diff --git a/package-lock.json b/package-lock.json index 3cbc60c4..4be39a9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,74 @@ { "name": "sbgnviz", - "version": "3.1.0", + "version": "4.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { + "ajv": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz", + "integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=", + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "json-schema-traverse": "0.3.1", + "json-stable-stringify": "1.0.1" + } + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "requires": { + "hoek": "4.2.0" + } + }, "browserify": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/browserify/-/browserify-11.2.0.tgz", "integrity": "sha1-oRu53SCdeVcrgT9+7q+Cil9cDk4=", "dev": true, "requires": { + "JSONStream": "1.3.1", "assert": "1.3.0", "browser-pack": "5.0.1", "browser-resolve": "1.11.2", @@ -33,7 +92,6 @@ "inherits": "2.0.3", "insert-module-globals": "6.6.3", "isarray": "0.0.1", - "JSONStream": "1.3.1", "labeled-stream-splicer": "1.0.2", "module-deps": "3.9.1", "os-browserify": "0.1.2", @@ -61,6 +119,30 @@ "xtend": "4.0.1" }, "dependencies": { + "JSONStream": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz", + "integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=", + "dev": true, + "requires": { + "jsonparse": "1.3.1", + "through": "2.3.8" + }, + "dependencies": { + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + } + } + }, "assert": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/assert/-/assert-1.3.0.tgz", @@ -76,9 +158,9 @@ "integrity": "sha1-QZdxmyDG4KqglFHFER5T77b7wY0=", "dev": true, "requires": { + "JSONStream": "1.3.1", "combine-source-map": "0.6.1", "defined": "1.0.0", - "JSONStream": "1.3.1", "through2": "1.1.1", "umd": "3.0.1" }, @@ -1185,10 +1267,10 @@ "integrity": "sha1-IGOOKaMPntHKLjqCX7wsulJG3fw=", "dev": true, "requires": { + "JSONStream": "1.3.1", "combine-source-map": "0.6.1", "concat-stream": "1.4.10", "is-buffer": "1.1.5", - "JSONStream": "1.3.1", "lexical-scope": "1.2.0", "process": "0.11.10", "through2": "1.1.1", @@ -1289,30 +1371,6 @@ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, - "JSONStream": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz", - "integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=", - "dev": true, - "requires": { - "jsonparse": "1.3.1", - "through": "2.3.8" - }, - "dependencies": { - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - } - } - }, "labeled-stream-splicer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-1.0.2.tgz", @@ -1383,13 +1441,13 @@ "integrity": "sha1-6nXK+RmQkNJbDVUStaysuW5/h/M=", "dev": true, "requires": { + "JSONStream": "1.3.1", "browser-resolve": "1.11.2", "concat-stream": "1.4.10", "defined": "1.0.0", "detective": "4.5.0", "duplexer2": "0.0.2", "inherits": "2.0.3", - "JSONStream": "1.3.1", "parents": "1.0.1", "readable-stream": "1.1.14", "resolve": "1.4.0", @@ -1897,6 +1955,112 @@ } } }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.2.0" + } + } + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "es6-promise": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-2.3.0.tgz", + "integrity": "sha1-lu258v2wGZWCKyY92KratnSBgbw=" + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "1.0.0" + } + }, "gulp": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", @@ -5592,6 +5756,62 @@ } } }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "requires": { + "ajv": "5.2.3", + "har-schema": "2.0.0" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.0.2" + } + }, + "hoek": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, "jshint-stylish": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/jshint-stylish/-/jshint-stylish-2.2.1.tgz", @@ -5741,506 +5961,86 @@ } } }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsonld": { + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-0.4.12.tgz", + "integrity": "sha1-oC8gXVNBQU3xtthBTxuWenEgc+g=", + "requires": { + "es6-promise": "2.3.0", + "pkginfo": "0.4.1", + "request": "2.83.0", + "xmldom": "0.1.19" + }, + "dependencies": { + "xmldom": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.19.tgz", + "integrity": "sha1-Yx/Ad3bv2EEYvyUXGzftTQdaCrw=" + } + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, "libsbgn.js": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/libsbgn.js/-/libsbgn.js-0.1.1.tgz", - "integrity": "sha1-xARpFqwH8TPNVO9Ia45I+zwmpbY=", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/libsbgn.js/-/libsbgn.js-0.1.3.tgz", + "integrity": "sha512-qk3FCXHhO1T5DnnrLKCpL1YIT3oR8uqpoloz3+yGZci4avKUZfrh+GmQpoO5M0ItCjnHyOwYYjP4WQUGCnj7Mw==", "requires": { - "n3": "0.10.0", + "n3": "0.11.1", "rdflib": "git+https://github.com/royludo/rdflib.js.git#761b45170b0652507a613160a3893d214b062c91", - "xml2js": "0.4.17" + "xml2js": "0.4.18" }, "dependencies": { - "n3": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/n3/-/n3-0.10.0.tgz", - "integrity": "sha1-df0Q8Ids3RdJ/IWRgfJmcUZ9TWM=" - }, - "rdflib": { - "version": "git+https://github.com/royludo/rdflib.js.git#761b45170b0652507a613160a3893d214b062c91", - "requires": { - "async": "0.9.2", - "jsonld": "0.4.12", - "n3": "0.4.5", - "xmldom": "0.1.27", - "xmlhttprequest": "1.8.0" - }, - "dependencies": { - "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" - }, - "jsonld": { - "version": "0.4.12", - "resolved": "https://registry.npmjs.org/jsonld/-/jsonld-0.4.12.tgz", - "integrity": "sha1-oC8gXVNBQU3xtthBTxuWenEgc+g=", - "requires": { - "es6-promise": "2.3.0", - "pkginfo": "0.4.0", - "request": "2.81.0", - "xmldom": "0.1.19" - }, - "dependencies": { - "es6-promise": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-2.3.0.tgz", - "integrity": "sha1-lu258v2wGZWCKyY92KratnSBgbw=" - }, - "pkginfo": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.0.tgz", - "integrity": "sha1-NJ27f/04CB/K3AhT32h/DHdEzWU=" - }, - "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.16", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" - }, - "dependencies": { - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" - }, - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "combined-stream": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", - "requires": { - "delayed-stream": "1.0.0" - }, - "dependencies": { - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - } - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.16" - }, - "dependencies": { - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - } - } - }, - "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - }, - "dependencies": { - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - }, - "dependencies": { - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "requires": { - "jsonify": "0.0.0" - }, - "dependencies": { - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" - } - } - } - } - }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" - } - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - }, - "dependencies": { - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "requires": { - "hoek": "2.16.3" - } - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "requires": { - "boom": "2.10.1" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" - }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "requires": { - "hoek": "2.16.3" - } - } - } - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.1", - "sshpk": "1.13.1" - }, - "dependencies": { - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "1.3.0" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - } - } - } - } - }, - "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "1.0.0" - } - }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "1.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true - } - } - } - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "mime-types": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz", - "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=", - "requires": { - "mime-db": "1.29.0" - }, - "dependencies": { - "mime-db": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz", - "integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg=" - } - } - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" - }, - "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" - }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=" - }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" - }, - "tough-cookie": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", - "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", - "requires": { - "punycode": "1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - } - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "5.1.1" - } - }, - "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ=" - } - } - }, - "xmldom": { - "version": "0.1.19", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.19.tgz", - "integrity": "sha1-Yx/Ad3bv2EEYvyUXGzftTQdaCrw=" - } - } - }, - "n3": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/n3/-/n3-0.4.5.tgz", - "integrity": "sha1-W3DTq2ohyejUyb2io9TZCQm+tQg=" - }, - "xmldom": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", - "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=" - }, - "xmlhttprequest": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", - "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" - } - } - }, "xml2js": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", - "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.18.tgz", + "integrity": "sha512-MMUtkwryoXmYoFUBT32tf7vYPHr98h6VtRLVbsjfmS5hqpp/deRMUNLZNQUHEAY4ChwyBEkisDYhH/EP15X6oA==", "requires": { "sax": "1.2.4", - "xmlbuilder": "4.2.1" - }, - "dependencies": { - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=" - }, - "xmlbuilder": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", - "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", - "requires": { - "lodash": "4.17.4" - }, - "dependencies": { - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" - } - } - } + "xmlbuilder": "9.0.4" } + }, + "xmlbuilder": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz", + "integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=" } } }, @@ -6249,6 +6049,24 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "n3": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/n3/-/n3-0.11.1.tgz", + "integrity": "sha512-g6hF3mPTGwFvtq4SGLhFaIjj+mfZokgB/ddP1b1vqRxygkkEYHM04izrVbWOE1ZdsB9a1dMq+FTghS5zQt09Dg==" + }, "node-notifier": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-4.6.1.tgz", @@ -6583,11 +6401,82 @@ } } }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "pkginfo": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz", + "integrity": "sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8=" + }, "pretty-data": { "version": "0.40.0", "resolved": "https://registry.npmjs.org/pretty-data/-/pretty-data-0.40.0.tgz", "integrity": "sha1-Vyqo6iNGdGerlLa1Jmpv2cj93XI=" }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "rdflib": { + "version": "git+https://github.com/royludo/rdflib.js.git#761b45170b0652507a613160a3893d214b062c91", + "requires": { + "async": "0.9.2", + "jsonld": "0.4.12", + "n3": "0.4.5", + "xmldom": "0.1.27", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "n3": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/n3/-/n3-0.4.5.tgz", + "integrity": "sha1-W3DTq2ohyejUyb2io9TZCQm+tQg=" + } + } + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, "run-sequence": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/run-sequence/-/run-sequence-1.2.2.tgz", @@ -6664,11 +6553,81 @@ } } }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, + "sntp": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz", + "integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=", + "requires": { + "hoek": "4.2.0" + } + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + }, "vinyl-buffer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/vinyl-buffer/-/vinyl-buffer-1.0.0.tgz", @@ -6894,6 +6853,16 @@ "requires": { "lodash": "4.17.4" } + }, + "xmldom": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", + "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=" + }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" } } } diff --git a/sbgnviz.js b/sbgnviz.js index ca782322..8e7808f0 100644 --- a/sbgnviz.js +++ b/sbgnviz.js @@ -1126,137 +1126,11 @@ }).call(this,_dereq_('_process')) -},{"_process":37}],2:[function(_dereq_,module,exports){ -var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - -;(function (exports) { - 'use strict'; - - var Arr = (typeof Uint8Array !== 'undefined') - ? Uint8Array - : Array - - var PLUS = '+'.charCodeAt(0) - var SLASH = '/'.charCodeAt(0) - var NUMBER = '0'.charCodeAt(0) - var LOWER = 'a'.charCodeAt(0) - var UPPER = 'A'.charCodeAt(0) - var PLUS_URL_SAFE = '-'.charCodeAt(0) - var SLASH_URL_SAFE = '_'.charCodeAt(0) - - function decode (elt) { - var code = elt.charCodeAt(0) - if (code === PLUS || - code === PLUS_URL_SAFE) - return 62 // '+' - if (code === SLASH || - code === SLASH_URL_SAFE) - return 63 // '/' - if (code < NUMBER) - return -1 //no match - if (code < NUMBER + 10) - return code - NUMBER + 26 + 26 - if (code < UPPER + 26) - return code - UPPER - if (code < LOWER + 26) - return code - LOWER + 26 - } - - function b64ToByteArray (b64) { - var i, j, l, tmp, placeHolders, arr - - if (b64.length % 4 > 0) { - throw new Error('Invalid string. Length must be a multiple of 4') - } - - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - var len = b64.length - placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 - - // base64 is 4/3 + up to two characters of the original data - arr = new Arr(b64.length * 3 / 4 - placeHolders) - - // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? b64.length - 4 : b64.length - - var L = 0 - - function push (v) { - arr[L++] = v - } - - for (i = 0, j = 0; i < l; i += 4, j += 3) { - tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) - push((tmp & 0xFF0000) >> 16) - push((tmp & 0xFF00) >> 8) - push(tmp & 0xFF) - } - - if (placeHolders === 2) { - tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) - push(tmp & 0xFF) - } else if (placeHolders === 1) { - tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) - push((tmp >> 8) & 0xFF) - push(tmp & 0xFF) - } - - return arr - } - - function uint8ToBase64 (uint8) { - var i, - extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes - output = "", - temp, length - - function encode (num) { - return lookup.charAt(num) - } - - function tripletToBase64 (num) { - return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) - } - - // go through the array every three bytes, we'll deal with trailing stuff later - for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { - temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) - output += tripletToBase64(temp) - } - - // pad the end with zeros, but make sure to not forget the extra bytes - switch (extraBytes) { - case 1: - temp = uint8[uint8.length - 1] - output += encode(temp >> 2) - output += encode((temp << 4) & 0x3F) - output += '==' - break - case 2: - temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) - output += encode(temp >> 10) - output += encode((temp >> 4) & 0x3F) - output += encode((temp << 2) & 0x3F) - output += '=' - break - } - - return output - } - - exports.toByteArray = b64ToByteArray - exports.fromByteArray = uint8ToBase64 -}(typeof exports === 'undefined' ? (this.base64js = {}) : exports)) +},{"_process":12}],2:[function(_dereq_,module,exports){ },{}],3:[function(_dereq_,module,exports){ - -},{}],4:[function(_dereq_,module,exports){ -arguments[4][3][0].apply(exports,arguments) -},{"dup":3}],5:[function(_dereq_,module,exports){ +arguments[4][2][0].apply(exports,arguments) +},{"dup":2}],4:[function(_dereq_,module,exports){ (function (global){ /*! * The buffer module from node.js, for the browser. @@ -2809,76 +2683,226 @@ function blitBuffer (src, dst, offset, length) { }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"base64-js":2,"ieee754":13,"isarray":6}],6:[function(_dereq_,module,exports){ +},{"base64-js":5,"ieee754":6,"isarray":7}],5:[function(_dereq_,module,exports){ +var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + +;(function (exports) { + 'use strict'; + + var Arr = (typeof Uint8Array !== 'undefined') + ? Uint8Array + : Array + + var PLUS = '+'.charCodeAt(0) + var SLASH = '/'.charCodeAt(0) + var NUMBER = '0'.charCodeAt(0) + var LOWER = 'a'.charCodeAt(0) + var UPPER = 'A'.charCodeAt(0) + var PLUS_URL_SAFE = '-'.charCodeAt(0) + var SLASH_URL_SAFE = '_'.charCodeAt(0) + + function decode (elt) { + var code = elt.charCodeAt(0) + if (code === PLUS || + code === PLUS_URL_SAFE) + return 62 // '+' + if (code === SLASH || + code === SLASH_URL_SAFE) + return 63 // '/' + if (code < NUMBER) + return -1 //no match + if (code < NUMBER + 10) + return code - NUMBER + 26 + 26 + if (code < UPPER + 26) + return code - UPPER + if (code < LOWER + 26) + return code - LOWER + 26 + } + + function b64ToByteArray (b64) { + var i, j, l, tmp, placeHolders, arr + + if (b64.length % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // the number of equal signs (place holders) + // if there are two placeholders, than the two characters before it + // represent one byte + // if there is only one, then the three characters before it represent 2 bytes + // this is just a cheap hack to not do indexOf twice + var len = b64.length + placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 + + // base64 is 4/3 + up to two characters of the original data + arr = new Arr(b64.length * 3 / 4 - placeHolders) + + // if there are placeholders, only get up to the last complete 4 chars + l = placeHolders > 0 ? b64.length - 4 : b64.length + + var L = 0 + + function push (v) { + arr[L++] = v + } + + for (i = 0, j = 0; i < l; i += 4, j += 3) { + tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) + push((tmp & 0xFF0000) >> 16) + push((tmp & 0xFF00) >> 8) + push(tmp & 0xFF) + } + + if (placeHolders === 2) { + tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) + push(tmp & 0xFF) + } else if (placeHolders === 1) { + tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) + push((tmp >> 8) & 0xFF) + push(tmp & 0xFF) + } + + return arr + } + + function uint8ToBase64 (uint8) { + var i, + extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes + output = "", + temp, length + + function encode (num) { + return lookup.charAt(num) + } + + function tripletToBase64 (num) { + return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) + } + + // go through the array every three bytes, we'll deal with trailing stuff later + for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { + temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) + output += tripletToBase64(temp) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + switch (extraBytes) { + case 1: + temp = uint8[uint8.length - 1] + output += encode(temp >> 2) + output += encode((temp << 4) & 0x3F) + output += '==' + break + case 2: + temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) + output += encode(temp >> 10) + output += encode((temp >> 4) & 0x3F) + output += encode((temp << 2) & 0x3F) + output += '=' + break + } + + return output + } + + exports.toByteArray = b64ToByteArray + exports.fromByteArray = uint8ToBase64 +}(typeof exports === 'undefined' ? (this.base64js = {}) : exports)) + +},{}],6:[function(_dereq_,module,exports){ +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = nBytes * 8 - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] + + i += d + + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) +} + +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = nBytes * 8 - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + + value = Math.abs(value) + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c + } else { + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 + } + + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + + buffer[offset + i - d] |= s * 128 +} + +},{}],7:[function(_dereq_,module,exports){ var toString = {}.toString; module.exports = Array.isArray || function (arr) { return toString.call(arr) == '[object Array]'; }; -},{}],7:[function(_dereq_,module,exports){ -module.exports = { - "100": "Continue", - "101": "Switching Protocols", - "102": "Processing", - "200": "OK", - "201": "Created", - "202": "Accepted", - "203": "Non-Authoritative Information", - "204": "No Content", - "205": "Reset Content", - "206": "Partial Content", - "207": "Multi-Status", - "300": "Multiple Choices", - "301": "Moved Permanently", - "302": "Moved Temporarily", - "303": "See Other", - "304": "Not Modified", - "305": "Use Proxy", - "307": "Temporary Redirect", - "308": "Permanent Redirect", - "400": "Bad Request", - "401": "Unauthorized", - "402": "Payment Required", - "403": "Forbidden", - "404": "Not Found", - "405": "Method Not Allowed", - "406": "Not Acceptable", - "407": "Proxy Authentication Required", - "408": "Request Time-out", - "409": "Conflict", - "410": "Gone", - "411": "Length Required", - "412": "Precondition Failed", - "413": "Request Entity Too Large", - "414": "Request-URI Too Large", - "415": "Unsupported Media Type", - "416": "Requested Range Not Satisfiable", - "417": "Expectation Failed", - "418": "I'm a teapot", - "422": "Unprocessable Entity", - "423": "Locked", - "424": "Failed Dependency", - "425": "Unordered Collection", - "426": "Upgrade Required", - "428": "Precondition Required", - "429": "Too Many Requests", - "431": "Request Header Fields Too Large", - "500": "Internal Server Error", - "501": "Not Implemented", - "502": "Bad Gateway", - "503": "Service Unavailable", - "504": "Gateway Time-out", - "505": "HTTP Version Not Supported", - "506": "Variant Also Negotiates", - "507": "Insufficient Storage", - "509": "Bandwidth Limit Exceeded", - "510": "Not Extended", - "511": "Network Authentication Required" -} - },{}],8:[function(_dereq_,module,exports){ -(function (Buffer){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -2900,1073 +2924,1162 @@ module.exports = { // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. - -function isArray(arg) { - if (Array.isArray) { - return Array.isArray(arg); - } - return objectToString(arg) === '[object Array]'; -} -exports.isArray = isArray; - -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; - -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; - -function isNullOrUndefined(arg) { - return arg == null; +function EventEmitter() { + this._events = this._events || {}; + this._maxListeners = this._maxListeners || undefined; } -exports.isNullOrUndefined = isNullOrUndefined; +module.exports = EventEmitter; -function isNumber(arg) { - return typeof arg === 'number'; -} -exports.isNumber = isNumber; +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +EventEmitter.defaultMaxListeners = 10; -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function(n) { + if (!isNumber(n) || n < 0 || isNaN(n)) + throw TypeError('n must be a positive number'); + this._maxListeners = n; + return this; +}; -function isRegExp(re) { - return objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; +EventEmitter.prototype.emit = function(type) { + var er, handler, len, args, i, listeners; -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; + if (!this._events) + this._events = {}; -function isDate(d) { - return objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events.error || + (isObject(this._events.error) && !this._events.error.length)) { + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } + throw TypeError('Uncaught, unspecified "error" event.'); + } + } -function isError(e) { - return (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; + handler = this._events[type]; -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; + if (isUndefined(handler)) + return false; -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; + if (isFunction(handler)) { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + handler.apply(this, args); + } + } else if (isObject(handler)) { + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; -exports.isBuffer = Buffer.isBuffer; + listeners = handler.slice(); + len = listeners.length; + for (i = 0; i < len; i++) + listeners[i].apply(this, args); + } -function objectToString(o) { - return Object.prototype.toString.call(o); -} + return true; +}; -}).call(this,{"isBuffer":_dereq_("../../is-buffer/index.js")}) +EventEmitter.prototype.addListener = function(type, listener) { + var m; -},{"../../is-buffer/index.js":16}],9:[function(_dereq_,module,exports){ -(function (process,global){ -/*! - * @overview es6-promise - a tiny implementation of Promises/A+. - * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) - * @license Licensed under MIT license - * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE - * @version 2.3.0 - */ + if (!isFunction(listener)) + throw TypeError('listener must be a function'); -(function() { - "use strict"; - function lib$es6$promise$utils$$objectOrFunction(x) { - return typeof x === 'function' || (typeof x === 'object' && x !== null); - } + if (!this._events) + this._events = {}; - function lib$es6$promise$utils$$isFunction(x) { - return typeof x === 'function'; - } + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (this._events.newListener) + this.emit('newListener', type, + isFunction(listener.listener) ? + listener.listener : listener); - function lib$es6$promise$utils$$isMaybeThenable(x) { - return typeof x === 'object' && x !== null; - } + if (!this._events[type]) + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + else if (isObject(this._events[type])) + // If we've already got an array, just append. + this._events[type].push(listener); + else + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; - var lib$es6$promise$utils$$_isArray; - if (!Array.isArray) { - lib$es6$promise$utils$$_isArray = function (x) { - return Object.prototype.toString.call(x) === '[object Array]'; - }; + // Check for listener leak + if (isObject(this._events[type]) && !this._events[type].warned) { + var m; + if (!isUndefined(this._maxListeners)) { + m = this._maxListeners; } else { - lib$es6$promise$utils$$_isArray = Array.isArray; + m = EventEmitter.defaultMaxListeners; } - var lib$es6$promise$utils$$isArray = lib$es6$promise$utils$$_isArray; - var lib$es6$promise$asap$$len = 0; - var lib$es6$promise$asap$$toString = {}.toString; - var lib$es6$promise$asap$$vertxNext; - var lib$es6$promise$asap$$customSchedulerFn; - - var lib$es6$promise$asap$$asap = function asap(callback, arg) { - lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len] = callback; - lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len + 1] = arg; - lib$es6$promise$asap$$len += 2; - if (lib$es6$promise$asap$$len === 2) { - // If len is 2, that means that we need to schedule an async flush. - // If additional callbacks are queued before the queue is flushed, they - // will be processed by this flush that we are scheduling. - if (lib$es6$promise$asap$$customSchedulerFn) { - lib$es6$promise$asap$$customSchedulerFn(lib$es6$promise$asap$$flush); - } else { - lib$es6$promise$asap$$scheduleFlush(); - } + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); } } + } - function lib$es6$promise$asap$$setScheduler(scheduleFn) { - lib$es6$promise$asap$$customSchedulerFn = scheduleFn; - } + return this; +}; - function lib$es6$promise$asap$$setAsap(asapFn) { - lib$es6$promise$asap$$asap = asapFn; - } +EventEmitter.prototype.on = EventEmitter.prototype.addListener; - var lib$es6$promise$asap$$browserWindow = (typeof window !== 'undefined') ? window : undefined; - var lib$es6$promise$asap$$browserGlobal = lib$es6$promise$asap$$browserWindow || {}; - var lib$es6$promise$asap$$BrowserMutationObserver = lib$es6$promise$asap$$browserGlobal.MutationObserver || lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver; - var lib$es6$promise$asap$$isNode = typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'; +EventEmitter.prototype.once = function(type, listener) { + if (!isFunction(listener)) + throw TypeError('listener must be a function'); - // test for web worker but not in IE10 - var lib$es6$promise$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' && - typeof importScripts !== 'undefined' && - typeof MessageChannel !== 'undefined'; + var fired = false; - // node - function lib$es6$promise$asap$$useNextTick() { - var nextTick = process.nextTick; - // node version 0.10.x displays a deprecation warning when nextTick is used recursively - // setImmediate should be used instead instead - var version = process.versions.node.match(/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/); - if (Array.isArray(version) && version[1] === '0' && version[2] === '10') { - nextTick = setImmediate; - } - return function() { - nextTick(lib$es6$promise$asap$$flush); - }; - } + function g() { + this.removeListener(type, g); - // vertx - function lib$es6$promise$asap$$useVertxTimer() { - return function() { - lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush); - }; + if (!fired) { + fired = true; + listener.apply(this, arguments); } + } - function lib$es6$promise$asap$$useMutationObserver() { - var iterations = 0; - var observer = new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush); - var node = document.createTextNode(''); - observer.observe(node, { characterData: true }); - - return function() { - node.data = (iterations = ++iterations % 2); - }; - } + g.listener = listener; + this.on(type, g); - // web worker - function lib$es6$promise$asap$$useMessageChannel() { - var channel = new MessageChannel(); - channel.port1.onmessage = lib$es6$promise$asap$$flush; - return function () { - channel.port2.postMessage(0); - }; - } + return this; +}; - function lib$es6$promise$asap$$useSetTimeout() { - return function() { - setTimeout(lib$es6$promise$asap$$flush, 1); - }; - } +// emits a 'removeListener' event iff the listener was removed +EventEmitter.prototype.removeListener = function(type, listener) { + var list, position, length, i; - var lib$es6$promise$asap$$queue = new Array(1000); - function lib$es6$promise$asap$$flush() { - for (var i = 0; i < lib$es6$promise$asap$$len; i+=2) { - var callback = lib$es6$promise$asap$$queue[i]; - var arg = lib$es6$promise$asap$$queue[i+1]; + if (!isFunction(listener)) + throw TypeError('listener must be a function'); - callback(arg); + if (!this._events || !this._events[type]) + return this; - lib$es6$promise$asap$$queue[i] = undefined; - lib$es6$promise$asap$$queue[i+1] = undefined; - } + list = this._events[type]; + length = list.length; + position = -1; - lib$es6$promise$asap$$len = 0; - } + if (list === listener || + (isFunction(list.listener) && list.listener === listener)) { + delete this._events[type]; + if (this._events.removeListener) + this.emit('removeListener', type, listener); - function lib$es6$promise$asap$$attemptVertex() { - try { - var r = _dereq_; - var vertx = r('vertx'); - lib$es6$promise$asap$$vertxNext = vertx.runOnLoop || vertx.runOnContext; - return lib$es6$promise$asap$$useVertxTimer(); - } catch(e) { - return lib$es6$promise$asap$$useSetTimeout(); + } else if (isObject(list)) { + for (i = length; i-- > 0;) { + if (list[i] === listener || + (list[i].listener && list[i].listener === listener)) { + position = i; + break; } } - var lib$es6$promise$asap$$scheduleFlush; - // Decide what async method to use to triggering processing of queued callbacks: - if (lib$es6$promise$asap$$isNode) { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useNextTick(); - } else if (lib$es6$promise$asap$$BrowserMutationObserver) { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMutationObserver(); - } else if (lib$es6$promise$asap$$isWorker) { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMessageChannel(); - } else if (lib$es6$promise$asap$$browserWindow === undefined && typeof _dereq_ === 'function') { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$attemptVertex(); + if (position < 0) + return this; + + if (list.length === 1) { + list.length = 0; + delete this._events[type]; } else { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useSetTimeout(); + list.splice(position, 1); } - function lib$es6$promise$$internal$$noop() {} + if (this._events.removeListener) + this.emit('removeListener', type, listener); + } - var lib$es6$promise$$internal$$PENDING = void 0; - var lib$es6$promise$$internal$$FULFILLED = 1; - var lib$es6$promise$$internal$$REJECTED = 2; + return this; +}; - var lib$es6$promise$$internal$$GET_THEN_ERROR = new lib$es6$promise$$internal$$ErrorObject(); +EventEmitter.prototype.removeAllListeners = function(type) { + var key, listeners; - function lib$es6$promise$$internal$$selfFullfillment() { - return new TypeError("You cannot resolve a promise with itself"); - } + if (!this._events) + return this; - function lib$es6$promise$$internal$$cannotReturnOwn() { - return new TypeError('A promises callback cannot return that same promise.'); - } + // not listening for removeListener, no need to emit + if (!this._events.removeListener) { + if (arguments.length === 0) + this._events = {}; + else if (this._events[type]) + delete this._events[type]; + return this; + } - function lib$es6$promise$$internal$$getThen(promise) { - try { - return promise.then; - } catch(error) { - lib$es6$promise$$internal$$GET_THEN_ERROR.error = error; - return lib$es6$promise$$internal$$GET_THEN_ERROR; - } + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + for (key in this._events) { + if (key === 'removeListener') continue; + this.removeAllListeners(key); } + this.removeAllListeners('removeListener'); + this._events = {}; + return this; + } - function lib$es6$promise$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) { - try { - then.call(value, fulfillmentHandler, rejectionHandler); - } catch(e) { - return e; - } - } + listeners = this._events[type]; - function lib$es6$promise$$internal$$handleForeignThenable(promise, thenable, then) { - lib$es6$promise$asap$$asap(function(promise) { - var sealed = false; - var error = lib$es6$promise$$internal$$tryThen(then, thenable, function(value) { - if (sealed) { return; } - sealed = true; - if (thenable !== value) { - lib$es6$promise$$internal$$resolve(promise, value); - } else { - lib$es6$promise$$internal$$fulfill(promise, value); - } - }, function(reason) { - if (sealed) { return; } - sealed = true; + if (isFunction(listeners)) { + this.removeListener(type, listeners); + } else { + // LIFO order + while (listeners.length) + this.removeListener(type, listeners[listeners.length - 1]); + } + delete this._events[type]; - lib$es6$promise$$internal$$reject(promise, reason); - }, 'Settle: ' + (promise._label || ' unknown promise')); + return this; +}; - if (!sealed && error) { - sealed = true; - lib$es6$promise$$internal$$reject(promise, error); - } - }, promise); - } +EventEmitter.prototype.listeners = function(type) { + var ret; + if (!this._events || !this._events[type]) + ret = []; + else if (isFunction(this._events[type])) + ret = [this._events[type]]; + else + ret = this._events[type].slice(); + return ret; +}; - function lib$es6$promise$$internal$$handleOwnThenable(promise, thenable) { - if (thenable._state === lib$es6$promise$$internal$$FULFILLED) { - lib$es6$promise$$internal$$fulfill(promise, thenable._result); - } else if (thenable._state === lib$es6$promise$$internal$$REJECTED) { - lib$es6$promise$$internal$$reject(promise, thenable._result); - } else { - lib$es6$promise$$internal$$subscribe(thenable, undefined, function(value) { - lib$es6$promise$$internal$$resolve(promise, value); - }, function(reason) { - lib$es6$promise$$internal$$reject(promise, reason); - }); - } - } +EventEmitter.listenerCount = function(emitter, type) { + var ret; + if (!emitter._events || !emitter._events[type]) + ret = 0; + else if (isFunction(emitter._events[type])) + ret = 1; + else + ret = emitter._events[type].length; + return ret; +}; - function lib$es6$promise$$internal$$handleMaybeThenable(promise, maybeThenable) { - if (maybeThenable.constructor === promise.constructor) { - lib$es6$promise$$internal$$handleOwnThenable(promise, maybeThenable); - } else { - var then = lib$es6$promise$$internal$$getThen(maybeThenable); +function isFunction(arg) { + return typeof arg === 'function'; +} - if (then === lib$es6$promise$$internal$$GET_THEN_ERROR) { - lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$GET_THEN_ERROR.error); - } else if (then === undefined) { - lib$es6$promise$$internal$$fulfill(promise, maybeThenable); - } else if (lib$es6$promise$utils$$isFunction(then)) { - lib$es6$promise$$internal$$handleForeignThenable(promise, maybeThenable, then); - } else { - lib$es6$promise$$internal$$fulfill(promise, maybeThenable); - } - } - } +function isNumber(arg) { + return typeof arg === 'number'; +} - function lib$es6$promise$$internal$$resolve(promise, value) { - if (promise === value) { - lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$selfFullfillment()); - } else if (lib$es6$promise$utils$$objectOrFunction(value)) { - lib$es6$promise$$internal$$handleMaybeThenable(promise, value); - } else { - lib$es6$promise$$internal$$fulfill(promise, value); - } - } +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} - function lib$es6$promise$$internal$$publishRejection(promise) { - if (promise._onerror) { - promise._onerror(promise._result); - } +function isUndefined(arg) { + return arg === void 0; +} - lib$es6$promise$$internal$$publish(promise); - } - - function lib$es6$promise$$internal$$fulfill(promise, value) { - if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } - - promise._result = value; - promise._state = lib$es6$promise$$internal$$FULFILLED; +},{}],9:[function(_dereq_,module,exports){ +var http = _dereq_('http'); - if (promise._subscribers.length !== 0) { - lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, promise); - } - } +var https = module.exports; - function lib$es6$promise$$internal$$reject(promise, reason) { - if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } - promise._state = lib$es6$promise$$internal$$REJECTED; - promise._result = reason; +for (var key in http) { + if (http.hasOwnProperty(key)) https[key] = http[key]; +}; - lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publishRejection, promise); - } +https.request = function (params, cb) { + if (!params) params = {}; + params.scheme = 'https'; + params.protocol = 'https:'; + return http.request.call(this, params, cb); +} - function lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection) { - var subscribers = parent._subscribers; - var length = subscribers.length; +},{"http":37}],10:[function(_dereq_,module,exports){ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} - parent._onerror = null; +},{}],11:[function(_dereq_,module,exports){ +/*! + * Determine if an object is a Buffer + * + * @author Feross Aboukhadijeh + * @license MIT + */ - subscribers[length] = child; - subscribers[length + lib$es6$promise$$internal$$FULFILLED] = onFulfillment; - subscribers[length + lib$es6$promise$$internal$$REJECTED] = onRejection; +// The _isBuffer check is for Safari 5-7 support, because it's missing +// Object.prototype.constructor. Remove this eventually +module.exports = function (obj) { + return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) +} - if (length === 0 && parent._state) { - lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, parent); - } - } +function isBuffer (obj) { + return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) +} - function lib$es6$promise$$internal$$publish(promise) { - var subscribers = promise._subscribers; - var settled = promise._state; +// For Node v0.10 support. Remove this eventually. +function isSlowBuffer (obj) { + return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) +} - if (subscribers.length === 0) { return; } +},{}],12:[function(_dereq_,module,exports){ +// shim for using process in browser +var process = module.exports = {}; - var child, callback, detail = promise._result; +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. - for (var i = 0; i < subscribers.length; i += 3) { - child = subscribers[i]; - callback = subscribers[i + settled]; +var cachedSetTimeout; +var cachedClearTimeout; - if (child) { - lib$es6$promise$$internal$$invokeCallback(settled, child, callback, detail); +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; } else { - callback(detail); + cachedSetTimeout = defaultSetTimout; } - } - - promise._subscribers.length = 0; - } - - function lib$es6$promise$$internal$$ErrorObject() { - this.error = null; - } - - var lib$es6$promise$$internal$$TRY_CATCH_ERROR = new lib$es6$promise$$internal$$ErrorObject(); - - function lib$es6$promise$$internal$$tryCatch(callback, detail) { - try { - return callback(detail); - } catch(e) { - lib$es6$promise$$internal$$TRY_CATCH_ERROR.error = e; - return lib$es6$promise$$internal$$TRY_CATCH_ERROR; - } + } catch (e) { + cachedSetTimeout = defaultSetTimout; } - - function lib$es6$promise$$internal$$invokeCallback(settled, promise, callback, detail) { - var hasCallback = lib$es6$promise$utils$$isFunction(callback), - value, error, succeeded, failed; - - if (hasCallback) { - value = lib$es6$promise$$internal$$tryCatch(callback, detail); - - if (value === lib$es6$promise$$internal$$TRY_CATCH_ERROR) { - failed = true; - error = value.error; - value = null; + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; } else { - succeeded = true; + cachedClearTimeout = defaultClearTimeout; } - - if (promise === value) { - lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$cannotReturnOwn()); - return; + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); } + } - } else { - value = detail; - succeeded = true; - } - if (promise._state !== lib$es6$promise$$internal$$PENDING) { - // noop - } else if (hasCallback && succeeded) { - lib$es6$promise$$internal$$resolve(promise, value); - } else if (failed) { - lib$es6$promise$$internal$$reject(promise, error); - } else if (settled === lib$es6$promise$$internal$$FULFILLED) { - lib$es6$promise$$internal$$fulfill(promise, value); - } else if (settled === lib$es6$promise$$internal$$REJECTED) { - lib$es6$promise$$internal$$reject(promise, value); - } +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); } - - function lib$es6$promise$$internal$$initializePromise(promise, resolver) { - try { - resolver(function resolvePromise(value){ - lib$es6$promise$$internal$$resolve(promise, value); - }, function rejectPromise(reason) { - lib$es6$promise$$internal$$reject(promise, reason); - }); - } catch(e) { - lib$es6$promise$$internal$$reject(promise, e); - } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); } - - function lib$es6$promise$enumerator$$Enumerator(Constructor, input) { - var enumerator = this; - - enumerator._instanceConstructor = Constructor; - enumerator.promise = new Constructor(lib$es6$promise$$internal$$noop); - - if (enumerator._validateInput(input)) { - enumerator._input = input; - enumerator.length = input.length; - enumerator._remaining = input.length; - - enumerator._init(); - - if (enumerator.length === 0) { - lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); - } else { - enumerator.length = enumerator.length || 0; - enumerator._enumerate(); - if (enumerator._remaining === 0) { - lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); - } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); } - } else { - lib$es6$promise$$internal$$reject(enumerator.promise, enumerator._validationError()); - } } - lib$es6$promise$enumerator$$Enumerator.prototype._validateInput = function(input) { - return lib$es6$promise$utils$$isArray(input); - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._validationError = function() { - return new Error('Array Methods must be provided an Array'); - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._init = function() { - this._result = new Array(this.length); - }; - - var lib$es6$promise$enumerator$$default = lib$es6$promise$enumerator$$Enumerator; - lib$es6$promise$enumerator$$Enumerator.prototype._enumerate = function() { - var enumerator = this; - var length = enumerator.length; - var promise = enumerator.promise; - var input = enumerator._input; +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; - for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) { - enumerator._eachEntry(input[i], i); - } - }; +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} - lib$es6$promise$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) { - var enumerator = this; - var c = enumerator._instanceConstructor; +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; - if (lib$es6$promise$utils$$isMaybeThenable(entry)) { - if (entry.constructor === c && entry._state !== lib$es6$promise$$internal$$PENDING) { - entry._onerror = null; - enumerator._settledAt(entry._state, i, entry._result); - } else { - enumerator._willSettleAt(c.resolve(entry), i); + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } } - } else { - enumerator._remaining--; - enumerator._result[i] = entry; - } - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) { - var enumerator = this; - var promise = enumerator.promise; - - if (promise._state === lib$es6$promise$$internal$$PENDING) { - enumerator._remaining--; + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} - if (state === lib$es6$promise$$internal$$REJECTED) { - lib$es6$promise$$internal$$reject(promise, value); - } else { - enumerator._result[i] = value; +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; } - } - - if (enumerator._remaining === 0) { - lib$es6$promise$$internal$$fulfill(promise, enumerator._result); - } - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) { - var enumerator = this; - - lib$es6$promise$$internal$$subscribe(promise, undefined, function(value) { - enumerator._settledAt(lib$es6$promise$$internal$$FULFILLED, i, value); - }, function(reason) { - enumerator._settledAt(lib$es6$promise$$internal$$REJECTED, i, reason); - }); - }; - function lib$es6$promise$promise$all$$all(entries) { - return new lib$es6$promise$enumerator$$default(this, entries).promise; } - var lib$es6$promise$promise$all$$default = lib$es6$promise$promise$all$$all; - function lib$es6$promise$promise$race$$race(entries) { - /*jshint validthis:true */ - var Constructor = this; + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; - var promise = new Constructor(lib$es6$promise$$internal$$noop); +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; - if (!lib$es6$promise$utils$$isArray(entries)) { - lib$es6$promise$$internal$$reject(promise, new TypeError('You must pass an array to race.')); - return promise; - } +function noop() {} - var length = entries.length; +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; - function onFulfillment(value) { - lib$es6$promise$$internal$$resolve(promise, value); - } +process.listeners = function (name) { return [] } - function onRejection(reason) { - lib$es6$promise$$internal$$reject(promise, reason); - } +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; - for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) { - lib$es6$promise$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); - } +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; - return promise; - } - var lib$es6$promise$promise$race$$default = lib$es6$promise$promise$race$$race; - function lib$es6$promise$promise$resolve$$resolve(object) { - /*jshint validthis:true */ - var Constructor = this; +},{}],13:[function(_dereq_,module,exports){ +(function (global){ +/*! https://mths.be/punycode v1.4.1 by @mathias */ +;(function(root) { - if (object && typeof object === 'object' && object.constructor === Constructor) { - return object; - } + /** Detect free variables */ + var freeExports = typeof exports == 'object' && exports && + !exports.nodeType && exports; + var freeModule = typeof module == 'object' && module && + !module.nodeType && module; + var freeGlobal = typeof global == 'object' && global; + if ( + freeGlobal.global === freeGlobal || + freeGlobal.window === freeGlobal || + freeGlobal.self === freeGlobal + ) { + root = freeGlobal; + } - var promise = new Constructor(lib$es6$promise$$internal$$noop); - lib$es6$promise$$internal$$resolve(promise, object); - return promise; - } - var lib$es6$promise$promise$resolve$$default = lib$es6$promise$promise$resolve$$resolve; - function lib$es6$promise$promise$reject$$reject(reason) { - /*jshint validthis:true */ - var Constructor = this; - var promise = new Constructor(lib$es6$promise$$internal$$noop); - lib$es6$promise$$internal$$reject(promise, reason); - return promise; - } - var lib$es6$promise$promise$reject$$default = lib$es6$promise$promise$reject$$reject; + /** + * The `punycode` object. + * @name punycode + * @type Object + */ + var punycode, - var lib$es6$promise$promise$$counter = 0; + /** Highest positive signed 32-bit float value */ + maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 - function lib$es6$promise$promise$$needsResolver() { - throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); - } + /** Bootstring parameters */ + base = 36, + tMin = 1, + tMax = 26, + skew = 38, + damp = 700, + initialBias = 72, + initialN = 128, // 0x80 + delimiter = '-', // '\x2D' - function lib$es6$promise$promise$$needsNew() { - throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); - } + /** Regular expressions */ + regexPunycode = /^xn--/, + regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars + regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators - var lib$es6$promise$promise$$default = lib$es6$promise$promise$$Promise; - /** - Promise objects represent the eventual result of an asynchronous operation. The - primary way of interacting with a promise is through its `then` method, which - registers callbacks to receive either a promise's eventual value or the reason - why the promise cannot be fulfilled. + /** Error messages */ + errors = { + 'overflow': 'Overflow: input needs wider integers to process', + 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', + 'invalid-input': 'Invalid input' + }, - Terminology - ----------- + /** Convenience shortcuts */ + baseMinusTMin = base - tMin, + floor = Math.floor, + stringFromCharCode = String.fromCharCode, - - `promise` is an object or function with a `then` method whose behavior conforms to this specification. - - `thenable` is an object or function that defines a `then` method. - - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). - - `exception` is a value that is thrown using the throw statement. - - `reason` is a value that indicates why a promise was rejected. - - `settled` the final resting state of a promise, fulfilled or rejected. + /** Temporary variable */ + key; - A promise can be in one of three states: pending, fulfilled, or rejected. - - Promises that are fulfilled have a fulfillment value and are in the fulfilled - state. Promises that are rejected have a rejection reason and are in the - rejected state. A fulfillment value is never a thenable. - - Promises can also be said to *resolve* a value. If this value is also a - promise, then the original promise's settled state will match the value's - settled state. So a promise that *resolves* a promise that rejects will - itself reject, and a promise that *resolves* a promise that fulfills will - itself fulfill. + /*--------------------------------------------------------------------------*/ + /** + * A generic error utility function. + * @private + * @param {String} type The error type. + * @returns {Error} Throws a `RangeError` with the applicable error message. + */ + function error(type) { + throw new RangeError(errors[type]); + } - Basic Usage: - ------------ + /** + * A generic `Array#map` utility function. + * @private + * @param {Array} array The array to iterate over. + * @param {Function} callback The function that gets called for every array + * item. + * @returns {Array} A new array of values returned by the callback function. + */ + function map(array, fn) { + var length = array.length; + var result = []; + while (length--) { + result[length] = fn(array[length]); + } + return result; + } - ```js - var promise = new Promise(function(resolve, reject) { - // on success - resolve(value); + /** + * A simple `Array#map`-like wrapper to work with domain name strings or email + * addresses. + * @private + * @param {String} domain The domain name or email address. + * @param {Function} callback The function that gets called for every + * character. + * @returns {Array} A new string of characters returned by the callback + * function. + */ + function mapDomain(string, fn) { + var parts = string.split('@'); + var result = ''; + if (parts.length > 1) { + // In email addresses, only the domain name should be punycoded. Leave + // the local part (i.e. everything up to `@`) intact. + result = parts[0] + '@'; + string = parts[1]; + } + // Avoid `split(regex)` for IE8 compatibility. See #17. + string = string.replace(regexSeparators, '\x2E'); + var labels = string.split('.'); + var encoded = map(labels, fn).join('.'); + return result + encoded; + } - // on failure - reject(reason); - }); + /** + * Creates an array containing the numeric code points of each Unicode + * character in the string. While JavaScript uses UCS-2 internally, + * this function will convert a pair of surrogate halves (each of which + * UCS-2 exposes as separate characters) into a single code point, + * matching UTF-16. + * @see `punycode.ucs2.encode` + * @see + * @memberOf punycode.ucs2 + * @name decode + * @param {String} string The Unicode input string (UCS-2). + * @returns {Array} The new array of code points. + */ + function ucs2decode(string) { + var output = [], + counter = 0, + length = string.length, + value, + extra; + while (counter < length) { + value = string.charCodeAt(counter++); + if (value >= 0xD800 && value <= 0xDBFF && counter < length) { + // high surrogate, and there is a next character + extra = string.charCodeAt(counter++); + if ((extra & 0xFC00) == 0xDC00) { // low surrogate + output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); + } else { + // unmatched surrogate; only append this code unit, in case the next + // code unit is the high surrogate of a surrogate pair + output.push(value); + counter--; + } + } else { + output.push(value); + } + } + return output; + } - promise.then(function(value) { - // on fulfillment - }, function(reason) { - // on rejection - }); - ``` + /** + * Creates a string based on an array of numeric code points. + * @see `punycode.ucs2.decode` + * @memberOf punycode.ucs2 + * @name encode + * @param {Array} codePoints The array of numeric code points. + * @returns {String} The new Unicode string (UCS-2). + */ + function ucs2encode(array) { + return map(array, function(value) { + var output = ''; + if (value > 0xFFFF) { + value -= 0x10000; + output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); + value = 0xDC00 | value & 0x3FF; + } + output += stringFromCharCode(value); + return output; + }).join(''); + } - Advanced Usage: - --------------- + /** + * Converts a basic code point into a digit/integer. + * @see `digitToBasic()` + * @private + * @param {Number} codePoint The basic numeric code point value. + * @returns {Number} The numeric value of a basic code point (for use in + * representing integers) in the range `0` to `base - 1`, or `base` if + * the code point does not represent a value. + */ + function basicToDigit(codePoint) { + if (codePoint - 48 < 10) { + return codePoint - 22; + } + if (codePoint - 65 < 26) { + return codePoint - 65; + } + if (codePoint - 97 < 26) { + return codePoint - 97; + } + return base; + } - Promises shine when abstracting away asynchronous interactions such as - `XMLHttpRequest`s. + /** + * Converts a digit/integer into a basic code point. + * @see `basicToDigit()` + * @private + * @param {Number} digit The numeric value of a basic code point. + * @returns {Number} The basic code point whose value (when used for + * representing integers) is `digit`, which needs to be in the range + * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is + * used; else, the lowercase form is used. The behavior is undefined + * if `flag` is non-zero and `digit` has no uppercase form. + */ + function digitToBasic(digit, flag) { + // 0..25 map to ASCII a..z or A..Z + // 26..35 map to ASCII 0..9 + return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); + } - ```js - function getJSON(url) { - return new Promise(function(resolve, reject){ - var xhr = new XMLHttpRequest(); + /** + * Bias adaptation function as per section 3.4 of RFC 3492. + * https://tools.ietf.org/html/rfc3492#section-3.4 + * @private + */ + function adapt(delta, numPoints, firstTime) { + var k = 0; + delta = firstTime ? floor(delta / damp) : delta >> 1; + delta += floor(delta / numPoints); + for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { + delta = floor(delta / baseMinusTMin); + } + return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); + } - xhr.open('GET', url); - xhr.onreadystatechange = handler; - xhr.responseType = 'json'; - xhr.setRequestHeader('Accept', 'application/json'); - xhr.send(); + /** + * Converts a Punycode string of ASCII-only symbols to a string of Unicode + * symbols. + * @memberOf punycode + * @param {String} input The Punycode string of ASCII-only symbols. + * @returns {String} The resulting string of Unicode symbols. + */ + function decode(input) { + // Don't use UCS-2 + var output = [], + inputLength = input.length, + out, + i = 0, + n = initialN, + bias = initialBias, + basic, + j, + index, + oldi, + w, + k, + digit, + t, + /** Cached calculation results */ + baseMinusT; - function handler() { - if (this.readyState === this.DONE) { - if (this.status === 200) { - resolve(this.response); - } else { - reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); - } - } - }; - }); - } + // Handle the basic code points: let `basic` be the number of input code + // points before the last delimiter, or `0` if there is none, then copy + // the first basic code points to the output. - getJSON('/posts.json').then(function(json) { - // on fulfillment - }, function(reason) { - // on rejection - }); - ``` + basic = input.lastIndexOf(delimiter); + if (basic < 0) { + basic = 0; + } - Unlike callbacks, promises are great composable primitives. + for (j = 0; j < basic; ++j) { + // if it's not a basic code point + if (input.charCodeAt(j) >= 0x80) { + error('not-basic'); + } + output.push(input.charCodeAt(j)); + } - ```js - Promise.all([ - getJSON('/posts'), - getJSON('/comments') - ]).then(function(values){ - values[0] // => postsJSON - values[1] // => commentsJSON + // Main decoding loop: start just after the last delimiter if any basic code + // points were copied; start at the beginning otherwise. - return values; - }); - ``` + for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { - @class Promise - @param {function} resolver - Useful for tooling. - @constructor - */ - function lib$es6$promise$promise$$Promise(resolver) { - this._id = lib$es6$promise$promise$$counter++; - this._state = undefined; - this._result = undefined; - this._subscribers = []; + // `index` is the index of the next character to be consumed. + // Decode a generalized variable-length integer into `delta`, + // which gets added to `i`. The overflow checking is easier + // if we increase `i` as we go, then subtract off its starting + // value at the end to obtain `delta`. + for (oldi = i, w = 1, k = base; /* no condition */; k += base) { - if (lib$es6$promise$$internal$$noop !== resolver) { - if (!lib$es6$promise$utils$$isFunction(resolver)) { - lib$es6$promise$promise$$needsResolver(); - } + if (index >= inputLength) { + error('invalid-input'); + } - if (!(this instanceof lib$es6$promise$promise$$Promise)) { - lib$es6$promise$promise$$needsNew(); - } + digit = basicToDigit(input.charCodeAt(index++)); - lib$es6$promise$$internal$$initializePromise(this, resolver); - } - } + if (digit >= base || digit > floor((maxInt - i) / w)) { + error('overflow'); + } - lib$es6$promise$promise$$Promise.all = lib$es6$promise$promise$all$$default; - lib$es6$promise$promise$$Promise.race = lib$es6$promise$promise$race$$default; - lib$es6$promise$promise$$Promise.resolve = lib$es6$promise$promise$resolve$$default; - lib$es6$promise$promise$$Promise.reject = lib$es6$promise$promise$reject$$default; - lib$es6$promise$promise$$Promise._setScheduler = lib$es6$promise$asap$$setScheduler; - lib$es6$promise$promise$$Promise._setAsap = lib$es6$promise$asap$$setAsap; - lib$es6$promise$promise$$Promise._asap = lib$es6$promise$asap$$asap; + i += digit * w; + t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); - lib$es6$promise$promise$$Promise.prototype = { - constructor: lib$es6$promise$promise$$Promise, + if (digit < t) { + break; + } - /** - The primary way of interacting with a promise is through its `then` method, - which registers callbacks to receive either a promise's eventual value or the - reason why the promise cannot be fulfilled. + baseMinusT = base - t; + if (w > floor(maxInt / baseMinusT)) { + error('overflow'); + } - ```js - findUser().then(function(user){ - // user is available - }, function(reason){ - // user is unavailable, and you are given the reason why - }); - ``` + w *= baseMinusT; - Chaining - -------- + } - The return value of `then` is itself a promise. This second, 'downstream' - promise is resolved with the return value of the first promise's fulfillment - or rejection handler, or rejected if the handler throws an exception. + out = output.length + 1; + bias = adapt(i - oldi, out, oldi == 0); - ```js - findUser().then(function (user) { - return user.name; - }, function (reason) { - return 'default name'; - }).then(function (userName) { - // If `findUser` fulfilled, `userName` will be the user's name, otherwise it - // will be `'default name'` - }); + // `i` was supposed to wrap around from `out` to `0`, + // incrementing `n` each time, so we'll fix that now: + if (floor(i / out) > maxInt - n) { + error('overflow'); + } - findUser().then(function (user) { - throw new Error('Found user, but still unhappy'); - }, function (reason) { - throw new Error('`findUser` rejected and we're unhappy'); - }).then(function (value) { - // never reached - }, function (reason) { - // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. - // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. - }); - ``` - If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + n += floor(i / out); + i %= out; - ```js - findUser().then(function (user) { - throw new PedagogicalException('Upstream error'); - }).then(function (value) { - // never reached - }).then(function (value) { - // never reached - }, function (reason) { - // The `PedgagocialException` is propagated all the way down to here - }); - ``` + // Insert `n` at position `i` of the output + output.splice(i++, 0, n); - Assimilation - ------------ + } - Sometimes the value you want to propagate to a downstream promise can only be - retrieved asynchronously. This can be achieved by returning a promise in the - fulfillment or rejection handler. The downstream promise will then be pending - until the returned promise is settled. This is called *assimilation*. + return ucs2encode(output); + } - ```js - findUser().then(function (user) { - return findCommentsByAuthor(user); - }).then(function (comments) { - // The user's comments are now available - }); - ``` + /** + * Converts a string of Unicode symbols (e.g. a domain name label) to a + * Punycode string of ASCII-only symbols. + * @memberOf punycode + * @param {String} input The string of Unicode symbols. + * @returns {String} The resulting Punycode string of ASCII-only symbols. + */ + function encode(input) { + var n, + delta, + handledCPCount, + basicLength, + bias, + j, + m, + q, + k, + t, + currentValue, + output = [], + /** `inputLength` will hold the number of code points in `input`. */ + inputLength, + /** Cached calculation results */ + handledCPCountPlusOne, + baseMinusT, + qMinusT; - If the assimliated promise rejects, then the downstream promise will also reject. + // Convert the input in UCS-2 to Unicode + input = ucs2decode(input); - ```js - findUser().then(function (user) { - return findCommentsByAuthor(user); - }).then(function (comments) { - // If `findCommentsByAuthor` fulfills, we'll have the value here - }, function (reason) { - // If `findCommentsByAuthor` rejects, we'll have the reason here - }); - ``` + // Cache the length + inputLength = input.length; - Simple Example - -------------- + // Initialize the state + n = initialN; + delta = 0; + bias = initialBias; - Synchronous Example + // Handle the basic code points + for (j = 0; j < inputLength; ++j) { + currentValue = input[j]; + if (currentValue < 0x80) { + output.push(stringFromCharCode(currentValue)); + } + } - ```javascript - var result; + handledCPCount = basicLength = output.length; - try { - result = findResult(); - // success - } catch(reason) { - // failure - } - ``` + // `handledCPCount` is the number of code points that have been handled; + // `basicLength` is the number of basic code points. - Errback Example + // Finish the basic string - if it is not empty - with a delimiter + if (basicLength) { + output.push(delimiter); + } - ```js - findResult(function(result, err){ - if (err) { - // failure - } else { - // success - } - }); - ``` + // Main encoding loop: + while (handledCPCount < inputLength) { - Promise Example; + // All non-basic code points < n have been handled already. Find the next + // larger one: + for (m = maxInt, j = 0; j < inputLength; ++j) { + currentValue = input[j]; + if (currentValue >= n && currentValue < m) { + m = currentValue; + } + } - ```javascript - findResult().then(function(result){ - // success - }, function(reason){ - // failure - }); - ``` + // Increase `delta` enough to advance the decoder's state to , + // but guard against overflow + handledCPCountPlusOne = handledCPCount + 1; + if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { + error('overflow'); + } - Advanced Example - -------------- + delta += (m - n) * handledCPCountPlusOne; + n = m; - Synchronous Example + for (j = 0; j < inputLength; ++j) { + currentValue = input[j]; - ```javascript - var author, books; + if (currentValue < n && ++delta > maxInt) { + error('overflow'); + } - try { - author = findAuthor(); - books = findBooksByAuthor(author); - // success - } catch(reason) { - // failure - } - ``` - - Errback Example - - ```js - - function foundBooks(books) { + if (currentValue == n) { + // Represent delta as a generalized variable-length integer + for (q = delta, k = base; /* no condition */; k += base) { + t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); + if (q < t) { + break; + } + qMinusT = q - t; + baseMinusT = base - t; + output.push( + stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) + ); + q = floor(qMinusT / baseMinusT); + } - } + output.push(stringFromCharCode(digitToBasic(q, 0))); + bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); + delta = 0; + ++handledCPCount; + } + } - function failure(reason) { + ++delta; + ++n; - } + } + return output.join(''); + } - findAuthor(function(author, err){ - if (err) { - failure(err); - // failure - } else { - try { - findBoooksByAuthor(author, function(books, err) { - if (err) { - failure(err); - } else { - try { - foundBooks(books); - } catch(reason) { - failure(reason); - } - } - }); - } catch(error) { - failure(err); - } - // success - } - }); - ``` + /** + * Converts a Punycode string representing a domain name or an email address + * to Unicode. Only the Punycoded parts of the input will be converted, i.e. + * it doesn't matter if you call it on a string that has already been + * converted to Unicode. + * @memberOf punycode + * @param {String} input The Punycoded domain name or email address to + * convert to Unicode. + * @returns {String} The Unicode representation of the given Punycode + * string. + */ + function toUnicode(input) { + return mapDomain(input, function(string) { + return regexPunycode.test(string) + ? decode(string.slice(4).toLowerCase()) + : string; + }); + } - Promise Example; + /** + * Converts a Unicode string representing a domain name or an email address to + * Punycode. Only the non-ASCII parts of the domain name will be converted, + * i.e. it doesn't matter if you call it with a domain that's already in + * ASCII. + * @memberOf punycode + * @param {String} input The domain name or email address to convert, as a + * Unicode string. + * @returns {String} The Punycode representation of the given domain name or + * email address. + */ + function toASCII(input) { + return mapDomain(input, function(string) { + return regexNonASCII.test(string) + ? 'xn--' + encode(string) + : string; + }); + } - ```javascript - findAuthor(). - then(findBooksByAuthor). - then(function(books){ - // found books - }).catch(function(reason){ - // something went wrong - }); - ``` + /*--------------------------------------------------------------------------*/ - @method then - @param {Function} onFulfilled - @param {Function} onRejected - Useful for tooling. - @return {Promise} - */ - then: function(onFulfillment, onRejection) { - var parent = this; - var state = parent._state; + /** Define the public API */ + punycode = { + /** + * A string representing the current Punycode.js version number. + * @memberOf punycode + * @type String + */ + 'version': '1.4.1', + /** + * An object of methods to convert from JavaScript's internal character + * representation (UCS-2) to Unicode code points, and back. + * @see + * @memberOf punycode + * @type Object + */ + 'ucs2': { + 'decode': ucs2decode, + 'encode': ucs2encode + }, + 'decode': decode, + 'encode': encode, + 'toASCII': toASCII, + 'toUnicode': toUnicode + }; - if (state === lib$es6$promise$$internal$$FULFILLED && !onFulfillment || state === lib$es6$promise$$internal$$REJECTED && !onRejection) { - return this; - } + /** Expose `punycode` */ + // Some AMD build optimizers, like r.js, check for specific condition patterns + // like the following: + if ( + typeof define == 'function' && + typeof define.amd == 'object' && + define.amd + ) { + define('punycode', function() { + return punycode; + }); + } else if (freeExports && freeModule) { + if (module.exports == freeExports) { + // in Node.js, io.js, or RingoJS v0.8.0+ + freeModule.exports = punycode; + } else { + // in Narwhal or RingoJS v0.7.0- + for (key in punycode) { + punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); + } + } + } else { + // in Rhino or a web browser + root.punycode = punycode; + } - var child = new this.constructor(lib$es6$promise$$internal$$noop); - var result = parent._result; +}(this)); - if (state) { - var callback = arguments[state - 1]; - lib$es6$promise$asap$$asap(function(){ - lib$es6$promise$$internal$$invokeCallback(state, child, callback, result); - }); - } else { - lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection); - } +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) - return child; - }, +},{}],14:[function(_dereq_,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. - /** - `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same - as the catch block of a try/catch statement. +'use strict'; - ```js - function findAuthor(){ - throw new Error('couldn't find that author'); - } +// If obj.hasOwnProperty has been overridden, then calling +// obj.hasOwnProperty(prop) will break. +// See: https://github.com/joyent/node/issues/1707 +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} - // synchronous - try { - findAuthor(); - } catch(reason) { - // something went wrong - } +module.exports = function(qs, sep, eq, options) { + sep = sep || '&'; + eq = eq || '='; + var obj = {}; - // async with promises - findAuthor().catch(function(reason){ - // something went wrong - }); - ``` + if (typeof qs !== 'string' || qs.length === 0) { + return obj; + } - @method catch - @param {Function} onRejection - Useful for tooling. - @return {Promise} - */ - 'catch': function(onRejection) { - return this.then(null, onRejection); - } - }; - function lib$es6$promise$polyfill$$polyfill() { - var local; + var regexp = /\+/g; + qs = qs.split(sep); - if (typeof global !== 'undefined') { - local = global; - } else if (typeof self !== 'undefined') { - local = self; - } else { - try { - local = Function('return this')(); - } catch (e) { - throw new Error('polyfill failed because global object is unavailable in this environment'); - } - } + var maxKeys = 1000; + if (options && typeof options.maxKeys === 'number') { + maxKeys = options.maxKeys; + } - var P = local.Promise; + var len = qs.length; + // maxKeys <= 0 means that we should not limit keys count + if (maxKeys > 0 && len > maxKeys) { + len = maxKeys; + } - if (P && Object.prototype.toString.call(P.resolve()) === '[object Promise]' && !P.cast) { - return; - } + for (var i = 0; i < len; ++i) { + var x = qs[i].replace(regexp, '%20'), + idx = x.indexOf(eq), + kstr, vstr, k, v; - local.Promise = lib$es6$promise$promise$$default; + if (idx >= 0) { + kstr = x.substr(0, idx); + vstr = x.substr(idx + 1); + } else { + kstr = x; + vstr = ''; } - var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill; - var lib$es6$promise$umd$$ES6Promise = { - 'Promise': lib$es6$promise$promise$$default, - 'polyfill': lib$es6$promise$polyfill$$default - }; + k = decodeURIComponent(kstr); + v = decodeURIComponent(vstr); - /* global define:true module:true window: true */ - if (typeof define === 'function' && define['amd']) { - define(function() { return lib$es6$promise$umd$$ES6Promise; }); - } else if (typeof module !== 'undefined' && module['exports']) { - module['exports'] = lib$es6$promise$umd$$ES6Promise; - } else if (typeof this !== 'undefined') { - this['ES6Promise'] = lib$es6$promise$umd$$ES6Promise; + if (!hasOwnProperty(obj, k)) { + obj[k] = v; + } else if (isArray(obj[k])) { + obj[k].push(v); + } else { + obj[k] = [obj[k], v]; } + } - lib$es6$promise$polyfill$$default(); -}).call(this); - + return obj; +}; -}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; -},{"_process":37}],10:[function(_dereq_,module,exports){ +},{}],15:[function(_dereq_,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -3988,27619 +4101,32178 @@ function objectToString(o) { // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; +'use strict'; -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; +var stringifyPrimitive = function(v) { + switch (typeof v) { + case 'string': + return v; -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; + case 'boolean': + return v ? 'true' : 'false'; -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; + case 'number': + return isFinite(v) ? v : ''; -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; + default: + return ''; + } }; -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) - this._events = {}; +module.exports = function(obj, sep, eq, name) { + sep = sep || '&'; + eq = eq || '='; + if (obj === null) { + obj = undefined; + } - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event + if (typeof obj === 'object') { + return map(objectKeys(obj), function(k) { + var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; + if (isArray(obj[k])) { + return map(obj[k], function(v) { + return ks + encodeURIComponent(stringifyPrimitive(v)); + }).join(sep); + } else { + return ks + encodeURIComponent(stringifyPrimitive(obj[k])); } - throw TypeError('Uncaught, unspecified "error" event.'); - } - } + }).join(sep); - handler = this._events[type]; + } - if (isUndefined(handler)) - return false; + if (!name) return ''; + return encodeURIComponent(stringifyPrimitive(name)) + eq + + encodeURIComponent(stringifyPrimitive(obj)); +}; - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - handler.apply(this, args); - } - } else if (isObject(handler)) { - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; +var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; +}; - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); +function map (xs, f) { + if (xs.map) return xs.map(f); + var res = []; + for (var i = 0; i < xs.length; i++) { + res.push(f(xs[i], i)); } + return res; +} - return true; +var objectKeys = Object.keys || function (obj) { + var res = []; + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); + } + return res; }; -EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); +},{}],16:[function(_dereq_,module,exports){ +'use strict'; - if (!this._events) - this._events = {}; +exports.decode = exports.parse = _dereq_('./decode'); +exports.encode = exports.stringify = _dereq_('./encode'); - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); +},{"./decode":14,"./encode":15}],17:[function(_dereq_,module,exports){ +module.exports = _dereq_('./lib/_stream_duplex.js'); - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; +},{"./lib/_stream_duplex.js":18}],18:[function(_dereq_,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - var m; - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } +// a duplex stream is just a stream that is both readable and writable. +// Since JS doesn't have multiple prototypal inheritance, this class +// prototypally inherits from Readable, and then parasitically from +// Writable. - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } +'use strict'; - return this; -}; +/**/ -EventEmitter.prototype.on = EventEmitter.prototype.addListener; +var processNextTick = _dereq_('process-nextick-args'); +/**/ -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); +/**/ +var objectKeys = Object.keys || function (obj) { + var keys = []; + for (var key in obj) { + keys.push(key); + }return keys; +}; +/**/ - var fired = false; +module.exports = Duplex; - function g() { - this.removeListener(type, g); +/**/ +var util = _dereq_('core-util-is'); +util.inherits = _dereq_('inherits'); +/**/ - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } +var Readable = _dereq_('./_stream_readable'); +var Writable = _dereq_('./_stream_writable'); - g.listener = listener; - this.on(type, g); +util.inherits(Duplex, Readable); - return this; -}; +var keys = objectKeys(Writable.prototype); +for (var v = 0; v < keys.length; v++) { + var method = keys[v]; + if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; +} -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; +function Duplex(options) { + if (!(this instanceof Duplex)) return new Duplex(options); - if (!isFunction(listener)) - throw TypeError('listener must be a function'); + Readable.call(this, options); + Writable.call(this, options); - if (!this._events || !this._events[type]) - return this; + if (options && options.readable === false) this.readable = false; - list = this._events[type]; - length = list.length; - position = -1; + if (options && options.writable === false) this.writable = false; - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); + this.allowHalfOpen = true; + if (options && options.allowHalfOpen === false) this.allowHalfOpen = false; - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } + this.once('end', onend); +} - if (position < 0) - return this; +// the no-half-open enforcer +function onend() { + // if we allow half-open state, or if the writable side ended, + // then we're ok. + if (this.allowHalfOpen || this._writableState.ended) return; - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); + // no more data can be written. + // But allow more writes to happen in this tick. + processNextTick(onEndNT, this); +} + +function onEndNT(self) { + self.end(); +} + +Object.defineProperty(Duplex.prototype, 'destroyed', { + get: function () { + if (this._readableState === undefined || this._writableState === undefined) { + return false; + } + return this._readableState.destroyed && this._writableState.destroyed; + }, + set: function (value) { + // we ignore the value if the stream + // has not been initialized yet + if (this._readableState === undefined || this._writableState === undefined) { + return; } - if (this._events.removeListener) - this.emit('removeListener', type, listener); + // backward compatibility, the user is explicitly + // managing destroyed + this._readableState.destroyed = value; + this._writableState.destroyed = value; } +}); - return this; -}; - -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; +Duplex.prototype._destroy = function (err, cb) { + this.push(null); + this.end(); - if (!this._events) - return this; + processNextTick(cb, err); +}; - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; +function forEach(xs, f) { + for (var i = 0, l = xs.length; i < l; i++) { + f(xs[i], i); } +} +},{"./_stream_readable":20,"./_stream_writable":22,"core-util-is":26,"inherits":10,"process-nextick-args":28}],19:[function(_dereq_,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } +// a passthrough stream. +// basically just the most minimal sort of Transform stream. +// Every written chunk gets output as-is. - listeners = this._events[type]; +'use strict'; - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; +module.exports = PassThrough; - return this; -}; +var Transform = _dereq_('./_stream_transform'); -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; +/**/ +var util = _dereq_('core-util-is'); +util.inherits = _dereq_('inherits'); +/**/ -EventEmitter.listenerCount = function(emitter, type) { - var ret; - if (!emitter._events || !emitter._events[type]) - ret = 0; - else if (isFunction(emitter._events[type])) - ret = 1; - else - ret = emitter._events[type].length; - return ret; -}; +util.inherits(PassThrough, Transform); -function isFunction(arg) { - return typeof arg === 'function'; -} +function PassThrough(options) { + if (!(this instanceof PassThrough)) return new PassThrough(options); -function isNumber(arg) { - return typeof arg === 'number'; + Transform.call(this, options); } -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} +PassThrough.prototype._transform = function (chunk, encoding, cb) { + cb(null, chunk); +}; +},{"./_stream_transform":21,"core-util-is":26,"inherits":10}],20:[function(_dereq_,module,exports){ +(function (process,global){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. -function isUndefined(arg) { - return arg === void 0; -} +'use strict'; -},{}],11:[function(_dereq_,module,exports){ +/**/ -var hasOwn = Object.prototype.hasOwnProperty; -var toString = Object.prototype.toString; +var processNextTick = _dereq_('process-nextick-args'); +/**/ -module.exports = function forEach (obj, fn, ctx) { - if (toString.call(fn) !== '[object Function]') { - throw new TypeError('iterator must be a function'); - } - var l = obj.length; - if (l === +l) { - for (var i = 0; i < l; i++) { - fn.call(ctx, obj[i], i, obj); - } - } else { - for (var k in obj) { - if (hasOwn.call(obj, k)) { - fn.call(ctx, obj[k], k, obj); - } - } - } -}; +module.exports = Readable; +/**/ +var isArray = _dereq_('isarray'); +/**/ -},{}],12:[function(_dereq_,module,exports){ -var http = _dereq_('http'); +/**/ +var Duplex; +/**/ -var https = module.exports; +Readable.ReadableState = ReadableState; -for (var key in http) { - if (http.hasOwnProperty(key)) https[key] = http[key]; +/**/ +var EE = _dereq_('events').EventEmitter; + +var EElistenerCount = function (emitter, type) { + return emitter.listeners(type).length; }; +/**/ -https.request = function (params, cb) { - if (!params) params = {}; - params.scheme = 'https'; - params.protocol = 'https:'; - return http.request.call(this, params, cb); +/**/ +var Stream = _dereq_('./internal/streams/stream'); +/**/ + +// TODO(bmeurer): Change this back to const once hole checks are +// properly optimized away early in Ignition+TurboFan. +/**/ +var Buffer = _dereq_('safe-buffer').Buffer; +var OurUint8Array = global.Uint8Array || function () {}; +function _uint8ArrayToBuffer(chunk) { + return Buffer.from(chunk); } +function _isUint8Array(obj) { + return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; +} +/**/ -},{"http":102}],13:[function(_dereq_,module,exports){ -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] +/**/ +var util = _dereq_('core-util-is'); +util.inherits = _dereq_('inherits'); +/**/ - i += d +/**/ +var debugUtil = _dereq_('util'); +var debug = void 0; +if (debugUtil && debugUtil.debuglog) { + debug = debugUtil.debuglog('stream'); +} else { + debug = function () {}; +} +/**/ - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} +var BufferList = _dereq_('./internal/streams/BufferList'); +var destroyImpl = _dereq_('./internal/streams/destroy'); +var StringDecoder; - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} +util.inherits(Readable, Stream); - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) +var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; + +function prependListener(emitter, event, fn) { + // Sadly this is not cacheable as some libraries bundle their own + // event emitter implementation with them. + if (typeof emitter.prependListener === 'function') { + return emitter.prependListener(event, fn); } else { - m = m + Math.pow(2, mLen) - e = e - eBias + // This is a hack to make sure that our error handler is attached before any + // userland ones. NEVER DO THIS. This is here only because this code needs + // to continue to work with older versions of Node.js that do not include + // the prependListener() method. The goal is to eventually remove this hack. + if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) } -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = nBytes * 8 - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 +function ReadableState(options, stream) { + Duplex = Duplex || _dereq_('./_stream_duplex'); - value = Math.abs(value) + options = options || {}; - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } + // object stream flag. Used to make read(n) ignore n and to + // make all the buffer merging and length checks go away + this.objectMode = !!options.objectMode; - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } + if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.readableObjectMode; - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + // the point at which it stops calling _read() to fill the buffer + // Note: 0 is a valid value, means "don't call _read preemptively ever" + var hwm = options.highWaterMark; + var defaultHwm = this.objectMode ? 16 : 16 * 1024; + this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + // cast to ints. + this.highWaterMark = Math.floor(this.highWaterMark); - buffer[offset + i - d] |= s * 128 -} + // A linked list is used to store data chunks instead of an array because the + // linked list can remove elements from the beginning faster than + // array.shift() + this.buffer = new BufferList(); + this.length = 0; + this.pipes = null; + this.pipesCount = 0; + this.flowing = null; + this.ended = false; + this.endEmitted = false; + this.reading = false; -},{}],14:[function(_dereq_,module,exports){ + // a flag to be able to tell if the event 'readable'/'data' is emitted + // immediately, or on a later tick. We set this to true at first, because + // any actions that shouldn't happen until "later" should generally also + // not happen before the first read call. + this.sync = true; -var indexOf = [].indexOf; + // whenever we return null, then we set a flag to say + // that we're awaiting a 'readable' event emission. + this.needReadable = false; + this.emittedReadable = false; + this.readableListening = false; + this.resumeScheduled = false; -module.exports = function(arr, obj){ - if (indexOf) return arr.indexOf(obj); - for (var i = 0; i < arr.length; ++i) { - if (arr[i] === obj) return i; - } - return -1; -}; -},{}],15:[function(_dereq_,module,exports){ -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } -} + // has it been destroyed + this.destroyed = false; -},{}],16:[function(_dereq_,module,exports){ -/*! - * Determine if an object is a Buffer - * - * @author Feross Aboukhadijeh - * @license MIT - */ + // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + this.defaultEncoding = options.defaultEncoding || 'utf8'; -// The _isBuffer check is for Safari 5-7 support, because it's missing -// Object.prototype.constructor. Remove this eventually -module.exports = function (obj) { - return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) -} + // the number of writers that are awaiting a drain event in .pipe()s + this.awaitDrain = 0; -function isBuffer (obj) { - return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) -} + // if true, a maybeReadMore has been scheduled + this.readingMore = false; -// For Node v0.10 support. Remove this eventually. -function isSlowBuffer (obj) { - return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) + this.decoder = null; + this.encoding = null; + if (options.encoding) { + if (!StringDecoder) StringDecoder = _dereq_('string_decoder/').StringDecoder; + this.decoder = new StringDecoder(options.encoding); + this.encoding = options.encoding; + } } -},{}],17:[function(_dereq_,module,exports){ -// Ignore module for browserify (see package.json) -},{}],18:[function(_dereq_,module,exports){ -(function (process,global,__dirname){ -/** - * A JavaScript implementation of the JSON-LD API. - * - * @author Dave Longley - * - * @license BSD 3-Clause License - * Copyright (c) 2011-2015 Digital Bazaar, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of the Digital Bazaar, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -(function() { +function Readable(options) { + Duplex = Duplex || _dereq_('./_stream_duplex'); -// determine if in-browser or using node.js -var _nodejs = ( - typeof process !== 'undefined' && process.versions && process.versions.node); -var _browser = !_nodejs && - (typeof window !== 'undefined' || typeof self !== 'undefined'); -if(_browser) { - if(typeof global === 'undefined') { - if(typeof window !== 'undefined') { - global = window; - } else if(typeof self !== 'undefined') { - global = self; - } else if(typeof $ !== 'undefined') { - global = $; - } - } -} + if (!(this instanceof Readable)) return new Readable(options); -// attaches jsonld API to the given object -var wrapper = function(jsonld) { + this._readableState = new ReadableState(options, this); -/* Core API */ + // legacy + this.readable = true; -/** - * Performs JSON-LD compaction. - * - * @param input the JSON-LD input to compact. - * @param ctx the context to compact with. - * @param [options] options to use: - * [base] the base IRI to use. - * [compactArrays] true to compact arrays to single values when - * appropriate, false not to (default: true). - * [graph] true to always output a top-level graph (default: false). - * [expandContext] a context to expand with. - * [skipExpansion] true to assume the input is expanded and skip - * expansion, false not to, defaults to false. - * [documentLoader(url, callback(err, remoteDoc))] the document loader. - * @param callback(err, compacted, ctx) called once the operation completes. - */ -jsonld.compact = function(input, ctx, options, callback) { - if(arguments.length < 2) { - return jsonld.nextTick(function() { - callback(new TypeError('Could not compact, too few arguments.')); - }); - } + if (options) { + if (typeof options.read === 'function') this._read = options.read; - // get arguments - if(typeof options === 'function') { - callback = options; - options = {}; + if (typeof options.destroy === 'function') this._destroy = options.destroy; } - options = options || {}; - if(ctx === null) { - return jsonld.nextTick(function() { - callback(new JsonLdError( - 'The compaction context must not be null.', - 'jsonld.CompactError', {code: 'invalid local context'})); - }); - } + Stream.call(this); +} - // nothing to compact - if(input === null) { - return jsonld.nextTick(function() { - callback(null, null); - }); - } +Object.defineProperty(Readable.prototype, 'destroyed', { + get: function () { + if (this._readableState === undefined) { + return false; + } + return this._readableState.destroyed; + }, + set: function (value) { + // we ignore the value if the stream + // has not been initialized yet + if (!this._readableState) { + return; + } - // set default options - if(!('base' in options)) { - options.base = (typeof input === 'string') ? input : ''; - } - if(!('compactArrays' in options)) { - options.compactArrays = true; - } - if(!('graph' in options)) { - options.graph = false; - } - if(!('skipExpansion' in options)) { - options.skipExpansion = false; - } - if(!('documentLoader' in options)) { - options.documentLoader = jsonld.loadDocument; - } - if(!('link' in options)) { - options.link = false; - } - if(options.link) { - // force skip expansion when linking, "link" is not part of the public - // API, it should only be called from framing - options.skipExpansion = true; + // backward compatibility, the user is explicitly + // managing destroyed + this._readableState.destroyed = value; } +}); - var expand = function(input, options, callback) { - if(options.skipExpansion) { - return jsonld.nextTick(function() { - callback(null, input); - }); - } - jsonld.expand(input, options, callback); - }; - - // expand input then do compaction - expand(input, options, function(err, expanded) { - if(err) { - return callback(new JsonLdError( - 'Could not expand input before compaction.', - 'jsonld.CompactError', {cause: err})); - } +Readable.prototype.destroy = destroyImpl.destroy; +Readable.prototype._undestroy = destroyImpl.undestroy; +Readable.prototype._destroy = function (err, cb) { + this.push(null); + cb(err); +}; - // process context - var activeCtx = _getInitialContext(options); - jsonld.processContext(activeCtx, ctx, options, function(err, activeCtx) { - if(err) { - return callback(new JsonLdError( - 'Could not process context before compaction.', - 'jsonld.CompactError', {cause: err})); - } +// Manually shove something into the read() buffer. +// This returns true if the highWaterMark has not been hit yet, +// similar to how Writable.write() returns true if you should +// write() some more. +Readable.prototype.push = function (chunk, encoding) { + var state = this._readableState; + var skipChunkCheck; - var compacted; - try { - // do compaction - compacted = new Processor().compact(activeCtx, null, expanded, options); - } catch(ex) { - return callback(ex); + if (!state.objectMode) { + if (typeof chunk === 'string') { + encoding = encoding || state.defaultEncoding; + if (encoding !== state.encoding) { + chunk = Buffer.from(chunk, encoding); + encoding = ''; } + skipChunkCheck = true; + } + } else { + skipChunkCheck = true; + } - cleanup(null, compacted, activeCtx, options); - }); - }); + return readableAddChunk(this, chunk, encoding, false, skipChunkCheck); +}; - // performs clean up after compaction - function cleanup(err, compacted, activeCtx, options) { - if(err) { - return callback(err); - } +// Unshift should *always* be something directly out of read() +Readable.prototype.unshift = function (chunk) { + return readableAddChunk(this, chunk, null, true, false); +}; - if(options.compactArrays && !options.graph && _isArray(compacted)) { - if(compacted.length === 1) { - // simplify to a single item - compacted = compacted[0]; - } else if(compacted.length === 0) { - // simplify to an empty object - compacted = {}; +function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { + var state = stream._readableState; + if (chunk === null) { + state.reading = false; + onEofChunk(stream, state); + } else { + var er; + if (!skipChunkCheck) er = chunkInvalid(state, chunk); + if (er) { + stream.emit('error', er); + } else if (state.objectMode || chunk && chunk.length > 0) { + if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) { + chunk = _uint8ArrayToBuffer(chunk); } - } else if(options.graph && _isObject(compacted)) { - // always use array if graph option is on - compacted = [compacted]; - } - - // follow @context key - if(_isObject(ctx) && '@context' in ctx) { - ctx = ctx['@context']; - } - // build output context - ctx = _clone(ctx); - if(!_isArray(ctx)) { - ctx = [ctx]; - } - // remove empty contexts - var tmp = ctx; - ctx = []; - for(var i = 0; i < tmp.length; ++i) { - if(!_isObject(tmp[i]) || Object.keys(tmp[i]).length > 0) { - ctx.push(tmp[i]); + if (addToFront) { + if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true); + } else if (state.ended) { + stream.emit('error', new Error('stream.push() after EOF')); + } else { + state.reading = false; + if (state.decoder && !encoding) { + chunk = state.decoder.write(chunk); + if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state); + } else { + addChunk(stream, state, chunk, false); + } } + } else if (!addToFront) { + state.reading = false; } + } - // remove array if only one context - var hasContext = (ctx.length > 0); - if(ctx.length === 1) { - ctx = ctx[0]; - } + return needMoreData(state); +} - // add context and/or @graph - if(_isArray(compacted)) { - // use '@graph' keyword - var kwgraph = _compactIri(activeCtx, '@graph'); - var graph = compacted; - compacted = {}; - if(hasContext) { - compacted['@context'] = ctx; - } - compacted[kwgraph] = graph; - } else if(_isObject(compacted) && hasContext) { - // reorder keys so @context is first - var graph = compacted; - compacted = {'@context': ctx}; - for(var key in graph) { - compacted[key] = graph[key]; - } - } +function addChunk(stream, state, chunk, addToFront) { + if (state.flowing && state.length === 0 && !state.sync) { + stream.emit('data', chunk); + stream.read(0); + } else { + // update the buffer info. + state.length += state.objectMode ? 1 : chunk.length; + if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk); - callback(null, compacted, activeCtx); + if (state.needReadable) emitReadable(stream); } -}; + maybeReadMore(stream, state); +} -/** - * Performs JSON-LD expansion. - * - * @param input the JSON-LD input to expand. - * @param [options] the options to use: - * [base] the base IRI to use. - * [expandContext] a context to expand with. - * [keepFreeFloatingNodes] true to keep free-floating nodes, - * false not to, defaults to false. - * [documentLoader(url, callback(err, remoteDoc))] the document loader. - * @param callback(err, expanded) called once the operation completes. - */ -jsonld.expand = function(input, options, callback) { - if(arguments.length < 1) { - return jsonld.nextTick(function() { - callback(new TypeError('Could not expand, too few arguments.')); - }); +function chunkInvalid(state, chunk) { + var er; + if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { + er = new TypeError('Invalid non-string/buffer chunk'); } + return er; +} - // get arguments - if(typeof options === 'function') { - callback = options; - options = {}; - } - options = options || {}; +// if it's past the high water mark, we can push in some more. +// Also, if we have no data yet, we can stand some +// more bytes. This is to work around cases where hwm=0, +// such as the repl. Also, if the push() triggered a +// readable event, and the user called read(largeNumber) such that +// needReadable was set, then we ought to push more, so that another +// 'readable' event will be triggered. +function needMoreData(state) { + return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0); +} - // set default options - if(!('documentLoader' in options)) { - options.documentLoader = jsonld.loadDocument; - } - if(!('keepFreeFloatingNodes' in options)) { - options.keepFreeFloatingNodes = false; - } +Readable.prototype.isPaused = function () { + return this._readableState.flowing === false; +}; - jsonld.nextTick(function() { - // if input is a string, attempt to dereference remote document - if(typeof input === 'string') { - var done = function(err, remoteDoc) { - if(err) { - return callback(err); - } - try { - if(!remoteDoc.document) { - throw new JsonLdError( - 'No remote document found at the given URL.', - 'jsonld.NullRemoteDocument'); - } - if(typeof remoteDoc.document === 'string') { - remoteDoc.document = JSON.parse(remoteDoc.document); - } - } catch(ex) { - return callback(new JsonLdError( - 'Could not retrieve a JSON-LD document from the URL. URL ' + - 'dereferencing not implemented.', 'jsonld.LoadDocumentError', { - code: 'loading document failed', - cause: ex, - remoteDoc: remoteDoc - })); - } - expand(remoteDoc); - }; - var promise = options.documentLoader(input, done); - if(promise && 'then' in promise) { - promise.then(done.bind(null, null), done); - } - return; - } - // nothing to load - expand({contextUrl: null, documentUrl: null, document: input}); - }); +// backwards compatibility. +Readable.prototype.setEncoding = function (enc) { + if (!StringDecoder) StringDecoder = _dereq_('string_decoder/').StringDecoder; + this._readableState.decoder = new StringDecoder(enc); + this._readableState.encoding = enc; + return this; +}; - function expand(remoteDoc) { - // set default base - if(!('base' in options)) { - options.base = remoteDoc.documentUrl || ''; - } - // build meta-object and retrieve all @context URLs - var input = { - document: _clone(remoteDoc.document), - remoteContext: {'@context': remoteDoc.contextUrl} - }; - if('expandContext' in options) { - var expandContext = _clone(options.expandContext); - if(typeof expandContext === 'object' && '@context' in expandContext) { - input.expandContext = expandContext; - } else { - input.expandContext = {'@context': expandContext}; - } - } - _retrieveContextUrls(input, options, function(err, input) { - if(err) { - return callback(err); - } +// Don't raise the hwm > 8MB +var MAX_HWM = 0x800000; +function computeNewHighWaterMark(n) { + if (n >= MAX_HWM) { + n = MAX_HWM; + } else { + // Get the next highest power of 2 to prevent increasing hwm excessively in + // tiny amounts + n--; + n |= n >>> 1; + n |= n >>> 2; + n |= n >>> 4; + n |= n >>> 8; + n |= n >>> 16; + n++; + } + return n; +} - var expanded; - try { - var processor = new Processor(); - var activeCtx = _getInitialContext(options); - var document = input.document; - var remoteContext = input.remoteContext['@context']; +// This function is designed to be inlinable, so please take care when making +// changes to the function body. +function howMuchToRead(n, state) { + if (n <= 0 || state.length === 0 && state.ended) return 0; + if (state.objectMode) return 1; + if (n !== n) { + // Only flow one buffer at a time + if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length; + } + // If we're asking for more than the current hwm, then raise the hwm. + if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n); + if (n <= state.length) return n; + // Don't have enough + if (!state.ended) { + state.needReadable = true; + return 0; + } + return state.length; +} - // process optional expandContext - if(input.expandContext) { - activeCtx = processor.processContext( - activeCtx, input.expandContext['@context'], options); - } +// you can override either this method, or the async _read(n) below. +Readable.prototype.read = function (n) { + debug('read', n); + n = parseInt(n, 10); + var state = this._readableState; + var nOrig = n; - // process remote context from HTTP Link Header - if(remoteContext) { - activeCtx = processor.processContext( - activeCtx, remoteContext, options); - } + if (n !== 0) state.emittedReadable = false; - // expand document - expanded = processor.expand( - activeCtx, null, document, options, false); + // if we're doing read(0) to trigger a readable event, but we + // already have a bunch of data in the buffer, then just trigger + // the 'readable' event and move on. + if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) { + debug('read: emitReadable', state.length, state.ended); + if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this); + return null; + } - // optimize away @graph with no other properties - if(_isObject(expanded) && ('@graph' in expanded) && - Object.keys(expanded).length === 1) { - expanded = expanded['@graph']; - } else if(expanded === null) { - expanded = []; - } + n = howMuchToRead(n, state); - // normalize to an array - if(!_isArray(expanded)) { - expanded = [expanded]; - } - } catch(ex) { - return callback(ex); - } - callback(null, expanded); - }); + // if we've ended, and we're now clear, then finish it up. + if (n === 0 && state.ended) { + if (state.length === 0) endReadable(this); + return null; } -}; -/** - * Performs JSON-LD flattening. - * - * @param input the JSON-LD to flatten. - * @param ctx the context to use to compact the flattened output, or null. - * @param [options] the options to use: - * [base] the base IRI to use. - * [expandContext] a context to expand with. - * [documentLoader(url, callback(err, remoteDoc))] the document loader. - * @param callback(err, flattened) called once the operation completes. - */ -jsonld.flatten = function(input, ctx, options, callback) { - if(arguments.length < 1) { - return jsonld.nextTick(function() { - callback(new TypeError('Could not flatten, too few arguments.')); - }); - } + // All the actual chunk generation logic needs to be + // *below* the call to _read. The reason is that in certain + // synthetic stream cases, such as passthrough streams, _read + // may be a completely synchronous operation which may change + // the state of the read buffer, providing enough data when + // before there was *not* enough. + // + // So, the steps are: + // 1. Figure out what the state of things will be after we do + // a read from the buffer. + // + // 2. If that resulting state will trigger a _read, then call _read. + // Note that this may be asynchronous, or synchronous. Yes, it is + // deeply ugly to write APIs this way, but that still doesn't mean + // that the Readable class should behave improperly, as streams are + // designed to be sync/async agnostic. + // Take note if the _read call is sync or async (ie, if the read call + // has returned yet), so that we know whether or not it's safe to emit + // 'readable' etc. + // + // 3. Actually pull the requested chunks out of the buffer and return. - // get arguments - if(typeof options === 'function') { - callback = options; - options = {}; - } else if(typeof ctx === 'function') { - callback = ctx; - ctx = null; - options = {}; + // if we need a readable event, then we need to do some reading. + var doRead = state.needReadable; + debug('need readable', doRead); + + // if we currently have less than the highWaterMark, then also read some + if (state.length === 0 || state.length - n < state.highWaterMark) { + doRead = true; + debug('length less than watermark', doRead); } - options = options || {}; - // set default options - if(!('base' in options)) { - options.base = (typeof input === 'string') ? input : ''; + // however, if we've ended, then there's no point, and if we're already + // reading, then it's unnecessary. + if (state.ended || state.reading) { + doRead = false; + debug('reading or ended', doRead); + } else if (doRead) { + debug('do read'); + state.reading = true; + state.sync = true; + // if the length is currently zero, then we *need* a readable event. + if (state.length === 0) state.needReadable = true; + // call internal read method + this._read(state.highWaterMark); + state.sync = false; + // If _read pushed data synchronously, then `reading` will be false, + // and we need to re-evaluate how much data we can return to the user. + if (!state.reading) n = howMuchToRead(nOrig, state); } - if(!('documentLoader' in options)) { - options.documentLoader = jsonld.loadDocument; + + var ret; + if (n > 0) ret = fromList(n, state);else ret = null; + + if (ret === null) { + state.needReadable = true; + n = 0; + } else { + state.length -= n; } - // expand input - jsonld.expand(input, options, function(err, _input) { - if(err) { - return callback(new JsonLdError( - 'Could not expand input before flattening.', - 'jsonld.FlattenError', {cause: err})); - } + if (state.length === 0) { + // If we have nothing in the buffer, then we want to know + // as soon as we *do* get something into the buffer. + if (!state.ended) state.needReadable = true; - var flattened; - try { - // do flattening - flattened = new Processor().flatten(_input); - } catch(ex) { - return callback(ex); - } + // If we tried to read() past the EOF, then emit end on the next tick. + if (nOrig !== n && state.ended) endReadable(this); + } - if(ctx === null) { - return callback(null, flattened); - } + if (ret !== null) this.emit('data', ret); - // compact result (force @graph option to true, skip expansion) - options.graph = true; - options.skipExpansion = true; - jsonld.compact(flattened, ctx, options, function(err, compacted) { - if(err) { - return callback(new JsonLdError( - 'Could not compact flattened output.', - 'jsonld.FlattenError', {cause: err})); - } - callback(null, compacted); - }); - }); + return ret; }; -/** - * Performs JSON-LD framing. - * - * @param input the JSON-LD input to frame. - * @param frame the JSON-LD frame to use. - * @param [options] the framing options. - * [base] the base IRI to use. - * [expandContext] a context to expand with. - * [embed] default @embed flag: '@last', '@always', '@never', '@link' - * (default: '@last'). - * [explicit] default @explicit flag (default: false). - * [requireAll] default @requireAll flag (default: true). - * [omitDefault] default @omitDefault flag (default: false). - * [documentLoader(url, callback(err, remoteDoc))] the document loader. - * @param callback(err, framed) called once the operation completes. - */ -jsonld.frame = function(input, frame, options, callback) { - if(arguments.length < 2) { - return jsonld.nextTick(function() { - callback(new TypeError('Could not frame, too few arguments.')); - }); +function onEofChunk(stream, state) { + if (state.ended) return; + if (state.decoder) { + var chunk = state.decoder.end(); + if (chunk && chunk.length) { + state.buffer.push(chunk); + state.length += state.objectMode ? 1 : chunk.length; + } } + state.ended = true; - // get arguments - if(typeof options === 'function') { - callback = options; - options = {}; - } - options = options || {}; + // emit 'readable' now to make sure it gets picked up. + emitReadable(stream); +} - // set default options - if(!('base' in options)) { - options.base = (typeof input === 'string') ? input : ''; +// Don't emit readable right away in sync mode, because this can trigger +// another read() call => stack overflow. This way, it might trigger +// a nextTick recursion warning, but that's not so bad. +function emitReadable(stream) { + var state = stream._readableState; + state.needReadable = false; + if (!state.emittedReadable) { + debug('emitReadable', state.flowing); + state.emittedReadable = true; + if (state.sync) processNextTick(emitReadable_, stream);else emitReadable_(stream); } - if(!('documentLoader' in options)) { - options.documentLoader = jsonld.loadDocument; +} + +function emitReadable_(stream) { + debug('emit readable'); + stream.emit('readable'); + flow(stream); +} + +// at this point, the user has presumably seen the 'readable' event, +// and called read() to consume some data. that may have triggered +// in turn another _read(n) call, in which case reading = true if +// it's in progress. +// However, if we're not ended, or reading, and the length < hwm, +// then go ahead and try to read some more preemptively. +function maybeReadMore(stream, state) { + if (!state.readingMore) { + state.readingMore = true; + processNextTick(maybeReadMore_, stream, state); } - if(!('embed' in options)) { - options.embed = '@last'; +} + +function maybeReadMore_(stream, state) { + var len = state.length; + while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) { + debug('maybeReadMore read 0'); + stream.read(0); + if (len === state.length) + // didn't get any data, stop spinning. + break;else len = state.length; } - options.explicit = options.explicit || false; - if(!('requireAll' in options)) { - options.requireAll = true; + state.readingMore = false; +} + +// abstract method. to be overridden in specific implementation classes. +// call cb(er, data) where data is <= n in length. +// for virtual (non-string, non-buffer) streams, "length" is somewhat +// arbitrary, and perhaps not very meaningful. +Readable.prototype._read = function (n) { + this.emit('error', new Error('_read() is not implemented')); +}; + +Readable.prototype.pipe = function (dest, pipeOpts) { + var src = this; + var state = this._readableState; + + switch (state.pipesCount) { + case 0: + state.pipes = dest; + break; + case 1: + state.pipes = [state.pipes, dest]; + break; + default: + state.pipes.push(dest); + break; } - options.omitDefault = options.omitDefault || false; + state.pipesCount += 1; + debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); - jsonld.nextTick(function() { - // if frame is a string, attempt to dereference remote document - if(typeof frame === 'string') { - var done = function(err, remoteDoc) { - if(err) { - return callback(err); - } - try { - if(!remoteDoc.document) { - throw new JsonLdError( - 'No remote document found at the given URL.', - 'jsonld.NullRemoteDocument'); - } - if(typeof remoteDoc.document === 'string') { - remoteDoc.document = JSON.parse(remoteDoc.document); - } - } catch(ex) { - return callback(new JsonLdError( - 'Could not retrieve a JSON-LD document from the URL. URL ' + - 'dereferencing not implemented.', 'jsonld.LoadDocumentError', { - code: 'loading document failed', - cause: ex, - remoteDoc: remoteDoc - })); - } - doFrame(remoteDoc); - }; - var promise = options.documentLoader(frame, done); - if(promise && 'then' in promise) { - promise.then(done.bind(null, null), done); - } - return; - } - // nothing to load - doFrame({contextUrl: null, documentUrl: null, document: frame}); - }); + var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; - function doFrame(remoteFrame) { - // preserve frame context and add any Link header context - var frame = remoteFrame.document; - var ctx; - if(frame) { - ctx = frame['@context']; - if(remoteFrame.contextUrl) { - if(!ctx) { - ctx = remoteFrame.contextUrl; - } else if(_isArray(ctx)) { - ctx.push(remoteFrame.contextUrl); - } else { - ctx = [ctx, remoteFrame.contextUrl]; - } - frame['@context'] = ctx; - } else { - ctx = ctx || {}; + var endFn = doEnd ? onend : unpipe; + if (state.endEmitted) processNextTick(endFn);else src.once('end', endFn); + + dest.on('unpipe', onunpipe); + function onunpipe(readable, unpipeInfo) { + debug('onunpipe'); + if (readable === src) { + if (unpipeInfo && unpipeInfo.hasUnpiped === false) { + unpipeInfo.hasUnpiped = true; + cleanup(); } - } else { - ctx = {}; } + } - // expand input - jsonld.expand(input, options, function(err, expanded) { - if(err) { - return callback(new JsonLdError( - 'Could not expand input before framing.', - 'jsonld.FrameError', {cause: err})); - } + function onend() { + debug('onend'); + dest.end(); + } - // expand frame - var opts = _clone(options); - opts.isFrame = true; - opts.keepFreeFloatingNodes = true; - jsonld.expand(frame, opts, function(err, expandedFrame) { - if(err) { - return callback(new JsonLdError( - 'Could not expand frame before framing.', - 'jsonld.FrameError', {cause: err})); - } + // when the dest drains, it reduces the awaitDrain counter + // on the source. This would be more elegant with a .once() + // handler in flow(), but adding and removing repeatedly is + // too slow. + var ondrain = pipeOnDrain(src); + dest.on('drain', ondrain); - var framed; - try { - // do framing - framed = new Processor().frame(expanded, expandedFrame, opts); - } catch(ex) { - return callback(ex); - } + var cleanedUp = false; + function cleanup() { + debug('cleanup'); + // cleanup event handlers once the pipe is broken + dest.removeListener('close', onclose); + dest.removeListener('finish', onfinish); + dest.removeListener('drain', ondrain); + dest.removeListener('error', onerror); + dest.removeListener('unpipe', onunpipe); + src.removeListener('end', onend); + src.removeListener('end', unpipe); + src.removeListener('data', ondata); - // compact result (force @graph option to true, skip expansion, - // check for linked embeds) - opts.graph = true; - opts.skipExpansion = true; - opts.link = {}; - jsonld.compact(framed, ctx, opts, function(err, compacted, ctx) { - if(err) { - return callback(new JsonLdError( - 'Could not compact framed output.', - 'jsonld.FrameError', {cause: err})); - } - // get graph alias - var graph = _compactIri(ctx, '@graph'); - // remove @preserve from results - opts.link = {}; - compacted[graph] = _removePreserve(ctx, compacted[graph], opts); - callback(null, compacted); - }); - }); - }); + cleanedUp = true; + + // if the reader is waiting for a drain event from this + // specific writer, then it would cause it to never start + // flowing again. + // So, if this is awaiting a drain, then we just call it now. + // If we don't know, then assume that we are waiting for one. + if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain(); } -}; -/** - * **Experimental** - * - * Links a JSON-LD document's nodes in memory. - * - * @param input the JSON-LD document to link. - * @param ctx the JSON-LD context to apply. - * @param [options] the options to use: - * [base] the base IRI to use. - * [expandContext] a context to expand with. - * [documentLoader(url, callback(err, remoteDoc))] the document loader. - * @param callback(err, linked) called once the operation completes. - */ -jsonld.link = function(input, ctx, options, callback) { - // API matches running frame with a wildcard frame and embed: '@link' - // get arguments - var frame = {}; - if(ctx) { - frame['@context'] = ctx; + // If the user pushes more data while we're writing to dest then we'll end up + // in ondata again. However, we only want to increase awaitDrain once because + // dest will only emit one 'drain' event for the multiple writes. + // => Introduce a guard on increasing awaitDrain. + var increasedAwaitDrain = false; + src.on('data', ondata); + function ondata(chunk) { + debug('ondata'); + increasedAwaitDrain = false; + var ret = dest.write(chunk); + if (false === ret && !increasedAwaitDrain) { + // If the user unpiped during `dest.write()`, it is possible + // to get stuck in a permanently paused state if that write + // also returned false. + // => Check whether `dest` is still a piping destination. + if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) { + debug('false write response, pause', src._readableState.awaitDrain); + src._readableState.awaitDrain++; + increasedAwaitDrain = true; + } + src.pause(); + } } - frame['@embed'] = '@link'; - jsonld.frame(input, frame, options, callback); -}; -/** - * **Deprecated** - * - * Performs JSON-LD objectification. - * - * @param input the JSON-LD document to objectify. - * @param ctx the JSON-LD context to apply. - * @param [options] the options to use: - * [base] the base IRI to use. - * [expandContext] a context to expand with. - * [documentLoader(url, callback(err, remoteDoc))] the document loader. - * @param callback(err, linked) called once the operation completes. - */ -jsonld.objectify = function(input, ctx, options, callback) { - if(typeof options === 'function') { - callback = options; - options = {}; + // if the dest has an error, then stop piping into it. + // however, don't suppress the throwing behavior for this. + function onerror(er) { + debug('onerror', er); + unpipe(); + dest.removeListener('error', onerror); + if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er); } - options = options || {}; - // set default options - if(!('base' in options)) { - options.base = (typeof input === 'string') ? input : ''; + // Make sure our error handler is attached before userland ones. + prependListener(dest, 'error', onerror); + + // Both close and finish should trigger unpipe, but only once. + function onclose() { + dest.removeListener('finish', onfinish); + unpipe(); } - if(!('documentLoader' in options)) { - options.documentLoader = jsonld.loadDocument; + dest.once('close', onclose); + function onfinish() { + debug('onfinish'); + dest.removeListener('close', onclose); + unpipe(); } + dest.once('finish', onfinish); - // expand input - jsonld.expand(input, options, function(err, _input) { - if(err) { - return callback(new JsonLdError( - 'Could not expand input before linking.', - 'jsonld.LinkError', {cause: err})); - } + function unpipe() { + debug('unpipe'); + src.unpipe(dest); + } - var flattened; - try { - // flatten the graph - flattened = new Processor().flatten(_input); - } catch(ex) { - return callback(ex); - } + // tell the dest that it's being piped to + dest.emit('pipe', src); - // compact result (force @graph option to true, skip expansion) - options.graph = true; - options.skipExpansion = true; - jsonld.compact(flattened, ctx, options, function(err, compacted, ctx) { - if(err) { - return callback(new JsonLdError( - 'Could not compact flattened output before linking.', - 'jsonld.LinkError', {cause: err})); - } - // get graph alias - var graph = _compactIri(ctx, '@graph'); - var top = compacted[graph][0]; + // start the flow if it hasn't been started already. + if (!state.flowing) { + debug('pipe resume'); + src.resume(); + } - var recurse = function(subject) { - // can't replace just a string - if(!_isObject(subject) && !_isArray(subject)) { - return; - } + return dest; +}; - // bottom out recursion on re-visit - if(_isObject(subject)) { - if(recurse.visited[subject['@id']]) { - return; - } - recurse.visited[subject['@id']] = true; - } +function pipeOnDrain(src) { + return function () { + var state = src._readableState; + debug('pipeOnDrain', state.awaitDrain); + if (state.awaitDrain) state.awaitDrain--; + if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) { + state.flowing = true; + flow(src); + } + }; +} - // each array element *or* object key - for(var k in subject) { - var obj = subject[k]; - var isid = (jsonld.getContextValue(ctx, k, '@type') === '@id'); +Readable.prototype.unpipe = function (dest) { + var state = this._readableState; + var unpipeInfo = { hasUnpiped: false }; - // can't replace a non-object or non-array unless it's an @id - if(!_isArray(obj) && !_isObject(obj) && !isid) { - continue; - } + // if we're not piping anywhere, then do nothing. + if (state.pipesCount === 0) return this; - if(_isString(obj) && isid) { - subject[k] = obj = top[obj]; - recurse(obj); - } else if(_isArray(obj)) { - for(var i = 0; i < obj.length; ++i) { - if(_isString(obj[i]) && isid) { - obj[i] = top[obj[i]]; - } else if(_isObject(obj[i]) && '@id' in obj[i]) { - obj[i] = top[obj[i]['@id']]; - } - recurse(obj[i]); - } - } else if(_isObject(obj)) { - var sid = obj['@id']; - subject[k] = obj = top[sid]; - recurse(obj); - } - } - }; - recurse.visited = {}; - recurse(top); + // just one destination. most common case. + if (state.pipesCount === 1) { + // passed in one, but it's not the right one. + if (dest && dest !== state.pipes) return this; - compacted.of_type = {}; - for(var s in top) { - if(!('@type' in top[s])) { - continue; - } - var types = top[s]['@type']; - if(!_isArray(types)) { - types = [types]; - } - for(var t = 0; t < types.length; ++t) { - if(!(types[t] in compacted.of_type)) { - compacted.of_type[types[t]] = []; - } - compacted.of_type[types[t]].push(top[s]); - } - } - callback(null, compacted); - }); - }); -}; + if (!dest) dest = state.pipes; -/** - * Performs RDF dataset normalization on the given input. The input is JSON-LD - * unless the 'inputFormat' option is used. The output is an RDF dataset - * unless the 'format' option is used. - * - * @param input the input to normalize as JSON-LD or as a format specified by - * the 'inputFormat' option. - * @param [options] the options to use: - * [algorithm] the normalization algorithm to use, `URDNA2015` or - * `URGNA2012` (default: `URGNA2012`). - * [base] the base IRI to use. - * [expandContext] a context to expand with. - * [inputFormat] the format if input is not JSON-LD: - * 'application/nquads' for N-Quads. - * [format] the format if output is a string: - * 'application/nquads' for N-Quads. - * [documentLoader(url, callback(err, remoteDoc))] the document loader. - * @param callback(err, normalized) called once the operation completes. - */ -jsonld.normalize = function(input, options, callback) { - if(arguments.length < 1) { - return jsonld.nextTick(function() { - callback(new TypeError('Could not normalize, too few arguments.')); - }); + // got a match. + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; + if (dest) dest.emit('unpipe', this, unpipeInfo); + return this; } - // get arguments - if(typeof options === 'function') { - callback = options; - options = {}; - } - options = options || {}; + // slow case. multiple pipe destinations. - // set default options - if(!('algorithm' in options)) { - options.algorithm = 'URGNA2012'; - } - if(!('base' in options)) { - options.base = (typeof input === 'string') ? input : ''; - } - if(!('documentLoader' in options)) { - options.documentLoader = jsonld.loadDocument; - } + if (!dest) { + // remove all. + var dests = state.pipes; + var len = state.pipesCount; + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; - if('inputFormat' in options) { - if(options.inputFormat !== 'application/nquads') { - return callback(new JsonLdError( - 'Unknown normalization input format.', - 'jsonld.NormalizeError')); - } - var parsedInput = _parseNQuads(input); - // do normalization - new Processor().normalize(parsedInput, options, callback); - } else { - // convert to RDF dataset then do normalization - var opts = _clone(options); - delete opts.format; - opts.produceGeneralizedRdf = false; - jsonld.toRDF(input, opts, function(err, dataset) { - if(err) { - return callback(new JsonLdError( - 'Could not convert input to RDF dataset before normalization.', - 'jsonld.NormalizeError', {cause: err})); - } - // do normalization - new Processor().normalize(dataset, options, callback); - }); + for (var i = 0; i < len; i++) { + dests[i].emit('unpipe', this, unpipeInfo); + }return this; } -}; -/** - * Converts an RDF dataset to JSON-LD. - * - * @param dataset a serialized string of RDF in a format specified by the - * format option or an RDF dataset to convert. - * @param [options] the options to use: - * [format] the format if dataset param must first be parsed: - * 'application/nquads' for N-Quads (default). - * [rdfParser] a custom RDF-parser to use to parse the dataset. - * [useRdfType] true to use rdf:type, false to use @type - * (default: false). - * [useNativeTypes] true to convert XSD types into native types - * (boolean, integer, double), false not to (default: false). - * @param callback(err, output) called once the operation completes. - */ -jsonld.fromRDF = function(dataset, options, callback) { - if(arguments.length < 1) { - return jsonld.nextTick(function() { - callback(new TypeError('Could not convert from RDF, too few arguments.')); - }); - } + // try to find the right one. + var index = indexOf(state.pipes, dest); + if (index === -1) return this; - // get arguments - if(typeof options === 'function') { - callback = options; - options = {}; - } - options = options || {}; + state.pipes.splice(index, 1); + state.pipesCount -= 1; + if (state.pipesCount === 1) state.pipes = state.pipes[0]; - // set default options - if(!('useRdfType' in options)) { - options.useRdfType = false; - } - if(!('useNativeTypes' in options)) { - options.useNativeTypes = false; - } + dest.emit('unpipe', this, unpipeInfo); - if(!('format' in options) && _isString(dataset)) { - // set default format to nquads - if(!('format' in options)) { - options.format = 'application/nquads'; - } - } + return this; +}; - jsonld.nextTick(function() { - // handle special format - var rdfParser; - if(options.format) { - // check supported formats - rdfParser = options.rdfParser || _rdfParsers[options.format]; - if(!rdfParser) { - return callback(new JsonLdError( - 'Unknown input format.', - 'jsonld.UnknownFormat', {format: options.format})); - } - } else { - // no-op parser, assume dataset already parsed - rdfParser = function() { - return dataset; - }; - } +// set up data events if they are asked for +// Ensure readable listeners eventually get something +Readable.prototype.on = function (ev, fn) { + var res = Stream.prototype.on.call(this, ev, fn); - var callbackCalled = false; - try { - // rdf parser may be async or sync, always pass callback - dataset = rdfParser(dataset, function(err, dataset) { - callbackCalled = true; - if(err) { - return callback(err); - } - fromRDF(dataset, options, callback); - }); - } catch(e) { - if(!callbackCalled) { - return callback(e); - } - throw e; - } - // handle synchronous or promise-based parser - if(dataset) { - // if dataset is actually a promise - if('then' in dataset) { - return dataset.then(function(dataset) { - fromRDF(dataset, options, callback); - }, callback); + if (ev === 'data') { + // Start flowing on next tick if stream isn't explicitly paused + if (this._readableState.flowing !== false) this.resume(); + } else if (ev === 'readable') { + var state = this._readableState; + if (!state.endEmitted && !state.readableListening) { + state.readableListening = state.needReadable = true; + state.emittedReadable = false; + if (!state.reading) { + processNextTick(nReadingNextTick, this); + } else if (state.length) { + emitReadable(this); } - // parser is synchronous - fromRDF(dataset, options, callback); } + } - function fromRDF(dataset, options, callback) { - // convert from RDF - new Processor().fromRDF(dataset, options, callback); - } - }); + return res; }; +Readable.prototype.addListener = Readable.prototype.on; -/** - * Outputs the RDF dataset found in the given JSON-LD object. - * - * @param input the JSON-LD input. - * @param [options] the options to use: - * [base] the base IRI to use. - * [expandContext] a context to expand with. - * [format] the format to use to output a string: - * 'application/nquads' for N-Quads. - * [produceGeneralizedRdf] true to output generalized RDF, false - * to produce only standard RDF (default: false). - * [documentLoader(url, callback(err, remoteDoc))] the document loader. - * @param callback(err, dataset) called once the operation completes. - */ -jsonld.toRDF = function(input, options, callback) { - if(arguments.length < 1) { - return jsonld.nextTick(function() { - callback(new TypeError('Could not convert to RDF, too few arguments.')); - }); - } +function nReadingNextTick(self) { + debug('readable nexttick read 0'); + self.read(0); +} - // get arguments - if(typeof options === 'function') { - callback = options; - options = {}; +// pause() and resume() are remnants of the legacy readable stream API +// If the user uses them, then switch into old mode. +Readable.prototype.resume = function () { + var state = this._readableState; + if (!state.flowing) { + debug('resume'); + state.flowing = true; + resume(this, state); } - options = options || {}; + return this; +}; - // set default options - if(!('base' in options)) { - options.base = (typeof input === 'string') ? input : ''; - } - if(!('documentLoader' in options)) { - options.documentLoader = jsonld.loadDocument; +function resume(stream, state) { + if (!state.resumeScheduled) { + state.resumeScheduled = true; + processNextTick(resume_, stream, state); } +} - // expand input - jsonld.expand(input, options, function(err, expanded) { - if(err) { - return callback(new JsonLdError( - 'Could not expand input before serialization to RDF.', - 'jsonld.RdfError', {cause: err})); - } +function resume_(stream, state) { + if (!state.reading) { + debug('resume read 0'); + stream.read(0); + } - var dataset; - try { - // output RDF dataset - dataset = Processor.prototype.toRDF(expanded, options); - if(options.format) { - if(options.format === 'application/nquads') { - return callback(null, _toNQuads(dataset)); - } - throw new JsonLdError( - 'Unknown output format.', - 'jsonld.UnknownFormat', {format: options.format}); - } - } catch(ex) { - return callback(ex); - } - callback(null, dataset); - }); -}; + state.resumeScheduled = false; + state.awaitDrain = 0; + stream.emit('resume'); + flow(stream); + if (state.flowing && !state.reading) stream.read(0); +} -/** - * **Experimental** - * - * Recursively flattens the nodes in the given JSON-LD input into a map of - * node ID => node. - * - * @param input the JSON-LD input. - * @param [options] the options to use: - * [base] the base IRI to use. - * [expandContext] a context to expand with. - * [issuer] a jsonld.IdentifierIssuer to use to label blank nodes. - * [namer] (deprecated) - * [documentLoader(url, callback(err, remoteDoc))] the document loader. - * @param callback(err, nodeMap) called once the operation completes. - */ -jsonld.createNodeMap = function(input, options, callback) { - if(arguments.length < 1) { - return jsonld.nextTick(function() { - callback(new TypeError('Could not create node map, too few arguments.')); - }); +Readable.prototype.pause = function () { + debug('call pause flowing=%j', this._readableState.flowing); + if (false !== this._readableState.flowing) { + debug('pause'); + this._readableState.flowing = false; + this.emit('pause'); } + return this; +}; - // get arguments - if(typeof options === 'function') { - callback = options; - options = {}; - } - options = options || {}; +function flow(stream) { + var state = stream._readableState; + debug('flow', state.flowing); + while (state.flowing && stream.read() !== null) {} +} - // set default options - if(!('base' in options)) { - options.base = (typeof input === 'string') ? input : ''; - } - if(!('documentLoader' in options)) { - options.documentLoader = jsonld.loadDocument; - } +// wrap an old-style stream as the async data source. +// This is *not* part of the readable stream interface. +// It is an ugly unfortunate mess of history. +Readable.prototype.wrap = function (stream) { + var state = this._readableState; + var paused = false; - // expand input - jsonld.expand(input, options, function(err, _input) { - if(err) { - return callback(new JsonLdError( - 'Could not expand input before creating node map.', - 'jsonld.CreateNodeMapError', {cause: err})); + var self = this; + stream.on('end', function () { + debug('wrapped end'); + if (state.decoder && !state.ended) { + var chunk = state.decoder.end(); + if (chunk && chunk.length) self.push(chunk); } - var nodeMap; - try { - nodeMap = new Processor().createNodeMap(_input, options); - } catch(ex) { - return callback(ex); - } + self.push(null); + }); - callback(null, nodeMap); + stream.on('data', function (chunk) { + debug('wrapped data'); + if (state.decoder) chunk = state.decoder.write(chunk); + + // don't skip over falsy values in objectMode + if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return; + + var ret = self.push(chunk); + if (!ret) { + paused = true; + stream.pause(); + } }); -}; -/** - * **Experimental** - * - * Merges two or more JSON-LD documents into a single flattened document. - * - * @param docs the JSON-LD documents to merge together. - * @param ctx the context to use to compact the merged result, or null. - * @param [options] the options to use: - * [base] the base IRI to use. - * [expandContext] a context to expand with. - * [issuer] a jsonld.IdentifierIssuer to use to label blank nodes. - * [namer] (deprecated). - * [mergeNodes] true to merge properties for nodes with the same ID, - * false to ignore new properties for nodes with the same ID once - * the ID has been defined; note that this may not prevent merging - * new properties where a node is in the `object` position - * (default: true). - * [documentLoader(url, callback(err, remoteDoc))] the document loader. - * @param callback(err, merged) called once the operation completes. - */ -jsonld.merge = function(docs, ctx, options, callback) { - if(arguments.length < 1) { - return jsonld.nextTick(function() { - callback(new TypeError('Could not merge, too few arguments.')); - }); - } - if(!_isArray(docs)) { - return jsonld.nextTick(function() { - callback(new TypeError('Could not merge, "docs" must be an array.')); - }); + // proxy all the other methods. + // important when wrapping filters and duplexes. + for (var i in stream) { + if (this[i] === undefined && typeof stream[i] === 'function') { + this[i] = function (method) { + return function () { + return stream[method].apply(stream, arguments); + }; + }(i); + } } - // get arguments - if(typeof options === 'function') { - callback = options; - options = {}; - } else if(typeof ctx === 'function') { - callback = ctx; - ctx = null; - options = {}; + // proxy certain important events. + for (var n = 0; n < kProxyEvents.length; n++) { + stream.on(kProxyEvents[n], self.emit.bind(self, kProxyEvents[n])); } - options = options || {}; - // expand all documents - var expanded = []; - var error = null; - var count = docs.length; - for(var i = 0; i < docs.length; ++i) { - var opts = {}; - for(var key in options) { - opts[key] = options[key]; + // when we try to consume some more bytes, simply unpause the + // underlying stream. + self._read = function (n) { + debug('wrapped _read', n); + if (paused) { + paused = false; + stream.resume(); } - jsonld.expand(docs[i], opts, expandComplete); - } + }; - function expandComplete(err, _input) { - if(error) { - return; - } - if(err) { - error = err; - return callback(new JsonLdError( - 'Could not expand input before flattening.', - 'jsonld.FlattenError', {cause: err})); - } - expanded.push(_input); - if(--count === 0) { - merge(expanded); - } - } + return self; +}; - function merge(expanded) { - var mergeNodes = true; - if('mergeNodes' in options) { - mergeNodes = options.mergeNodes; - } +// exposed for testing purposes only. +Readable._fromList = fromList; - var issuer = options.namer || options.issuer || new IdentifierIssuer('_:b'); - var graphs = {'@default': {}}; +// Pluck off n bytes from an array of buffers. +// Length is the combined lengths of all the buffers in the list. +// This function is designed to be inlinable, so please take care when making +// changes to the function body. +function fromList(n, state) { + // nothing buffered + if (state.length === 0) return null; - var defaultGraph; - try { - for(var i = 0; i < expanded.length; ++i) { - // uniquely relabel blank nodes - var doc = expanded[i]; - doc = jsonld.relabelBlankNodes(doc, { - issuer: new IdentifierIssuer('_:b' + i + '-') - }); + var ret; + if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) { + // read it all, truncate the list + if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length); + state.buffer.clear(); + } else { + // read part of list + ret = fromListPartial(n, state.buffer, state.decoder); + } - // add nodes to the shared node map graphs if merging nodes, to a - // separate graph set if not - var _graphs = (mergeNodes || i === 0) ? graphs : {'@default': {}}; - _createNodeMap(doc, _graphs, '@default', issuer); + return ret; +} - if(_graphs !== graphs) { - // merge document graphs but don't merge existing nodes - for(var graphName in _graphs) { - var _nodeMap = _graphs[graphName]; - if(!(graphName in graphs)) { - graphs[graphName] = _nodeMap; - continue; - } - var nodeMap = graphs[graphName]; - for(var key in _nodeMap) { - if(!(key in nodeMap)) { - nodeMap[key] = _nodeMap[key]; - } - } - } - } - } +// Extracts only enough buffered data to satisfy the amount requested. +// This function is designed to be inlinable, so please take care when making +// changes to the function body. +function fromListPartial(n, list, hasStrings) { + var ret; + if (n < list.head.data.length) { + // slice is the same for buffers and strings + ret = list.head.data.slice(0, n); + list.head.data = list.head.data.slice(n); + } else if (n === list.head.data.length) { + // first chunk is a perfect match + ret = list.shift(); + } else { + // result spans more than one buffer + ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list); + } + return ret; +} - // add all non-default graphs to default graph - defaultGraph = _mergeNodeMaps(graphs); - } catch(ex) { - return callback(ex); +// Copies a specified amount of characters from the list of buffered data +// chunks. +// This function is designed to be inlinable, so please take care when making +// changes to the function body. +function copyFromBufferString(n, list) { + var p = list.head; + var c = 1; + var ret = p.data; + n -= ret.length; + while (p = p.next) { + var str = p.data; + var nb = n > str.length ? str.length : n; + if (nb === str.length) ret += str;else ret += str.slice(0, n); + n -= nb; + if (n === 0) { + if (nb === str.length) { + ++c; + if (p.next) list.head = p.next;else list.head = list.tail = null; + } else { + list.head = p; + p.data = str.slice(nb); + } + break; } + ++c; + } + list.length -= c; + return ret; +} - // produce flattened output - var flattened = []; - var keys = Object.keys(defaultGraph).sort(); - for(var ki = 0; ki < keys.length; ++ki) { - var node = defaultGraph[keys[ki]]; - // only add full subjects to top-level - if(!_isSubjectReference(node)) { - flattened.push(node); +// Copies a specified amount of bytes from the list of buffered data chunks. +// This function is designed to be inlinable, so please take care when making +// changes to the function body. +function copyFromBuffer(n, list) { + var ret = Buffer.allocUnsafe(n); + var p = list.head; + var c = 1; + p.data.copy(ret); + n -= p.data.length; + while (p = p.next) { + var buf = p.data; + var nb = n > buf.length ? buf.length : n; + buf.copy(ret, ret.length - n, 0, nb); + n -= nb; + if (n === 0) { + if (nb === buf.length) { + ++c; + if (p.next) list.head = p.next;else list.head = list.tail = null; + } else { + list.head = p; + p.data = buf.slice(nb); } + break; } + ++c; + } + list.length -= c; + return ret; +} - if(ctx === null) { - return callback(null, flattened); - } +function endReadable(stream) { + var state = stream._readableState; - // compact result (force @graph option to true, skip expansion) - options.graph = true; - options.skipExpansion = true; - jsonld.compact(flattened, ctx, options, function(err, compacted) { - if(err) { - return callback(new JsonLdError( - 'Could not compact merged output.', - 'jsonld.MergeError', {cause: err})); - } - callback(null, compacted); - }); - } -}; + // If we get here before consuming all the bytes, then that is a + // bug in node. Should never happen. + if (state.length > 0) throw new Error('"endReadable()" called on non-empty stream'); -/** - * Relabels all blank nodes in the given JSON-LD input. - * - * @param input the JSON-LD input. - * @param [options] the options to use: - * [issuer] a jsonld.IdentifierIssuer to use to label blank nodes. - * [namer] (deprecated). - */ -jsonld.relabelBlankNodes = function(input, options) { - options = options || {}; - var issuer = options.namer || options.issuer || new IdentifierIssuer('_:b'); - return _labelBlankNodes(issuer, input); -}; + if (!state.endEmitted) { + state.ended = true; + processNextTick(endReadableNT, state, stream); + } +} -/** - * Prepends a base IRI to the given relative IRI. - * - * @param base the base IRI. - * @param iri the relative IRI. - * - * @return the absolute IRI. - */ -jsonld.prependBase = function(base, iri) { - return _prependBase(base, iri); -}; +function endReadableNT(state, stream) { + // Check that we didn't get one last unshift. + if (!state.endEmitted && state.length === 0) { + state.endEmitted = true; + stream.readable = false; + stream.emit('end'); + } +} -/** - * The default document loader for external documents. If the environment - * is node.js, a callback-continuation-style document loader is used; otherwise, - * a promises-style document loader is used. - * - * @param url the URL to load. - * @param callback(err, remoteDoc) called once the operation completes, - * if using a non-promises API. - * - * @return a promise, if using a promises API. - */ -jsonld.documentLoader = function(url, callback) { - var err = new JsonLdError( - 'Could not retrieve a JSON-LD document from the URL. URL ' + - 'dereferencing not implemented.', 'jsonld.LoadDocumentError', - {code: 'loading document failed'}); - if(_nodejs) { - return callback(err, {contextUrl: null, documentUrl: url, document: null}); +function forEach(xs, f) { + for (var i = 0, l = xs.length; i < l; i++) { + f(xs[i], i); } - return jsonld.promisify(function(callback) { - callback(err); - }); -}; +} -/** - * Deprecated default document loader. Use or override jsonld.documentLoader - * instead. - */ -jsonld.loadDocument = function(url, callback) { - var promise = jsonld.documentLoader(url, callback); - if(promise && 'then' in promise) { - promise.then(callback.bind(null, null), callback); +function indexOf(xs, x) { + for (var i = 0, l = xs.length; i < l; i++) { + if (xs[i] === x) return i; } -}; + return -1; +} +}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -/* Promises API */ +},{"./_stream_duplex":18,"./internal/streams/BufferList":23,"./internal/streams/destroy":24,"./internal/streams/stream":25,"_process":12,"core-util-is":26,"events":8,"inherits":10,"isarray":27,"process-nextick-args":28,"safe-buffer":29,"string_decoder/":30,"util":3}],21:[function(_dereq_,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. -/** - * Creates a new promises API object. - * - * @param [options] the options to use: - * [api] an object to attach the API to. - * [version] 'json-ld-1.0' to output a standard JSON-LD 1.0 promises - * API, 'jsonld.js' to output the same with augmented proprietary - * methods (default: 'jsonld.js') - * - * @return the promises API object. - */ -jsonld.promises = function(options) { - options = options || {}; - var slice = Array.prototype.slice; - var promisify = jsonld.promisify; +// a transform stream is a readable/writable stream where you do +// something with the data. Sometimes it's called a "filter", +// but that's not a great name for it, since that implies a thing where +// some bits pass through, and others are simply ignored. (That would +// be a valid example of a transform, of course.) +// +// While the output is causally related to the input, it's not a +// necessarily symmetric or synchronous transformation. For example, +// a zlib stream might take multiple plain-text writes(), and then +// emit a single compressed chunk some time in the future. +// +// Here's how this works: +// +// The Transform stream has all the aspects of the readable and writable +// stream classes. When you write(chunk), that calls _write(chunk,cb) +// internally, and returns false if there's a lot of pending writes +// buffered up. When you call read(), that calls _read(n) until +// there's enough pending readable data buffered up. +// +// In a transform stream, the written data is placed in a buffer. When +// _read(n) is called, it transforms the queued up data, calling the +// buffered _write cb's as it consumes chunks. If consuming a single +// written chunk would result in multiple output chunks, then the first +// outputted bit calls the readcb, and subsequent chunks just go into +// the read buffer, and will cause it to emit 'readable' if necessary. +// +// This way, back-pressure is actually determined by the reading side, +// since _read has to be called to start processing a new chunk. However, +// a pathological inflate type of transform can cause excessive buffering +// here. For example, imagine a stream where every byte of input is +// interpreted as an integer from 0-255, and then results in that many +// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in +// 1kb of data being output. In this case, you could write a very small +// amount of input, and end up with a very large amount of output. In +// such a pathological inflating mechanism, there'd be no way to tell +// the system to stop doing the transform. A single 4MB write could +// cause the system to run out of memory. +// +// However, even in such a pathological case, only a single written chunk +// would be consumed, and then the rest would wait (un-transformed) until +// the results of the previous transformed chunk were consumed. - // handle 'api' option as version, set defaults - var api = options.api || {}; - var version = options.version || 'jsonld.js'; - if(typeof options.api === 'string') { - if(!options.version) { - version = options.api; - } - api = {}; - } +'use strict'; - // The Web IDL test harness will check the number of parameters defined in - // the functions below. The number of parameters must exactly match the - // required (non-optional) parameters of the JsonLdProcessor interface as - // defined here: - // https://www.w3.org/TR/json-ld-api/#the-jsonldprocessor-interface +module.exports = Transform; - api.expand = function(input) { - if(arguments.length < 1) { - throw new TypeError('Could not expand, too few arguments.'); - } - return promisify.apply(null, [jsonld.expand].concat(slice.call(arguments))); - }; - api.compact = function(input, ctx) { - if(arguments.length < 2) { - throw new TypeError('Could not compact, too few arguments.'); - } - var compact = function(input, ctx, options, callback) { - if(typeof options === 'function') { - callback = options; - options = {}; - } - options = options || {}; - // ensure only one value is returned in callback - jsonld.compact(input, ctx, options, function(err, compacted) { - callback(err, compacted); - }); - }; - return promisify.apply(null, [compact].concat(slice.call(arguments))); - }; - api.flatten = function(input) { - if(arguments.length < 1) { - throw new TypeError('Could not flatten, too few arguments.'); - } - return promisify.apply( - null, [jsonld.flatten].concat(slice.call(arguments))); - }; - api.frame = function(input, frame) { - if(arguments.length < 2) { - throw new TypeError('Could not frame, too few arguments.'); - } - return promisify.apply(null, [jsonld.frame].concat(slice.call(arguments))); - }; - api.fromRDF = function(dataset) { - if(arguments.length < 1) { - throw new TypeError('Could not convert from RDF, too few arguments.'); - } - return promisify.apply( - null, [jsonld.fromRDF].concat(slice.call(arguments))); - }; - api.toRDF = function(input) { - if(arguments.length < 1) { - throw new TypeError('Could not convert to RDF, too few arguments.'); - } - return promisify.apply(null, [jsonld.toRDF].concat(slice.call(arguments))); - }; - api.normalize = function(input) { - if(arguments.length < 1) { - throw new TypeError('Could not normalize, too few arguments.'); - } - return promisify.apply( - null, [jsonld.normalize].concat(slice.call(arguments))); +var Duplex = _dereq_('./_stream_duplex'); + +/**/ +var util = _dereq_('core-util-is'); +util.inherits = _dereq_('inherits'); +/**/ + +util.inherits(Transform, Duplex); + +function TransformState(stream) { + this.afterTransform = function (er, data) { + return afterTransform(stream, er, data); }; - if(version === 'jsonld.js') { - api.link = function(input, ctx) { - if(arguments.length < 2) { - throw new TypeError('Could not link, too few arguments.'); - } - return promisify.apply( - null, [jsonld.link].concat(slice.call(arguments))); - }; - api.objectify = function(input) { - return promisify.apply( - null, [jsonld.objectify].concat(slice.call(arguments))); - }; - api.createNodeMap = function(input) { - return promisify.apply( - null, [jsonld.createNodeMap].concat(slice.call(arguments))); - }; - api.merge = function(input) { - return promisify.apply( - null, [jsonld.merge].concat(slice.call(arguments))); - }; - } + this.needTransform = false; + this.transforming = false; + this.writecb = null; + this.writechunk = null; + this.writeencoding = null; +} - try { - jsonld.Promise = global.Promise || _dereq_('es6-promise').Promise; - } catch(e) { - var f = function() { - throw new Error('Unable to find a Promise implementation.'); - }; - for(var method in api) { - api[method] = f; - } - } +function afterTransform(stream, er, data) { + var ts = stream._transformState; + ts.transforming = false; - return api; -}; + var cb = ts.writecb; -/** - * Converts a node.js async op into a promise w/boxed resolved value(s). - * - * @param op the operation to convert. - * - * @return the promise. - */ -jsonld.promisify = function(op) { - if(!jsonld.Promise) { - try { - jsonld.Promise = global.Promise || _dereq_('es6-promise').Promise; - } catch(e) { - throw new Error('Unable to find a Promise implementation.'); - } + if (!cb) { + return stream.emit('error', new Error('write callback called multiple times')); } - var args = Array.prototype.slice.call(arguments, 1); - return new jsonld.Promise(function(resolve, reject) { - op.apply(null, args.concat(function(err, value) { - if(!err) { - resolve(value); - } else { - reject(err); - } - })); - }); -}; -// extend jsonld.promises w/jsonld.js methods -jsonld.promises({api: jsonld.promises}); + ts.writechunk = null; + ts.writecb = null; -/* WebIDL API */ + if (data !== null && data !== undefined) stream.push(data); -function JsonLdProcessor() {} -JsonLdProcessor.prototype = jsonld.promises({version: 'json-ld-1.0'}); -JsonLdProcessor.prototype.toString = function() { - if(this instanceof JsonLdProcessor) { - return '[object JsonLdProcessor]'; + cb(er); + + var rs = stream._readableState; + rs.reading = false; + if (rs.needReadable || rs.length < rs.highWaterMark) { + stream._read(rs.highWaterMark); } - return '[object JsonLdProcessorPrototype]'; -}; -jsonld.JsonLdProcessor = JsonLdProcessor; +} -// IE8 has Object.defineProperty but it only -// works on DOM nodes -- so feature detection -// requires try/catch :-( -var canDefineProperty = !!Object.defineProperty; -if(canDefineProperty) { - try { - Object.defineProperty({}, 'x', {}); - } catch(e) { - canDefineProperty = false; - } -} +function Transform(options) { + if (!(this instanceof Transform)) return new Transform(options); -if(canDefineProperty) { - Object.defineProperty(JsonLdProcessor, 'prototype', { - writable: false, - enumerable: false - }); - Object.defineProperty(JsonLdProcessor.prototype, 'constructor', { - writable: true, - enumerable: false, - configurable: true, - value: JsonLdProcessor - }); -} + Duplex.call(this, options); -// setup browser global JsonLdProcessor -if(_browser && typeof global.JsonLdProcessor === 'undefined') { - if(canDefineProperty) { - Object.defineProperty(global, 'JsonLdProcessor', { - writable: true, - enumerable: false, - configurable: true, - value: JsonLdProcessor - }); - } else { - global.JsonLdProcessor = JsonLdProcessor; - } -} + this._transformState = new TransformState(this); -/* Utility API */ + var stream = this; -// define setImmediate and nextTick -//// nextTick implementation with browser-compatible fallback //// -// from https://github.com/caolan/async/blob/master/lib/async.js + // start out asking for a readable event once data is transformed. + this._readableState.needReadable = true; -// capture the global reference to guard against fakeTimer mocks -var _setImmediate = typeof setImmediate === 'function' && setImmediate; + // we have implemented the _read method, and done the other things + // that Readable wants before the first _read call, so unset the + // sync guard flag. + this._readableState.sync = false; -var _delay = _setImmediate ? function(fn) { - // not a direct alias (for IE10 compatibility) - _setImmediate(fn); -} : function(fn) { - setTimeout(fn, 0); -}; + if (options) { + if (typeof options.transform === 'function') this._transform = options.transform; -if(typeof process === 'object' && typeof process.nextTick === 'function') { - jsonld.nextTick = process.nextTick; -} else { - jsonld.nextTick = _delay; + if (typeof options.flush === 'function') this._flush = options.flush; + } + + // When the writable side finishes, then flush out anything remaining. + this.once('prefinish', function () { + if (typeof this._flush === 'function') this._flush(function (er, data) { + done(stream, er, data); + });else done(stream); + }); } -jsonld.setImmediate = _setImmediate ? _delay : jsonld.nextTick; -/** - * Parses a link header. The results will be key'd by the value of "rel". - * - * Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" - * - * Parses as: { - * 'http://www.w3.org/ns/json-ld#context': { - * target: http://json-ld.org/contexts/person.jsonld, - * type: 'application/ld+json' - * } - * } - * - * If there is more than one "rel" with the same IRI, then entries in the - * resulting map for that "rel" will be arrays. - * - * @param header the link header to parse. - */ -jsonld.parseLinkHeader = function(header) { - var rval = {}; - // split on unbracketed/unquoted commas - var entries = header.match(/(?:<[^>]*?>|"[^"]*?"|[^,])+/g); - var rLinkHeader = /\s*<([^>]*?)>\s*(?:;\s*(.*))?/; - for(var i = 0; i < entries.length; ++i) { - var match = entries[i].match(rLinkHeader); - if(!match) { - continue; - } - var result = {target: match[1]}; - var params = match[2]; - var rParams = /(.*?)=(?:(?:"([^"]*?)")|([^"]*?))\s*(?:(?:;\s*)|$)/g; - while(match = rParams.exec(params)) { - result[match[1]] = (match[2] === undefined) ? match[3] : match[2]; - } - var rel = result['rel'] || ''; - if(_isArray(rval[rel])) { - rval[rel].push(result); - } else if(rel in rval) { - rval[rel] = [rval[rel], result]; - } else { - rval[rel] = result; - } - } - return rval; +Transform.prototype.push = function (chunk, encoding) { + this._transformState.needTransform = false; + return Duplex.prototype.push.call(this, chunk, encoding); }; -/** - * Creates a simple queue for requesting documents. - */ -jsonld.RequestQueue = function() { - this._requests = {}; -}; -jsonld.RequestQueue.prototype.wrapLoader = function(loader) { - this._loader = loader; - this._usePromise = (loader.length === 1); - return this.add.bind(this); +// This is the part where you do stuff! +// override this function in implementation classes. +// 'chunk' is an input chunk. +// +// Call `push(newChunk)` to pass along transformed output +// to the readable side. You may call 'push' zero or more times. +// +// Call `cb(err)` when you are done with this chunk. If you pass +// an error, then that'll put the hurt on the whole operation. If you +// never call cb(), then you'll never get another chunk. +Transform.prototype._transform = function (chunk, encoding, cb) { + throw new Error('_transform() is not implemented'); }; -jsonld.RequestQueue.prototype.add = function(url, callback) { - var self = this; - // callback must be given if not using promises - if(!callback && !self._usePromise) { - throw new Error('callback must be specified.'); +Transform.prototype._write = function (chunk, encoding, cb) { + var ts = this._transformState; + ts.writecb = cb; + ts.writechunk = chunk; + ts.writeencoding = encoding; + if (!ts.transforming) { + var rs = this._readableState; + if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark); } +}; - // Promise-based API - if(self._usePromise) { - return new jsonld.Promise(function(resolve, reject) { - var load = self._requests[url]; - if(!load) { - // load URL then remove from queue - load = self._requests[url] = self._loader(url) - .then(function(remoteDoc) { - delete self._requests[url]; - return remoteDoc; - }).catch(function(err) { - delete self._requests[url]; - throw err; - }); - } - // resolve/reject promise once URL has been loaded - load.then(function(remoteDoc) { - resolve(remoteDoc); - }).catch(function(err) { - reject(err); - }); - }); - } +// Doesn't matter what the args are here. +// _transform does all the work. +// That we got here means that the readable side wants more data. +Transform.prototype._read = function (n) { + var ts = this._transformState; - // callback-based API - if(url in self._requests) { - self._requests[url].push(callback); + if (ts.writechunk !== null && ts.writecb && !ts.transforming) { + ts.transforming = true; + this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); } else { - self._requests[url] = [callback]; - self._loader(url, function(err, remoteDoc) { - var callbacks = self._requests[url]; - delete self._requests[url]; - for(var i = 0; i < callbacks.length; ++i) { - callbacks[i](err, remoteDoc); - } - }); + // mark that we need a transform, so that any data that comes in + // will get processed, now that we've asked for it. + ts.needTransform = true; } }; -/** - * Creates a simple document cache that retains documents for a short - * period of time. - * - * FIXME: Implement simple HTTP caching instead. - * - * @param size the maximum size of the cache. - */ -jsonld.DocumentCache = function(size) { - this.order = []; - this.cache = {}; - this.size = size || 50; - this.expires = 30 * 1000; -}; -jsonld.DocumentCache.prototype.get = function(url) { - if(url in this.cache) { - var entry = this.cache[url]; - if(entry.expires >= +new Date()) { - return entry.ctx; - } - delete this.cache[url]; - this.order.splice(this.order.indexOf(url), 1); - } - return null; -}; -jsonld.DocumentCache.prototype.set = function(url, ctx) { - if(this.order.length === this.size) { - delete this.cache[this.order.shift()]; - } - this.order.push(url); - this.cache[url] = {ctx: ctx, expires: (+new Date() + this.expires)}; -}; +Transform.prototype._destroy = function (err, cb) { + var _this = this; -/** - * Creates an active context cache. - * - * @param size the maximum size of the cache. - */ -jsonld.ActiveContextCache = function(size) { - this.order = []; - this.cache = {}; - this.size = size || 100; -}; -jsonld.ActiveContextCache.prototype.get = function(activeCtx, localCtx) { - var key1 = JSON.stringify(activeCtx); - var key2 = JSON.stringify(localCtx); - var level1 = this.cache[key1]; - if(level1 && key2 in level1) { - return level1[key2]; - } - return null; -}; -jsonld.ActiveContextCache.prototype.set = function( - activeCtx, localCtx, result) { - if(this.order.length === this.size) { - var entry = this.order.shift(); - delete this.cache[entry.activeCtx][entry.localCtx]; - } - var key1 = JSON.stringify(activeCtx); - var key2 = JSON.stringify(localCtx); - this.order.push({activeCtx: key1, localCtx: key2}); - if(!(key1 in this.cache)) { - this.cache[key1] = {}; - } - this.cache[key1][key2] = _clone(result); + Duplex.prototype._destroy.call(this, err, function (err2) { + cb(err2); + _this.emit('close'); + }); }; -/** - * Default JSON-LD cache. - */ -jsonld.cache = { - activeCtx: new jsonld.ActiveContextCache() -}; +function done(stream, er, data) { + if (er) return stream.emit('error', er); -/** - * Document loaders. - */ -jsonld.documentLoaders = {}; + if (data !== null && data !== undefined) stream.push(data); -/** - * Creates a built-in jquery document loader. - * - * @param $ the jquery instance to use. - * @param options the options to use: - * secure: require all URLs to use HTTPS. - * usePromise: true to use a promises API, false for a - * callback-continuation-style API; defaults to true if Promise - * is globally defined, false if not. - * - * @return the jquery document loader. - */ -jsonld.documentLoaders.jquery = function($, options) { - options = options || {}; - var queue = new jsonld.RequestQueue(); + // if there's nothing in the write buffer, then that means + // that nothing more will ever be provided + var ws = stream._writableState; + var ts = stream._transformState; - // use option or, by default, use Promise when its defined - var usePromise = ('usePromise' in options ? - options.usePromise : (typeof Promise !== 'undefined')); - if(usePromise) { - return queue.wrapLoader(function(url) { - return jsonld.promisify(loader, url); - }); - } - return queue.wrapLoader(loader); + if (ws.length) throw new Error('Calling transform done when ws.length != 0'); - function loader(url, callback) { - if(url.indexOf('http:') !== 0 && url.indexOf('https:') !== 0) { - return callback(new JsonLdError( - 'URL could not be dereferenced; only "http" and "https" URLs are ' + - 'supported.', - 'jsonld.InvalidUrl', {code: 'loading document failed', url: url}), - {contextUrl: null, documentUrl: url, document: null}); - } - if(options.secure && url.indexOf('https') !== 0) { - return callback(new JsonLdError( - 'URL could not be dereferenced; secure mode is enabled and ' + - 'the URL\'s scheme is not "https".', - 'jsonld.InvalidUrl', {code: 'loading document failed', url: url}), - {contextUrl: null, documentUrl: url, document: null}); - } - $.ajax({ - url: url, - accepts: { - json: 'application/ld+json, application/json' - }, - // ensure Accept header is very specific for JSON-LD/JSON - headers: { - 'Accept': 'application/ld+json, application/json' - }, - dataType: 'json', - crossDomain: true, - success: function(data, textStatus, jqXHR) { - var doc = {contextUrl: null, documentUrl: url, document: data}; + if (ts.transforming) throw new Error('Calling transform done when still transforming'); - // handle Link Header - var contentType = jqXHR.getResponseHeader('Content-Type'); - var linkHeader = jqXHR.getResponseHeader('Link'); - if(linkHeader && contentType !== 'application/ld+json') { - // only 1 related link header permitted - linkHeader = jsonld.parseLinkHeader(linkHeader)[LINK_HEADER_REL]; - if(_isArray(linkHeader)) { - return callback(new JsonLdError( - 'URL could not be dereferenced, it has more than one ' + - 'associated HTTP Link Header.', - 'jsonld.InvalidUrl', - {code: 'multiple context link headers', url: url}), doc); - } - if(linkHeader) { - doc.contextUrl = linkHeader.target; - } - } + return stream.push(null); +} +},{"./_stream_duplex":18,"core-util-is":26,"inherits":10}],22:[function(_dereq_,module,exports){ +(function (process,global){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. - callback(null, doc); - }, - error: function(jqXHR, textStatus, err) { - callback(new JsonLdError( - 'URL could not be dereferenced, an error occurred.', - 'jsonld.LoadDocumentError', - {code: 'loading document failed', url: url, cause: err}), - {contextUrl: null, documentUrl: url, document: null}); - } - }); - } -}; +// A bit simpler than readable streams. +// Implement an async ._write(chunk, encoding, cb), and it'll handle all +// the drain event emission and buffering. -/** - * Creates a built-in node document loader. - * - * @param options the options to use: - * secure: require all URLs to use HTTPS. - * strictSSL: true to require SSL certificates to be valid, - * false not to (default: true). - * maxRedirects: the maximum number of redirects to permit, none by - * default. - * request: the object which will make the request, default is - * provided by `https://www.npmjs.com/package/request`. - * headers: an array of headers which will be passed as request - * headers for the requested document. Accept is not allowed. - * usePromise: true to use a promises API, false for a - * callback-continuation-style API; false by default. - * - * @return the node document loader. - */ -jsonld.documentLoaders.node = function(options) { - options = options || {}; - var strictSSL = ('strictSSL' in options) ? options.strictSSL : true; - var maxRedirects = ('maxRedirects' in options) ? options.maxRedirects : -1; - var request = ('request' in options) ? options.request : _dereq_('request'); - var acceptHeader = 'application/ld+json, application/json'; - var http = _dereq_('http'); - // TODO: disable cache until HTTP caching implemented - //var cache = new jsonld.DocumentCache(); +'use strict'; - var queue = new jsonld.RequestQueue(); - if(options.usePromise) { - return queue.wrapLoader(function(url) { - return jsonld.promisify(loadDocument, url, []); - }); - } - var headers = options.headers || {}; - if('Accept' in headers || 'accept' in headers) { - throw new RangeError( - 'Accept header may not be specified as an option; only "' + - acceptHeader + '" is supported.'); - } - return queue.wrapLoader(function(url, callback) { - loadDocument(url, [], callback); - }); +/**/ - function loadDocument(url, redirects, callback) { - if(url.indexOf('http:') !== 0 && url.indexOf('https:') !== 0) { - return callback(new JsonLdError( - 'URL could not be dereferenced; only "http" and "https" URLs are ' + - 'supported.', - 'jsonld.InvalidUrl', {code: 'loading document failed', url: url}), - {contextUrl: null, documentUrl: url, document: null}); - } - if(options.secure && url.indexOf('https') !== 0) { - return callback(new JsonLdError( - 'URL could not be dereferenced; secure mode is enabled and ' + - 'the URL\'s scheme is not "https".', - 'jsonld.InvalidUrl', {code: 'loading document failed', url: url}), - {contextUrl: null, documentUrl: url, document: null}); - } - // TODO: disable cache until HTTP caching implemented - var doc = null;//cache.get(url); - if(doc !== null) { - return callback(null, doc); - } - var headers = {'Accept': acceptHeader}; - for(var k in options.headers) { headers[k] = options.headers[k]; } - request({ - url: url, - headers: headers, - strictSSL: strictSSL, - followRedirect: false - }, handleResponse); +var processNextTick = _dereq_('process-nextick-args'); +/**/ - function handleResponse(err, res, body) { - doc = {contextUrl: null, documentUrl: url, document: body || null}; +module.exports = Writable; - // handle error - if(err) { - return callback(new JsonLdError( - 'URL could not be dereferenced, an error occurred.', - 'jsonld.LoadDocumentError', - {code: 'loading document failed', url: url, cause: err}), doc); - } - var statusText = http.STATUS_CODES[res.statusCode]; - if(res.statusCode >= 400) { - return callback(new JsonLdError( - 'URL could not be dereferenced: ' + statusText, - 'jsonld.InvalidUrl', { - code: 'loading document failed', - url: url, - httpStatusCode: res.statusCode - }), doc); - } +/* */ +function WriteReq(chunk, encoding, cb) { + this.chunk = chunk; + this.encoding = encoding; + this.callback = cb; + this.next = null; +} - // handle Link Header - if(res.headers.link && - res.headers['content-type'] !== 'application/ld+json') { - // only 1 related link header permitted - var linkHeader = jsonld.parseLinkHeader( - res.headers.link)[LINK_HEADER_REL]; - if(_isArray(linkHeader)) { - return callback(new JsonLdError( - 'URL could not be dereferenced, it has more than one associated ' + - 'HTTP Link Header.', - 'jsonld.InvalidUrl', - {code: 'multiple context link headers', url: url}), doc); - } - if(linkHeader) { - doc.contextUrl = linkHeader.target; - } - } - - // handle redirect - if(res.statusCode >= 300 && res.statusCode < 400 && - res.headers.location) { - if(redirects.length === maxRedirects) { - return callback(new JsonLdError( - 'URL could not be dereferenced; there were too many redirects.', - 'jsonld.TooManyRedirects', { - code: 'loading document failed', - url: url, - httpStatusCode: res.statusCode, - redirects: redirects - }), doc); - } - if(redirects.indexOf(url) !== -1) { - return callback(new JsonLdError( - 'URL could not be dereferenced; infinite redirection was detected.', - 'jsonld.InfiniteRedirectDetected', { - code: 'recursive context inclusion', - url: url, - httpStatusCode: res.statusCode, - redirects: redirects - }), doc); - } - redirects.push(url); - return loadDocument(res.headers.location, redirects, callback); - } - // cache for each redirected URL - redirects.push(url); - // TODO: disable cache until HTTP caching implemented - /*for(var i = 0; i < redirects.length; ++i) { - cache.set( - redirects[i], - {contextUrl: null, documentUrl: redirects[i], document: body}); - }*/ - callback(err, doc); - } - } -}; - -/** - * Creates a built-in XMLHttpRequest document loader. - * - * @param options the options to use: - * secure: require all URLs to use HTTPS. - * usePromise: true to use a promises API, false for a - * callback-continuation-style API; defaults to true if Promise - * is globally defined, false if not. - * [xhr]: the XMLHttpRequest API to use. - * - * @return the XMLHttpRequest document loader. - */ -jsonld.documentLoaders.xhr = function(options) { - options = options || {}; - var rlink = /(^|(\r\n))link:/i; - var queue = new jsonld.RequestQueue(); - - // use option or, by default, use Promise when its defined - var usePromise = ('usePromise' in options ? - options.usePromise : (typeof Promise !== 'undefined')); - if(usePromise) { - return queue.wrapLoader(function(url) { - return jsonld.promisify(loader, url); - }); - } - return queue.wrapLoader(loader); +// It seems a linked list but it is not +// there will be only 2 of these for each stream +function CorkedRequest(state) { + var _this = this; - function loader(url, callback) { - if(url.indexOf('http:') !== 0 && url.indexOf('https:') !== 0) { - return callback(new JsonLdError( - 'URL could not be dereferenced; only "http" and "https" URLs are ' + - 'supported.', - 'jsonld.InvalidUrl', {code: 'loading document failed', url: url}), - {contextUrl: null, documentUrl: url, document: null}); - } - if(options.secure && url.indexOf('https') !== 0) { - return callback(new JsonLdError( - 'URL could not be dereferenced; secure mode is enabled and ' + - 'the URL\'s scheme is not "https".', - 'jsonld.InvalidUrl', {code: 'loading document failed', url: url}), - {contextUrl: null, documentUrl: url, document: null}); - } - var xhr = options.xhr || XMLHttpRequest; - var req = new xhr(); - req.onload = function() { - if(req.status >= 400) { - return callback(new JsonLdError( - 'URL could not be dereferenced: ' + req.statusText, - 'jsonld.LoadDocumentError', { - code: 'loading document failed', - url: url, - httpStatusCode: req.status - }), {contextUrl: null, documentUrl: url, document: null}); - } + this.next = null; + this.entry = null; + this.finish = function () { + onCorkedFinish(_this, state); + }; +} +/* */ - var doc = {contextUrl: null, documentUrl: url, document: req.response}; +/**/ +var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick; +/**/ - // handle Link Header (avoid unsafe header warning by existence testing) - var contentType = req.getResponseHeader('Content-Type'); - var linkHeader; - if(rlink.test(req.getAllResponseHeaders())) { - linkHeader = req.getResponseHeader('Link'); - } - if(linkHeader && contentType !== 'application/ld+json') { - // only 1 related link header permitted - linkHeader = jsonld.parseLinkHeader(linkHeader)[LINK_HEADER_REL]; - if(_isArray(linkHeader)) { - return callback(new JsonLdError( - 'URL could not be dereferenced, it has more than one ' + - 'associated HTTP Link Header.', - 'jsonld.InvalidUrl', - {code: 'multiple context link headers', url: url}), doc); - } - if(linkHeader) { - doc.contextUrl = linkHeader.target; - } - } +/**/ +var Duplex; +/**/ - callback(null, doc); - }; - req.onerror = function() { - callback(new JsonLdError( - 'URL could not be dereferenced, an error occurred.', - 'jsonld.LoadDocumentError', - {code: 'loading document failed', url: url}), - {contextUrl: null, documentUrl: url, document: null}); - }; - req.open('GET', url, true); - req.setRequestHeader('Accept', 'application/ld+json, application/json'); - req.send(); - } -}; +Writable.WritableState = WritableState; -/** - * Assigns the default document loader for external document URLs to a built-in - * default. Supported types currently include: 'jquery' and 'node'. - * - * To use the jquery document loader, the first parameter must be a reference - * to the main jquery object. - * - * @param type the type to set. - * @param [params] the parameters required to use the document loader. - */ -jsonld.useDocumentLoader = function(type) { - if(!(type in jsonld.documentLoaders)) { - throw new JsonLdError( - 'Unknown document loader type: "' + type + '"', - 'jsonld.UnknownDocumentLoader', - {type: type}); - } +/**/ +var util = _dereq_('core-util-is'); +util.inherits = _dereq_('inherits'); +/**/ - // set document loader - jsonld.documentLoader = jsonld.documentLoaders[type].apply( - jsonld, Array.prototype.slice.call(arguments, 1)); +/**/ +var internalUtil = { + deprecate: _dereq_('util-deprecate') }; +/**/ -/** - * Processes a local context, resolving any URLs as necessary, and returns a - * new active context in its callback. - * - * @param activeCtx the current active context. - * @param localCtx the local context to process. - * @param [options] the options to use: - * [documentLoader(url, callback(err, remoteDoc))] the document loader. - * @param callback(err, ctx) called once the operation completes. - */ -jsonld.processContext = function(activeCtx, localCtx) { - // get arguments - var options = {}; - var callbackArg = 2; - if(arguments.length > 3) { - options = arguments[2] || {}; - callbackArg += 1; - } - var callback = arguments[callbackArg]; +/**/ +var Stream = _dereq_('./internal/streams/stream'); +/**/ - // set default options - if(!('base' in options)) { - options.base = ''; - } - if(!('documentLoader' in options)) { - options.documentLoader = jsonld.loadDocument; - } +/**/ +var Buffer = _dereq_('safe-buffer').Buffer; +var OurUint8Array = global.Uint8Array || function () {}; +function _uint8ArrayToBuffer(chunk) { + return Buffer.from(chunk); +} +function _isUint8Array(obj) { + return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; +} +/**/ - // return initial context early for null context - if(localCtx === null) { - return callback(null, _getInitialContext(options)); - } +var destroyImpl = _dereq_('./internal/streams/destroy'); - // retrieve URLs in localCtx - localCtx = _clone(localCtx); - if(!(_isObject(localCtx) && '@context' in localCtx)) { - localCtx = {'@context': localCtx}; - } - _retrieveContextUrls(localCtx, options, function(err, ctx) { - if(err) { - return callback(err); - } - try { - // process context - ctx = new Processor().processContext(activeCtx, ctx, options); - } catch(ex) { - return callback(ex); - } - callback(null, ctx); - }); -}; +util.inherits(Writable, Stream); -/** - * Returns true if the given subject has the given property. - * - * @param subject the subject to check. - * @param property the property to look for. - * - * @return true if the subject has the given property, false if not. - */ -jsonld.hasProperty = function(subject, property) { - var rval = false; - if(property in subject) { - var value = subject[property]; - rval = (!_isArray(value) || value.length > 0); - } - return rval; -}; +function nop() {} -/** - * Determines if the given value is a property of the given subject. - * - * @param subject the subject to check. - * @param property the property to check. - * @param value the value to check. - * - * @return true if the value exists, false if not. - */ -jsonld.hasValue = function(subject, property, value) { - var rval = false; - if(jsonld.hasProperty(subject, property)) { - var val = subject[property]; - var isList = _isList(val); - if(_isArray(val) || isList) { - if(isList) { - val = val['@list']; - } - for(var i = 0; i < val.length; ++i) { - if(jsonld.compareValues(value, val[i])) { - rval = true; - break; - } - } - } else if(!_isArray(value)) { - // avoid matching the set of values with an array value parameter - rval = jsonld.compareValues(value, val); - } - } - return rval; -}; +function WritableState(options, stream) { + Duplex = Duplex || _dereq_('./_stream_duplex'); -/** - * Adds a value to a subject. If the value is an array, all values in the - * array will be added. - * - * @param subject the subject to add the value to. - * @param property the property that relates the value to the subject. - * @param value the value to add. - * @param [options] the options to use: - * [propertyIsArray] true if the property is always an array, false - * if not (default: false). - * [allowDuplicate] true to allow duplicates, false not to (uses a - * simple shallow comparison of subject ID or value) (default: true). - */ -jsonld.addValue = function(subject, property, value, options) { options = options || {}; - if(!('propertyIsArray' in options)) { - options.propertyIsArray = false; - } - if(!('allowDuplicate' in options)) { - options.allowDuplicate = true; - } - - if(_isArray(value)) { - if(value.length === 0 && options.propertyIsArray && - !(property in subject)) { - subject[property] = []; - } - for(var i = 0; i < value.length; ++i) { - jsonld.addValue(subject, property, value[i], options); - } - } else if(property in subject) { - // check if subject already has value if duplicates not allowed - var hasValue = (!options.allowDuplicate && - jsonld.hasValue(subject, property, value)); - // make property an array if value not present or always an array - if(!_isArray(subject[property]) && - (!hasValue || options.propertyIsArray)) { - subject[property] = [subject[property]]; - } + // object stream flag to indicate whether or not this stream + // contains buffers or objects. + this.objectMode = !!options.objectMode; - // add new value - if(!hasValue) { - subject[property].push(value); - } - } else { - // add new value as set or single value - subject[property] = options.propertyIsArray ? [value] : value; - } -}; + if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode; -/** - * Gets all of the values for a subject's property as an array. - * - * @param subject the subject. - * @param property the property. - * - * @return all of the values for a subject's property as an array. - */ -jsonld.getValues = function(subject, property) { - var rval = subject[property] || []; - if(!_isArray(rval)) { - rval = [rval]; - } - return rval; -}; + // the point at which write() starts returning false + // Note: 0 is a valid value, means that we always return false if + // the entire buffer is not flushed immediately on write() + var hwm = options.highWaterMark; + var defaultHwm = this.objectMode ? 16 : 16 * 1024; + this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; -/** - * Removes a property from a subject. - * - * @param subject the subject. - * @param property the property. - */ -jsonld.removeProperty = function(subject, property) { - delete subject[property]; -}; + // cast to ints. + this.highWaterMark = Math.floor(this.highWaterMark); -/** - * Removes a value from a subject. - * - * @param subject the subject. - * @param property the property that relates the value to the subject. - * @param value the value to remove. - * @param [options] the options to use: - * [propertyIsArray] true if the property is always an array, false - * if not (default: false). - */ -jsonld.removeValue = function(subject, property, value, options) { - options = options || {}; - if(!('propertyIsArray' in options)) { - options.propertyIsArray = false; - } + // if _final has been called + this.finalCalled = false; - // filter out value - var values = jsonld.getValues(subject, property).filter(function(e) { - return !jsonld.compareValues(e, value); - }); + // drain event flag. + this.needDrain = false; + // at the start of calling end() + this.ending = false; + // when end() has been called, and returned + this.ended = false; + // when 'finish' is emitted + this.finished = false; - if(values.length === 0) { - jsonld.removeProperty(subject, property); - } else if(values.length === 1 && !options.propertyIsArray) { - subject[property] = values[0]; - } else { - subject[property] = values; - } -}; + // has it been destroyed + this.destroyed = false; -/** - * Compares two JSON-LD values for equality. Two JSON-LD values will be - * considered equal if: - * - * 1. They are both primitives of the same type and value. - * 2. They are both @values with the same @value, @type, @language, - * and @index, OR - * 3. They both have @ids they are the same. - * - * @param v1 the first value. - * @param v2 the second value. - * - * @return true if v1 and v2 are considered equal, false if not. - */ -jsonld.compareValues = function(v1, v2) { - // 1. equal primitives - if(v1 === v2) { - return true; - } + // should we decode strings into buffers before passing to _write? + // this is here so that some node-core streams can optimize string + // handling at a lower level. + var noDecode = options.decodeStrings === false; + this.decodeStrings = !noDecode; - // 2. equal @values - if(_isValue(v1) && _isValue(v2) && - v1['@value'] === v2['@value'] && - v1['@type'] === v2['@type'] && - v1['@language'] === v2['@language'] && - v1['@index'] === v2['@index']) { - return true; - } + // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + this.defaultEncoding = options.defaultEncoding || 'utf8'; - // 3. equal @ids - if(_isObject(v1) && ('@id' in v1) && _isObject(v2) && ('@id' in v2)) { - return v1['@id'] === v2['@id']; - } + // not an actual buffer we keep track of, but a measurement + // of how much we're waiting to get pushed to some underlying + // socket or file. + this.length = 0; - return false; -}; + // a flag to see when we're in the middle of a write. + this.writing = false; -/** - * Gets the value for the given active context key and type, null if none is - * set. - * - * @param ctx the active context. - * @param key the context key. - * @param [type] the type of value to get (eg: '@id', '@type'), if not - * specified gets the entire entry for a key, null if not found. - * - * @return the value. - */ -jsonld.getContextValue = function(ctx, key, type) { - var rval = null; + // when true all writes will be buffered until .uncork() call + this.corked = 0; - // return null for invalid key - if(key === null) { - return rval; - } + // a flag to be able to tell if the onwrite cb is called immediately, + // or on a later tick. We set this to true at first, because any + // actions that shouldn't happen until "later" should generally also + // not happen before the first write call. + this.sync = true; - // get default language - if(type === '@language' && (type in ctx)) { - rval = ctx[type]; - } + // a flag to know if we're processing previously buffered items, which + // may call the _write() callback in the same tick, so that we don't + // end up in an overlapped onwrite situation. + this.bufferProcessing = false; - // get specific entry information - if(ctx.mappings[key]) { - var entry = ctx.mappings[key]; + // the callback that's passed to _write(chunk,cb) + this.onwrite = function (er) { + onwrite(stream, er); + }; - if(_isUndefined(type)) { - // return whole entry - rval = entry; - } else if(type in entry) { - // return entry value for type - rval = entry[type]; - } - } + // the callback that the user supplies to write(chunk,encoding,cb) + this.writecb = null; - return rval; -}; + // the amount that is being written when _write is called. + this.writelen = 0; -/** Registered RDF dataset parsers hashed by content-type. */ -var _rdfParsers = {}; - -/** - * Registers an RDF dataset parser by content-type, for use with - * jsonld.fromRDF. An RDF dataset parser will always be given two parameters, - * a string of input and a callback. An RDF dataset parser can be synchronous - * or asynchronous. - * - * If the parser function returns undefined or null then it will be assumed to - * be asynchronous w/a continuation-passing style and the callback parameter - * given to the parser MUST be invoked. - * - * If it returns a Promise, then it will be assumed to be asynchronous, but the - * callback parameter MUST NOT be invoked. It should instead be ignored. - * - * If it returns an RDF dataset, it will be assumed to be synchronous and the - * callback parameter MUST NOT be invoked. It should instead be ignored. - * - * @param contentType the content-type for the parser. - * @param parser(input, callback(err, dataset)) the parser function (takes a - * string as a parameter and either returns null/undefined and uses - * the given callback, returns a Promise, or returns an RDF dataset). - */ -jsonld.registerRDFParser = function(contentType, parser) { - _rdfParsers[contentType] = parser; -}; + this.bufferedRequest = null; + this.lastBufferedRequest = null; -/** - * Unregisters an RDF dataset parser by content-type. - * - * @param contentType the content-type for the parser. - */ -jsonld.unregisterRDFParser = function(contentType) { - delete _rdfParsers[contentType]; -}; + // number of pending user-supplied write callbacks + // this must be 0 before 'finish' can be emitted + this.pendingcb = 0; -if(_nodejs) { - // needed for serialization of XML literals - if(typeof XMLSerializer === 'undefined') { - var XMLSerializer = null; - } - if(typeof Node === 'undefined') { - var Node = { - ELEMENT_NODE: 1, - ATTRIBUTE_NODE: 2, - TEXT_NODE: 3, - CDATA_SECTION_NODE: 4, - ENTITY_REFERENCE_NODE: 5, - ENTITY_NODE: 6, - PROCESSING_INSTRUCTION_NODE: 7, - COMMENT_NODE: 8, - DOCUMENT_NODE: 9, - DOCUMENT_TYPE_NODE: 10, - DOCUMENT_FRAGMENT_NODE: 11, - NOTATION_NODE:12 - }; - } -} + // emit prefinish if the only thing we're waiting for is _write cbs + // This is relevant for synchronous Transform streams + this.prefinished = false; -// constants -var XSD_BOOLEAN = 'http://www.w3.org/2001/XMLSchema#boolean'; -var XSD_DOUBLE = 'http://www.w3.org/2001/XMLSchema#double'; -var XSD_INTEGER = 'http://www.w3.org/2001/XMLSchema#integer'; -var XSD_STRING = 'http://www.w3.org/2001/XMLSchema#string'; + // True if the error was already emitted and should not be thrown again + this.errorEmitted = false; -var RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; -var RDF_LIST = RDF + 'List'; -var RDF_FIRST = RDF + 'first'; -var RDF_REST = RDF + 'rest'; -var RDF_NIL = RDF + 'nil'; -var RDF_TYPE = RDF + 'type'; -var RDF_PLAIN_LITERAL = RDF + 'PlainLiteral'; -var RDF_XML_LITERAL = RDF + 'XMLLiteral'; -var RDF_OBJECT = RDF + 'object'; -var RDF_LANGSTRING = RDF + 'langString'; + // count buffered requests + this.bufferedRequestCount = 0; -var LINK_HEADER_REL = 'http://www.w3.org/ns/json-ld#context'; -var MAX_CONTEXT_URLS = 10; + // allocate the first CorkedRequest, there is always + // one allocated and free to use, and we maintain at most two + this.corkedRequestsFree = new CorkedRequest(this); +} -/** - * A JSON-LD Error. - * - * @param msg the error message. - * @param type the error type. - * @param details the error details. - */ -var JsonLdError = function(msg, type, details) { - if(_nodejs) { - Error.call(this); - Error.captureStackTrace(this, this.constructor); - } else if(typeof Error !== 'undefined') { - this.stack = (new Error()).stack; +WritableState.prototype.getBuffer = function getBuffer() { + var current = this.bufferedRequest; + var out = []; + while (current) { + out.push(current); + current = current.next; } - this.name = type || 'jsonld.Error'; - this.message = msg || 'An unspecified JSON-LD error occurred.'; - this.details = details || {}; + return out; }; -if(_nodejs) { - _dereq_('util').inherits(JsonLdError, Error); -} else if(typeof Error !== 'undefined') { - JsonLdError.prototype = new Error(); -} - -/** - * Constructs a new JSON-LD Processor. - */ -var Processor = function() {}; -/** - * Recursively compacts an element using the given active context. All values - * must be in expanded form before this method is called. - * - * @param activeCtx the active context to use. - * @param activeProperty the compacted property associated with the element - * to compact, null for none. - * @param element the element to compact. - * @param options the compaction options. - * - * @return the compacted value. - */ -Processor.prototype.compact = function( - activeCtx, activeProperty, element, options) { - // recursively compact array - if(_isArray(element)) { - var rval = []; - for(var i = 0; i < element.length; ++i) { - // compact, dropping any null values - var compacted = this.compact( - activeCtx, activeProperty, element[i], options); - if(compacted !== null) { - rval.push(compacted); - } - } - if(options.compactArrays && rval.length === 1) { - // use single element if no container is specified - var container = jsonld.getContextValue( - activeCtx, activeProperty, '@container'); - if(container === null) { - rval = rval[0]; - } - } - return rval; - } +(function () { + try { + Object.defineProperty(WritableState.prototype, 'buffer', { + get: internalUtil.deprecate(function () { + return this.getBuffer(); + }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003') + }); + } catch (_) {} +})(); - // recursively compact object - if(_isObject(element)) { - if(options.link && '@id' in element && element['@id'] in options.link) { - // check for a linked element to reuse - var linked = options.link[element['@id']]; - for(var i = 0; i < linked.length; ++i) { - if(linked[i].expanded === element) { - return linked[i].compacted; - } - } - } +// Test _writableState for inheritance to account for Duplex streams, +// whose prototype chain only points to Readable. +var realHasInstance; +if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') { + realHasInstance = Function.prototype[Symbol.hasInstance]; + Object.defineProperty(Writable, Symbol.hasInstance, { + value: function (object) { + if (realHasInstance.call(this, object)) return true; - // do value compaction on @values and subject references - if(_isValue(element) || _isSubjectReference(element)) { - var rval = _compactValue(activeCtx, activeProperty, element); - if(options.link && _isSubjectReference(element)) { - // store linked element - if(!(element['@id'] in options.link)) { - options.link[element['@id']] = []; - } - options.link[element['@id']].push({expanded: element, compacted: rval}); - } - return rval; + return object && object._writableState instanceof WritableState; } + }); +} else { + realHasInstance = function (object) { + return object instanceof this; + }; +} - // FIXME: avoid misuse of active property as an expanded property? - var insideReverse = (activeProperty === '@reverse'); - - var rval = {}; - - if(options.link && '@id' in element) { - // store linked element - if(!(element['@id'] in options.link)) { - options.link[element['@id']] = []; - } - options.link[element['@id']].push({expanded: element, compacted: rval}); - } +function Writable(options) { + Duplex = Duplex || _dereq_('./_stream_duplex'); - // process element keys in order - var keys = Object.keys(element).sort(); - for(var ki = 0; ki < keys.length; ++ki) { - var expandedProperty = keys[ki]; - var expandedValue = element[expandedProperty]; + // Writable ctor is applied to Duplexes, too. + // `realHasInstance` is necessary because using plain `instanceof` + // would return false, as no `_writableState` property is attached. - // compact @id and @type(s) - if(expandedProperty === '@id' || expandedProperty === '@type') { - var compactedValue; + // Trying to use the custom `instanceof` for Writable here will also break the + // Node.js LazyTransform implementation, which has a non-trivial getter for + // `_writableState` that would lead to infinite recursion. + if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) { + return new Writable(options); + } - // compact single @id - if(_isString(expandedValue)) { - compactedValue = _compactIri( - activeCtx, expandedValue, null, - {vocab: (expandedProperty === '@type')}); - } else { - // expanded value must be a @type array - compactedValue = []; - for(var vi = 0; vi < expandedValue.length; ++vi) { - compactedValue.push(_compactIri( - activeCtx, expandedValue[vi], null, {vocab: true})); - } - } + this._writableState = new WritableState(options, this); - // use keyword alias and add value - var alias = _compactIri(activeCtx, expandedProperty); - var isArray = (_isArray(compactedValue) && expandedValue.length === 0); - jsonld.addValue( - rval, alias, compactedValue, {propertyIsArray: isArray}); - continue; - } + // legacy. + this.writable = true; - // handle @reverse - if(expandedProperty === '@reverse') { - // recursively compact expanded value - var compactedValue = this.compact( - activeCtx, '@reverse', expandedValue, options); + if (options) { + if (typeof options.write === 'function') this._write = options.write; - // handle double-reversed properties - for(var compactedProperty in compactedValue) { - if(activeCtx.mappings[compactedProperty] && - activeCtx.mappings[compactedProperty].reverse) { - var value = compactedValue[compactedProperty]; - var container = jsonld.getContextValue( - activeCtx, compactedProperty, '@container'); - var useArray = (container === '@set' || !options.compactArrays); - jsonld.addValue( - rval, compactedProperty, value, {propertyIsArray: useArray}); - delete compactedValue[compactedProperty]; - } - } + if (typeof options.writev === 'function') this._writev = options.writev; - if(Object.keys(compactedValue).length > 0) { - // use keyword alias and add value - var alias = _compactIri(activeCtx, expandedProperty); - jsonld.addValue(rval, alias, compactedValue); - } + if (typeof options.destroy === 'function') this._destroy = options.destroy; - continue; - } + if (typeof options.final === 'function') this._final = options.final; + } - // handle @index property - if(expandedProperty === '@index') { - // drop @index if inside an @index container - var container = jsonld.getContextValue( - activeCtx, activeProperty, '@container'); - if(container === '@index') { - continue; - } + Stream.call(this); +} - // use keyword alias and add value - var alias = _compactIri(activeCtx, expandedProperty); - jsonld.addValue(rval, alias, expandedValue); - continue; - } +// Otherwise people can pipe Writable streams, which is just wrong. +Writable.prototype.pipe = function () { + this.emit('error', new Error('Cannot pipe, not readable')); +}; - // skip array processing for keywords that aren't @graph or @list - if(expandedProperty !== '@graph' && expandedProperty !== '@list' && - _isKeyword(expandedProperty)) { - // use keyword alias and add value as is - var alias = _compactIri(activeCtx, expandedProperty); - jsonld.addValue(rval, alias, expandedValue); - continue; - } +function writeAfterEnd(stream, cb) { + var er = new Error('write after end'); + // TODO: defer error events consistently everywhere, not just the cb + stream.emit('error', er); + processNextTick(cb, er); +} - // Note: expanded value must be an array due to expansion algorithm. +// Checks that a user-supplied chunk is valid, especially for the particular +// mode the stream is in. Currently this means that `null` is never accepted +// and undefined/non-string values are only allowed in object mode. +function validChunk(stream, state, chunk, cb) { + var valid = true; + var er = false; - // preserve empty arrays - if(expandedValue.length === 0) { - var itemActiveProperty = _compactIri( - activeCtx, expandedProperty, expandedValue, {vocab: true}, - insideReverse); - jsonld.addValue( - rval, itemActiveProperty, expandedValue, {propertyIsArray: true}); - } + if (chunk === null) { + er = new TypeError('May not write null values to stream'); + } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { + er = new TypeError('Invalid non-string/buffer chunk'); + } + if (er) { + stream.emit('error', er); + processNextTick(cb, er); + valid = false; + } + return valid; +} - // recusively process array values - for(var vi = 0; vi < expandedValue.length; ++vi) { - var expandedItem = expandedValue[vi]; +Writable.prototype.write = function (chunk, encoding, cb) { + var state = this._writableState; + var ret = false; + var isBuf = _isUint8Array(chunk) && !state.objectMode; - // compact property and get container type - var itemActiveProperty = _compactIri( - activeCtx, expandedProperty, expandedItem, {vocab: true}, - insideReverse); - var container = jsonld.getContextValue( - activeCtx, itemActiveProperty, '@container'); + if (isBuf && !Buffer.isBuffer(chunk)) { + chunk = _uint8ArrayToBuffer(chunk); + } - // get @list value if appropriate - var isList = _isList(expandedItem); - var list = null; - if(isList) { - list = expandedItem['@list']; - } + if (typeof encoding === 'function') { + cb = encoding; + encoding = null; + } - // recursively compact expanded item - var compactedItem = this.compact( - activeCtx, itemActiveProperty, isList ? list : expandedItem, options); + if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; - // handle @list - if(isList) { - // ensure @list value is an array - if(!_isArray(compactedItem)) { - compactedItem = [compactedItem]; - } + if (typeof cb !== 'function') cb = nop; - if(container !== '@list') { - // wrap using @list alias - var wrapper = {}; - wrapper[_compactIri(activeCtx, '@list')] = compactedItem; - compactedItem = wrapper; + if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { + state.pendingcb++; + ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); + } - // include @index from expanded @list, if any - if('@index' in expandedItem) { - compactedItem[_compactIri(activeCtx, '@index')] = - expandedItem['@index']; - } - } else if(itemActiveProperty in rval) { - // can't use @list container for more than 1 list - throw new JsonLdError( - 'JSON-LD compact error; property has a "@list" @container ' + - 'rule but there is more than a single @list that matches ' + - 'the compacted term in the document. Compaction might mix ' + - 'unwanted items into the list.', - 'jsonld.SyntaxError', {code: 'compaction to list of lists'}); - } - } + return ret; +}; - // handle language and index maps - if(container === '@language' || container === '@index') { - // get or create the map object - var mapObject; - if(itemActiveProperty in rval) { - mapObject = rval[itemActiveProperty]; - } else { - rval[itemActiveProperty] = mapObject = {}; - } +Writable.prototype.cork = function () { + var state = this._writableState; - // if container is a language map, simplify compacted value to - // a simple string - if(container === '@language' && _isValue(compactedItem)) { - compactedItem = compactedItem['@value']; - } + state.corked++; +}; - // add compact value to map object using key from expanded value - // based on the container type - jsonld.addValue(mapObject, expandedItem[container], compactedItem); - } else { - // use an array if: compactArrays flag is false, - // @container is @set or @list , value is an empty - // array, or key is @graph - var isArray = (!options.compactArrays || container === '@set' || - container === '@list' || - (_isArray(compactedItem) && compactedItem.length === 0) || - expandedProperty === '@list' || expandedProperty === '@graph'); +Writable.prototype.uncork = function () { + var state = this._writableState; - // add compact value - jsonld.addValue( - rval, itemActiveProperty, compactedItem, - {propertyIsArray: isArray}); - } - } - } + if (state.corked) { + state.corked--; - return rval; + if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); } - - // only primitives remain which are already compact - return element; }; -/** - * Recursively expands an element using the given context. Any context in - * the element will be removed. All context URLs must have been retrieved - * before calling this method. - * - * @param activeCtx the context to use. - * @param activeProperty the property for the element, null for none. - * @param element the element to expand. - * @param options the expansion options. - * @param insideList true if the element is a list, false if not. - * - * @return the expanded value. - */ -Processor.prototype.expand = function( - activeCtx, activeProperty, element, options, insideList) { - var self = this; +Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { + // node::ParseEncoding() requires lower case. + if (typeof encoding === 'string') encoding = encoding.toLowerCase(); + if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding); + this._writableState.defaultEncoding = encoding; + return this; +}; - // nothing to expand - if(element === null || element === undefined) { - return null; +function decodeChunk(state, chunk, encoding) { + if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { + chunk = Buffer.from(chunk, encoding); } + return chunk; +} - if(!_isArray(element) && !_isObject(element)) { - // drop free-floating scalars that are not in lists - if(!insideList && (activeProperty === null || - _expandIri(activeCtx, activeProperty, {vocab: true}) === '@graph')) { - return null; +// if we're already writing something, then just put this +// in the queue, and wait our turn. Otherwise, call _write +// If we return false, then we need a drain event, so set that flag. +function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) { + if (!isBuf) { + var newChunk = decodeChunk(state, chunk, encoding); + if (chunk !== newChunk) { + isBuf = true; + encoding = 'buffer'; + chunk = newChunk; } - - // expand element according to value expansion rules - return _expandValue(activeCtx, activeProperty, element); } + var len = state.objectMode ? 1 : chunk.length; - // recursively expand array - if(_isArray(element)) { - var rval = []; - var container = jsonld.getContextValue( - activeCtx, activeProperty, '@container'); - insideList = insideList || container === '@list'; - for(var i = 0; i < element.length; ++i) { - // expand element - var e = self.expand(activeCtx, activeProperty, element[i], options); - if(insideList && (_isArray(e) || _isList(e))) { - // lists of lists are illegal - throw new JsonLdError( - 'Invalid JSON-LD syntax; lists of lists are not permitted.', - 'jsonld.SyntaxError', {code: 'list of lists'}); - } - // drop null values - if(e !== null) { - if(_isArray(e)) { - rval = rval.concat(e); - } else { - rval.push(e); - } - } + state.length += len; + + var ret = state.length < state.highWaterMark; + // we must ensure that previous needDrain will not be reset to false. + if (!ret) state.needDrain = true; + + if (state.writing || state.corked) { + var last = state.lastBufferedRequest; + state.lastBufferedRequest = { + chunk: chunk, + encoding: encoding, + isBuf: isBuf, + callback: cb, + next: null + }; + if (last) { + last.next = state.lastBufferedRequest; + } else { + state.bufferedRequest = state.lastBufferedRequest; } - return rval; + state.bufferedRequestCount += 1; + } else { + doWrite(stream, state, false, len, chunk, encoding, cb); } - // recursively expand object: + return ret; +} - // if element has a context, process it - if('@context' in element) { - activeCtx = self.processContext(activeCtx, element['@context'], options); - } +function doWrite(stream, state, writev, len, chunk, encoding, cb) { + state.writelen = len; + state.writecb = cb; + state.writing = true; + state.sync = true; + if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite); + state.sync = false; +} - // expand the active property - var expandedActiveProperty = _expandIri( - activeCtx, activeProperty, {vocab: true}); +function onwriteError(stream, state, sync, er, cb) { + --state.pendingcb; - var rval = {}; - var keys = Object.keys(element).sort(); - for(var ki = 0; ki < keys.length; ++ki) { - var key = keys[ki]; - var value = element[key]; - var expandedValue; + if (sync) { + // defer the callback if we are being called synchronously + // to avoid piling up things on the stack + processNextTick(cb, er); + // this can emit finish, and it will always happen + // after error + processNextTick(finishMaybe, stream, state); + stream._writableState.errorEmitted = true; + stream.emit('error', er); + } else { + // the caller expect this to happen before if + // it is async + cb(er); + stream._writableState.errorEmitted = true; + stream.emit('error', er); + // this can emit finish, but finish must + // always follow error + finishMaybe(stream, state); + } +} - // skip @context - if(key === '@context') { - continue; - } +function onwriteStateUpdate(state) { + state.writing = false; + state.writecb = null; + state.length -= state.writelen; + state.writelen = 0; +} - // expand property - var expandedProperty = _expandIri(activeCtx, key, {vocab: true}); +function onwrite(stream, er) { + var state = stream._writableState; + var sync = state.sync; + var cb = state.writecb; - // drop non-absolute IRI keys that aren't keywords - if(expandedProperty === null || - !(_isAbsoluteIri(expandedProperty) || _isKeyword(expandedProperty))) { - continue; - } + onwriteStateUpdate(state); - if(_isKeyword(expandedProperty)) { - if(expandedActiveProperty === '@reverse') { - throw new JsonLdError( - 'Invalid JSON-LD syntax; a keyword cannot be used as a @reverse ' + - 'property.', 'jsonld.SyntaxError', - {code: 'invalid reverse property map', value: value}); - } - if(expandedProperty in rval) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; colliding keywords detected.', - 'jsonld.SyntaxError', - {code: 'colliding keywords', keyword: expandedProperty}); - } - } + if (er) onwriteError(stream, state, sync, er, cb);else { + // Check if we're actually ready to finish, but don't emit yet + var finished = needFinish(state); - // syntax error if @id is not a string - if(expandedProperty === '@id' && !_isString(value)) { - if(!options.isFrame) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; "@id" value must a string.', - 'jsonld.SyntaxError', {code: 'invalid @id value', value: value}); - } - if(!_isObject(value)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; "@id" value must be a string or an ' + - 'object.', 'jsonld.SyntaxError', - {code: 'invalid @id value', value: value}); - } + if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) { + clearBuffer(stream, state); } - if(expandedProperty === '@type') { - _validateTypeValue(value); + if (sync) { + /**/ + asyncWrite(afterWrite, stream, state, finished, cb); + /**/ + } else { + afterWrite(stream, state, finished, cb); } + } +} - // @graph must be an array or an object - if(expandedProperty === '@graph' && - !(_isObject(value) || _isArray(value))) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; "@graph" value must not be an ' + - 'object or an array.', - 'jsonld.SyntaxError', {code: 'invalid @graph value', value: value}); - } +function afterWrite(stream, state, finished, cb) { + if (!finished) onwriteDrain(stream, state); + state.pendingcb--; + cb(); + finishMaybe(stream, state); +} - // @value must not be an object or an array - if(expandedProperty === '@value' && - (_isObject(value) || _isArray(value))) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; "@value" value must not be an ' + - 'object or an array.', - 'jsonld.SyntaxError', - {code: 'invalid value object value', value: value}); - } +// Must force callback to be called on nextTick, so that we don't +// emit 'drain' before the write() consumer gets the 'false' return +// value, and has a chance to attach a 'drain' listener. +function onwriteDrain(stream, state) { + if (state.length === 0 && state.needDrain) { + state.needDrain = false; + stream.emit('drain'); + } +} - // @language must be a string - if(expandedProperty === '@language') { - if(value === null) { - // drop null @language values, they expand as if they didn't exist - continue; - } - if(!_isString(value)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; "@language" value must be a string.', - 'jsonld.SyntaxError', - {code: 'invalid language-tagged string', value: value}); - } - // ensure language value is lowercase - value = value.toLowerCase(); - } +// if there's something in the buffer waiting, then process it +function clearBuffer(stream, state) { + state.bufferProcessing = true; + var entry = state.bufferedRequest; - // @index must be a string - if(expandedProperty === '@index') { - if(!_isString(value)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; "@index" value must be a string.', - 'jsonld.SyntaxError', - {code: 'invalid @index value', value: value}); - } + if (stream._writev && entry && entry.next) { + // Fast case, write everything using _writev() + var l = state.bufferedRequestCount; + var buffer = new Array(l); + var holder = state.corkedRequestsFree; + holder.entry = entry; + + var count = 0; + var allBuffers = true; + while (entry) { + buffer[count] = entry; + if (!entry.isBuf) allBuffers = false; + entry = entry.next; + count += 1; } + buffer.allBuffers = allBuffers; - // @reverse must be an object - if(expandedProperty === '@reverse') { - if(!_isObject(value)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; "@reverse" value must be an object.', - 'jsonld.SyntaxError', {code: 'invalid @reverse value', value: value}); - } + doWrite(stream, state, true, state.length, buffer, '', holder.finish); - expandedValue = self.expand(activeCtx, '@reverse', value, options); + // doWrite is almost always async, defer these to save a bit of time + // as the hot path ends with doWrite + state.pendingcb++; + state.lastBufferedRequest = null; + if (holder.next) { + state.corkedRequestsFree = holder.next; + holder.next = null; + } else { + state.corkedRequestsFree = new CorkedRequest(state); + } + } else { + // Slow case, write chunks one-by-one + while (entry) { + var chunk = entry.chunk; + var encoding = entry.encoding; + var cb = entry.callback; + var len = state.objectMode ? 1 : chunk.length; - // properties double-reversed - if('@reverse' in expandedValue) { - for(var property in expandedValue['@reverse']) { - jsonld.addValue( - rval, property, expandedValue['@reverse'][property], - {propertyIsArray: true}); - } + doWrite(stream, state, false, len, chunk, encoding, cb); + entry = entry.next; + // if we didn't call the onwrite immediately, then + // it means that we need to wait until it does. + // also, that means that the chunk and cb are currently + // being processed, so move the buffer counter past them. + if (state.writing) { + break; } + } - // FIXME: can this be merged with code below to simplify? - // merge in all reversed properties - var reverseMap = rval['@reverse'] || null; - for(var property in expandedValue) { - if(property === '@reverse') { - continue; - } - if(reverseMap === null) { - reverseMap = rval['@reverse'] = {}; - } - jsonld.addValue(reverseMap, property, [], {propertyIsArray: true}); - var items = expandedValue[property]; - for(var ii = 0; ii < items.length; ++ii) { - var item = items[ii]; - if(_isValue(item) || _isList(item)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; "@reverse" value must not be a ' + - '@value or an @list.', 'jsonld.SyntaxError', - {code: 'invalid reverse property value', value: expandedValue}); - } - jsonld.addValue( - reverseMap, property, item, {propertyIsArray: true}); - } - } + if (entry === null) state.lastBufferedRequest = null; + } - continue; - } + state.bufferedRequestCount = 0; + state.bufferedRequest = entry; + state.bufferProcessing = false; +} - var container = jsonld.getContextValue(activeCtx, key, '@container'); +Writable.prototype._write = function (chunk, encoding, cb) { + cb(new Error('_write() is not implemented')); +}; - if(container === '@language' && _isObject(value)) { - // handle language map container (skip if value is not an object) - expandedValue = _expandLanguageMap(value); - } else if(container === '@index' && _isObject(value)) { - // handle index container (skip if value is not an object) - expandedValue = (function _expandIndexMap(activeProperty) { - var rval = []; - var keys = Object.keys(value).sort(); - for(var ki = 0; ki < keys.length; ++ki) { - var key = keys[ki]; - var val = value[key]; - if(!_isArray(val)) { - val = [val]; - } - val = self.expand(activeCtx, activeProperty, val, options, false); - for(var vi = 0; vi < val.length; ++vi) { - var item = val[vi]; - if(!('@index' in item)) { - item['@index'] = key; - } - rval.push(item); - } - } - return rval; - })(key); - } else { - // recurse into @list or @set - var isList = (expandedProperty === '@list'); - if(isList || expandedProperty === '@set') { - var nextActiveProperty = activeProperty; - if(isList && expandedActiveProperty === '@graph') { - nextActiveProperty = null; - } - expandedValue = self.expand( - activeCtx, nextActiveProperty, value, options, isList); - if(isList && _isList(expandedValue)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; lists of lists are not permitted.', - 'jsonld.SyntaxError', {code: 'list of lists'}); - } - } else { - // recursively expand value with key as new active property - expandedValue = self.expand(activeCtx, key, value, options, false); - } - } +Writable.prototype._writev = null; - // drop null values if property is not @value - if(expandedValue === null && expandedProperty !== '@value') { - continue; - } +Writable.prototype.end = function (chunk, encoding, cb) { + var state = this._writableState; - // convert expanded value to @list if container specifies it - if(expandedProperty !== '@list' && !_isList(expandedValue) && - container === '@list') { - // ensure expanded value is an array - expandedValue = (_isArray(expandedValue) ? - expandedValue : [expandedValue]); - expandedValue = {'@list': expandedValue}; - } + if (typeof chunk === 'function') { + cb = chunk; + chunk = null; + encoding = null; + } else if (typeof encoding === 'function') { + cb = encoding; + encoding = null; + } - // FIXME: can this be merged with code above to simplify? - // merge in reverse properties - if(activeCtx.mappings[key] && activeCtx.mappings[key].reverse) { - var reverseMap = rval['@reverse'] = rval['@reverse'] || {}; - if(!_isArray(expandedValue)) { - expandedValue = [expandedValue]; - } - for(var ii = 0; ii < expandedValue.length; ++ii) { - var item = expandedValue[ii]; - if(_isValue(item) || _isList(item)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; "@reverse" value must not be a ' + - '@value or an @list.', 'jsonld.SyntaxError', - {code: 'invalid reverse property value', value: expandedValue}); - } - jsonld.addValue( - reverseMap, expandedProperty, item, {propertyIsArray: true}); - } - continue; - } + if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); - // add value for property - // use an array except for certain keywords - var useArray = - ['@index', '@id', '@type', '@value', '@language'].indexOf( - expandedProperty) === -1; - jsonld.addValue( - rval, expandedProperty, expandedValue, {propertyIsArray: useArray}); + // .end() fully uncorks + if (state.corked) { + state.corked = 1; + this.uncork(); } - // get property count on expanded output - keys = Object.keys(rval); - var count = keys.length; + // ignore unnecessary end() calls. + if (!state.ending && !state.finished) endWritable(this, state, cb); +}; - if('@value' in rval) { - // @value must only have @language or @type - if('@type' in rval && '@language' in rval) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; an element containing "@value" may not ' + - 'contain both "@type" and "@language".', - 'jsonld.SyntaxError', {code: 'invalid value object', element: rval}); - } - var validCount = count - 1; - if('@type' in rval) { - validCount -= 1; - } - if('@index' in rval) { - validCount -= 1; - } - if('@language' in rval) { - validCount -= 1; - } - if(validCount !== 0) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; an element containing "@value" may only ' + - 'have an "@index" property and at most one other property ' + - 'which can be "@type" or "@language".', - 'jsonld.SyntaxError', {code: 'invalid value object', element: rval}); - } - // drop null @values - if(rval['@value'] === null) { - rval = null; - } else if('@language' in rval && !_isString(rval['@value'])) { - // if @language is present, @value must be a string - throw new JsonLdError( - 'Invalid JSON-LD syntax; only strings may be language-tagged.', - 'jsonld.SyntaxError', - {code: 'invalid language-tagged value', element: rval}); - } else if('@type' in rval && (!_isAbsoluteIri(rval['@type']) || - rval['@type'].indexOf('_:') === 0)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; an element containing "@value" and "@type" ' + - 'must have an absolute IRI for the value of "@type".', - 'jsonld.SyntaxError', {code: 'invalid typed value', element: rval}); - } - } else if('@type' in rval && !_isArray(rval['@type'])) { - // convert @type to an array - rval['@type'] = [rval['@type']]; - } else if('@set' in rval || '@list' in rval) { - // handle @set and @list - if(count > 1 && !(count === 2 && '@index' in rval)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; if an element has the property "@set" ' + - 'or "@list", then it can have at most one other property that is ' + - '"@index".', 'jsonld.SyntaxError', - {code: 'invalid set or list object', element: rval}); +function needFinish(state) { + return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing; +} +function callFinal(stream, state) { + stream._final(function (err) { + state.pendingcb--; + if (err) { + stream.emit('error', err); } - // optimize away @set - if('@set' in rval) { - rval = rval['@set']; - keys = Object.keys(rval); - count = keys.length; + state.prefinished = true; + stream.emit('prefinish'); + finishMaybe(stream, state); + }); +} +function prefinish(stream, state) { + if (!state.prefinished && !state.finalCalled) { + if (typeof stream._final === 'function') { + state.pendingcb++; + state.finalCalled = true; + processNextTick(callFinal, stream, state); + } else { + state.prefinished = true; + stream.emit('prefinish'); } - } else if(count === 1 && '@language' in rval) { - // drop objects with only @language - rval = null; } +} - // drop certain top-level objects that do not occur in lists - if(_isObject(rval) && - !options.keepFreeFloatingNodes && !insideList && - (activeProperty === null || expandedActiveProperty === '@graph')) { - // drop empty object, top-level @value/@list, or object with only @id - if(count === 0 || '@value' in rval || '@list' in rval || - (count === 1 && '@id' in rval)) { - rval = null; +function finishMaybe(stream, state) { + var need = needFinish(state); + if (need) { + prefinish(stream, state); + if (state.pendingcb === 0) { + state.finished = true; + stream.emit('finish'); } } + return need; +} - return rval; -}; - -/** - * Creates a JSON-LD node map (node ID => node). - * - * @param input the expanded JSON-LD to create a node map of. - * @param [options] the options to use: - * [issuer] a jsonld.IdentifierIssuer to use to label blank nodes. - * [namer] (deprecated). - * - * @return the node map. - */ -Processor.prototype.createNodeMap = function(input, options) { - options = options || {}; - - // produce a map of all subjects and name each bnode - var issuer = options.namer || options.issuer || new IdentifierIssuer('_:b'); - var graphs = {'@default': {}}; - _createNodeMap(input, graphs, '@default', issuer); - - // add all non-default graphs to default graph - return _mergeNodeMaps(graphs); -}; +function endWritable(stream, state, cb) { + state.ending = true; + finishMaybe(stream, state); + if (cb) { + if (state.finished) processNextTick(cb);else stream.once('finish', cb); + } + state.ended = true; + stream.writable = false; +} -/** - * Performs JSON-LD flattening. - * - * @param input the expanded JSON-LD to flatten. - * - * @return the flattened output. - */ -Processor.prototype.flatten = function(input) { - var defaultGraph = this.createNodeMap(input); +function onCorkedFinish(corkReq, state, err) { + var entry = corkReq.entry; + corkReq.entry = null; + while (entry) { + var cb = entry.callback; + state.pendingcb--; + cb(err); + entry = entry.next; + } + if (state.corkedRequestsFree) { + state.corkedRequestsFree.next = corkReq; + } else { + state.corkedRequestsFree = corkReq; + } +} - // produce flattened output - var flattened = []; - var keys = Object.keys(defaultGraph).sort(); - for(var ki = 0; ki < keys.length; ++ki) { - var node = defaultGraph[keys[ki]]; - // only add full subjects to top-level - if(!_isSubjectReference(node)) { - flattened.push(node); +Object.defineProperty(Writable.prototype, 'destroyed', { + get: function () { + if (this._writableState === undefined) { + return false; + } + return this._writableState.destroyed; + }, + set: function (value) { + // we ignore the value if the stream + // has not been initialized yet + if (!this._writableState) { + return; } + + // backward compatibility, the user is explicitly + // managing destroyed + this._writableState.destroyed = value; } - return flattened; +}); + +Writable.prototype.destroy = destroyImpl.destroy; +Writable.prototype._undestroy = destroyImpl.undestroy; +Writable.prototype._destroy = function (err, cb) { + this.end(); + cb(err); }; +}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -/** - * Performs JSON-LD framing. - * - * @param input the expanded JSON-LD to frame. - * @param frame the expanded JSON-LD frame to use. - * @param options the framing options. - * - * @return the framed output. - */ -Processor.prototype.frame = function(input, frame, options) { - // create framing state - var state = { - options: options, - graphs: {'@default': {}, '@merged': {}}, - subjectStack: [], - link: {} - }; +},{"./_stream_duplex":18,"./internal/streams/destroy":24,"./internal/streams/stream":25,"_process":12,"core-util-is":26,"inherits":10,"process-nextick-args":28,"safe-buffer":29,"util-deprecate":31}],23:[function(_dereq_,module,exports){ +'use strict'; - // produce a map of all graphs and name each bnode - // FIXME: currently uses subjects from @merged graph only - var issuer = new IdentifierIssuer('_:b'); - _createNodeMap(input, state.graphs, '@merged', issuer); - state.subjects = state.graphs['@merged']; +/**/ - // frame the subjects - var framed = []; - _frame(state, Object.keys(state.subjects).sort(), frame, framed, null); - return framed; -}; +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -/** - * Performs normalization on the given RDF dataset. - * - * @param dataset the RDF dataset to normalize. - * @param options the normalization options. - * @param callback(err, normalized) called once the operation completes. - */ -Processor.prototype.normalize = function(dataset, options, callback) { - if(options.algorithm === 'URDNA2015') { - return new URDNA2015(options).main(dataset, callback); - } - if(options.algorithm === 'URGNA2012') { - return new URGNA2012(options).main(dataset, callback); - } - callback(new Error( - 'Invalid RDF Dataset Normalization algorithm: ' + options.algorithm)); -}; +var Buffer = _dereq_('safe-buffer').Buffer; +/**/ -/** - * Converts an RDF dataset to JSON-LD. - * - * @param dataset the RDF dataset. - * @param options the RDF serialization options. - * @param callback(err, output) called once the operation completes. - */ -Processor.prototype.fromRDF = function(dataset, options, callback) { - var defaultGraph = {}; - var graphMap = {'@default': defaultGraph}; - var referencedOnce = {}; +function copyBuffer(src, target, offset) { + src.copy(target, offset); +} - for(var name in dataset) { - var graph = dataset[name]; - if(!(name in graphMap)) { - graphMap[name] = {}; - } - if(name !== '@default' && !(name in defaultGraph)) { - defaultGraph[name] = {'@id': name}; - } - var nodeMap = graphMap[name]; - for(var ti = 0; ti < graph.length; ++ti) { - var triple = graph[ti]; +module.exports = function () { + function BufferList() { + _classCallCheck(this, BufferList); - // get subject, predicate, object - var s = triple.subject.value; - var p = triple.predicate.value; - var o = triple.object; + this.head = null; + this.tail = null; + this.length = 0; + } - if(!(s in nodeMap)) { - nodeMap[s] = {'@id': s}; - } - var node = nodeMap[s]; + BufferList.prototype.push = function push(v) { + var entry = { data: v, next: null }; + if (this.length > 0) this.tail.next = entry;else this.head = entry; + this.tail = entry; + ++this.length; + }; - var objectIsId = (o.type === 'IRI' || o.type === 'blank node'); - if(objectIsId && !(o.value in nodeMap)) { - nodeMap[o.value] = {'@id': o.value}; - } + BufferList.prototype.unshift = function unshift(v) { + var entry = { data: v, next: this.head }; + if (this.length === 0) this.tail = entry; + this.head = entry; + ++this.length; + }; - if(p === RDF_TYPE && !options.useRdfType && objectIsId) { - jsonld.addValue(node, '@type', o.value, {propertyIsArray: true}); - continue; - } + BufferList.prototype.shift = function shift() { + if (this.length === 0) return; + var ret = this.head.data; + if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next; + --this.length; + return ret; + }; - var value = _RDFToObject(o, options.useNativeTypes); - jsonld.addValue(node, p, value, {propertyIsArray: true}); + BufferList.prototype.clear = function clear() { + this.head = this.tail = null; + this.length = 0; + }; - // object may be an RDF list/partial list node but we can't know easily - // until all triples are read - if(objectIsId) { - if(o.value === RDF_NIL) { - // track rdf:nil uniquely per graph - var object = nodeMap[o.value]; - if(!('usages' in object)) { - object.usages = []; - } - object.usages.push({ - node: node, - property: p, - value: value - }); - } else if(o.value in referencedOnce) { - // object referenced more than once - referencedOnce[o.value] = false; - } else { - // keep track of single reference - referencedOnce[o.value] = { - node: node, - property: p, - value: value - }; - } - } + BufferList.prototype.join = function join(s) { + if (this.length === 0) return ''; + var p = this.head; + var ret = '' + p.data; + while (p = p.next) { + ret += s + p.data; + }return ret; + }; + + BufferList.prototype.concat = function concat(n) { + if (this.length === 0) return Buffer.alloc(0); + if (this.length === 1) return this.head.data; + var ret = Buffer.allocUnsafe(n >>> 0); + var p = this.head; + var i = 0; + while (p) { + copyBuffer(p.data, ret, i); + i += p.data.length; + p = p.next; } - } + return ret; + }; - // convert linked lists to @list arrays - for(var name in graphMap) { - var graphObject = graphMap[name]; + return BufferList; +}(); +},{"safe-buffer":29}],24:[function(_dereq_,module,exports){ +'use strict'; - // no @lists to be converted, continue - if(!(RDF_NIL in graphObject)) { - continue; - } +/**/ - // iterate backwards through each RDF list - var nil = graphObject[RDF_NIL]; - for(var i = 0; i < nil.usages.length; ++i) { - var usage = nil.usages[i]; - var node = usage.node; - var property = usage.property; - var head = usage.value; - var list = []; - var listNodes = []; +var processNextTick = _dereq_('process-nextick-args'); +/**/ - // ensure node is a well-formed list node; it must: - // 1. Be referenced only once. - // 2. Have an array for rdf:first that has 1 item. - // 3. Have an array for rdf:rest that has 1 item. - // 4. Have no keys other than: @id, rdf:first, rdf:rest, and, - // optionally, @type where the value is rdf:List. - var nodeKeyCount = Object.keys(node).length; - while(property === RDF_REST && - _isObject(referencedOnce[node['@id']]) && - _isArray(node[RDF_FIRST]) && node[RDF_FIRST].length === 1 && - _isArray(node[RDF_REST]) && node[RDF_REST].length === 1 && - (nodeKeyCount === 3 || (nodeKeyCount === 4 && _isArray(node['@type']) && - node['@type'].length === 1 && node['@type'][0] === RDF_LIST))) { - list.push(node[RDF_FIRST][0]); - listNodes.push(node['@id']); +// undocumented cb() API, needed for core, not for public API +function destroy(err, cb) { + var _this = this; - // get next node, moving backwards through list - usage = referencedOnce[node['@id']]; - node = usage.node; - property = usage.property; - head = usage.value; - nodeKeyCount = Object.keys(node).length; + var readableDestroyed = this._readableState && this._readableState.destroyed; + var writableDestroyed = this._writableState && this._writableState.destroyed; - // if node is not a blank node, then list head found - if(node['@id'].indexOf('_:') !== 0) { - break; - } - } + if (readableDestroyed || writableDestroyed) { + if (cb) { + cb(err); + } else if (err && (!this._writableState || !this._writableState.errorEmitted)) { + processNextTick(emitErrorNT, this, err); + } + return; + } - // the list is nested in another list - if(property === RDF_FIRST) { - // empty list - if(node['@id'] === RDF_NIL) { - // can't convert rdf:nil to a @list object because it would - // result in a list of lists which isn't supported - continue; - } + // we set destroyed to true before firing error callbacks in order + // to make it re-entrance safe in case destroy() is called within callbacks - // preserve list head - head = graphObject[head['@id']][RDF_REST][0]; - list.pop(); - listNodes.pop(); - } + if (this._readableState) { + this._readableState.destroyed = true; + } - // transform list into @list object - delete head['@id']; - head['@list'] = list.reverse(); - for(var j = 0; j < listNodes.length; ++j) { - delete graphObject[listNodes[j]]; + // if this is a duplex stream mark the writable part as destroyed as well + if (this._writableState) { + this._writableState.destroyed = true; + } + + this._destroy(err || null, function (err) { + if (!cb && err) { + processNextTick(emitErrorNT, _this, err); + if (_this._writableState) { + _this._writableState.errorEmitted = true; } + } else if (cb) { + cb(err); } + }); +} - delete nil.usages; +function undestroy() { + if (this._readableState) { + this._readableState.destroyed = false; + this._readableState.reading = false; + this._readableState.ended = false; + this._readableState.endEmitted = false; } - var result = []; - var subjects = Object.keys(defaultGraph).sort(); - for(var i = 0; i < subjects.length; ++i) { - var subject = subjects[i]; - var node = defaultGraph[subject]; - if(subject in graphMap) { - var graph = node['@graph'] = []; - var graphObject = graphMap[subject]; - var subjects_ = Object.keys(graphObject).sort(); - for(var si = 0; si < subjects_.length; ++si) { - var node_ = graphObject[subjects_[si]]; - // only add full subjects to top-level - if(!_isSubjectReference(node_)) { - graph.push(node_); - } - } - } - // only add full subjects to top-level - if(!_isSubjectReference(node)) { - result.push(node); - } + if (this._writableState) { + this._writableState.destroyed = false; + this._writableState.ended = false; + this._writableState.ending = false; + this._writableState.finished = false; + this._writableState.errorEmitted = false; } +} - callback(null, result); +function emitErrorNT(self, err) { + self.emit('error', err); +} + +module.exports = { + destroy: destroy, + undestroy: undestroy }; +},{"process-nextick-args":28}],25:[function(_dereq_,module,exports){ +module.exports = _dereq_('events').EventEmitter; -/** - * Outputs an RDF dataset for the expanded JSON-LD input. - * - * @param input the expanded JSON-LD input. - * @param options the RDF serialization options. - * - * @return the RDF dataset. - */ -Processor.prototype.toRDF = function(input, options) { - // create node map for default graph (and any named graphs) - var issuer = new IdentifierIssuer('_:b'); - var nodeMap = {'@default': {}}; - _createNodeMap(input, nodeMap, '@default', issuer); +},{"events":8}],26:[function(_dereq_,module,exports){ +(function (Buffer){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. - var dataset = {}; - var graphNames = Object.keys(nodeMap).sort(); - for(var i = 0; i < graphNames.length; ++i) { - var graphName = graphNames[i]; - // skip relative IRIs - if(graphName === '@default' || _isAbsoluteIri(graphName)) { - dataset[graphName] = _graphToRDF(nodeMap[graphName], issuer, options); - } - } - return dataset; -}; +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. -/** - * Processes a local context and returns a new active context. - * - * @param activeCtx the current active context. - * @param localCtx the local context to process. - * @param options the context processing options. - * - * @return the new active context. - */ -Processor.prototype.processContext = function(activeCtx, localCtx, options) { - // normalize local context to an array of @context objects - if(_isObject(localCtx) && '@context' in localCtx && - _isArray(localCtx['@context'])) { - localCtx = localCtx['@context']; +function isArray(arg) { + if (Array.isArray) { + return Array.isArray(arg); } - var ctxs = _isArray(localCtx) ? localCtx : [localCtx]; + return objectToString(arg) === '[object Array]'; +} +exports.isArray = isArray; - // no contexts in array, clone existing context - if(ctxs.length === 0) { - return activeCtx.clone(); - } +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; - // process each context in order, update active context - // on each iteration to ensure proper caching - var rval = activeCtx; - for(var i = 0; i < ctxs.length; ++i) { - var ctx = ctxs[i]; +function isNull(arg) { + return arg === null; +} +exports.isNull = isNull; - // reset to initial context - if(ctx === null) { - rval = activeCtx = _getInitialContext(options); - continue; - } +function isNullOrUndefined(arg) { + return arg == null; +} +exports.isNullOrUndefined = isNullOrUndefined; - // dereference @context key if present - if(_isObject(ctx) && '@context' in ctx) { - ctx = ctx['@context']; - } +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; - // context must be an object by now, all URLs retrieved before this call - if(!_isObject(ctx)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; @context must be an object.', - 'jsonld.SyntaxError', {code: 'invalid local context', context: ctx}); - } +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; - // get context from cache if available - if(jsonld.cache.activeCtx) { - var cached = jsonld.cache.activeCtx.get(activeCtx, ctx); - if(cached) { - rval = activeCtx = cached; - continue; - } - } +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; - // update active context and clone new one before updating - activeCtx = rval; - rval = rval.clone(); +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; - // define context mappings for keys in local context - var defined = {}; +function isRegExp(re) { + return objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; - // handle @base - if('@base' in ctx) { - var base = ctx['@base']; +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} +exports.isObject = isObject; - // clear base - if(base === null) { - base = null; - } else if(!_isString(base)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; the value of "@base" in a ' + - '@context must be a string or null.', - 'jsonld.SyntaxError', {code: 'invalid base IRI', context: ctx}); - } else if(base !== '' && !_isAbsoluteIri(base)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; the value of "@base" in a ' + - '@context must be an absolute IRI or the empty string.', - 'jsonld.SyntaxError', {code: 'invalid base IRI', context: ctx}); - } +function isDate(d) { + return objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; - if(base !== null) { - base = jsonld.url.parse(base || ''); - } - rval['@base'] = base; - defined['@base'] = true; - } +function isError(e) { + return (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; - // handle @vocab - if('@vocab' in ctx) { - var value = ctx['@vocab']; - if(value === null) { - delete rval['@vocab']; - } else if(!_isString(value)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; the value of "@vocab" in a ' + - '@context must be a string or null.', - 'jsonld.SyntaxError', {code: 'invalid vocab mapping', context: ctx}); - } else if(!_isAbsoluteIri(value)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; the value of "@vocab" in a ' + - '@context must be an absolute IRI.', - 'jsonld.SyntaxError', {code: 'invalid vocab mapping', context: ctx}); - } else { - rval['@vocab'] = value; - } - defined['@vocab'] = true; - } +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; - // handle @language - if('@language' in ctx) { - var value = ctx['@language']; - if(value === null) { - delete rval['@language']; - } else if(!_isString(value)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; the value of "@language" in a ' + - '@context must be a string or null.', - 'jsonld.SyntaxError', - {code: 'invalid default language', context: ctx}); - } else { - rval['@language'] = value.toLowerCase(); - } - defined['@language'] = true; - } +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; - // process all other keys - for(var key in ctx) { - _createTermDefinition(rval, ctx, key, defined); - } +exports.isBuffer = Buffer.isBuffer; - // cache result - if(jsonld.cache.activeCtx) { - jsonld.cache.activeCtx.set(activeCtx, ctx, rval); - } - } +function objectToString(o) { + return Object.prototype.toString.call(o); +} - return rval; -}; +}).call(this,{"isBuffer":_dereq_("../../../../insert-module-globals/node_modules/is-buffer/index.js")}) -/** - * Expands a language map. - * - * @param languageMap the language map to expand. - * - * @return the expanded language map. - */ -function _expandLanguageMap(languageMap) { - var rval = []; - var keys = Object.keys(languageMap).sort(); - for(var ki = 0; ki < keys.length; ++ki) { - var key = keys[ki]; - var val = languageMap[key]; - if(!_isArray(val)) { - val = [val]; - } - for(var vi = 0; vi < val.length; ++vi) { - var item = val[vi]; - if(item === null) { - // null values are allowed (8.5) but ignored (3.1) - continue; - } - if(!_isString(item)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; language map values must be strings.', - 'jsonld.SyntaxError', - {code: 'invalid language map value', languageMap: languageMap}); - } - rval.push({ - '@value': item, - '@language': key.toLowerCase() - }); +},{"../../../../insert-module-globals/node_modules/is-buffer/index.js":11}],27:[function(_dereq_,module,exports){ +arguments[4][7][0].apply(exports,arguments) +},{"dup":7}],28:[function(_dereq_,module,exports){ +(function (process){ +'use strict'; + +if (!process.version || + process.version.indexOf('v0.') === 0 || + process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) { + module.exports = nextTick; +} else { + module.exports = process.nextTick; +} + +function nextTick(fn, arg1, arg2, arg3) { + if (typeof fn !== 'function') { + throw new TypeError('"callback" argument must be a function'); + } + var len = arguments.length; + var args, i; + switch (len) { + case 0: + case 1: + return process.nextTick(fn); + case 2: + return process.nextTick(function afterTickOne() { + fn.call(null, arg1); + }); + case 3: + return process.nextTick(function afterTickTwo() { + fn.call(null, arg1, arg2); + }); + case 4: + return process.nextTick(function afterTickThree() { + fn.call(null, arg1, arg2, arg3); + }); + default: + args = new Array(len - 1); + i = 0; + while (i < args.length) { + args[i++] = arguments[i]; } + return process.nextTick(function afterTick() { + fn.apply(null, args); + }); } - return rval; } -/** - * Labels the blank nodes in the given value using the given IdentifierIssuer. - * - * @param issuer the IdentifierIssuer to use. - * @param element the element with blank nodes to rename. - * - * @return the element. - */ -function _labelBlankNodes(issuer, element) { - if(_isArray(element)) { - for(var i = 0; i < element.length; ++i) { - element[i] = _labelBlankNodes(issuer, element[i]); - } - } else if(_isList(element)) { - element['@list'] = _labelBlankNodes(issuer, element['@list']); - } else if(_isObject(element)) { - // relabel blank node - if(_isBlankNode(element)) { - element['@id'] = issuer.getId(element['@id']); - } +}).call(this,_dereq_('_process')) - // recursively apply to all keys - var keys = Object.keys(element).sort(); - for(var ki = 0; ki < keys.length; ++ki) { - var key = keys[ki]; - if(key !== '@id') { - element[key] = _labelBlankNodes(issuer, element[key]); - } - } +},{"_process":12}],29:[function(_dereq_,module,exports){ +/* eslint-disable node/no-deprecated-api */ +var buffer = _dereq_('buffer') +var Buffer = buffer.Buffer + +// alternative to using Object.keys for old browsers +function copyProps (src, dst) { + for (var key in src) { + dst[key] = src[key] } +} +if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { + module.exports = buffer +} else { + // Copy properties from require('buffer') + copyProps(buffer, exports) + exports.Buffer = SafeBuffer +} - return element; +function SafeBuffer (arg, encodingOrOffset, length) { + return Buffer(arg, encodingOrOffset, length) } -/** - * Expands the given value by using the coercion and keyword rules in the - * given context. - * - * @param activeCtx the active context to use. - * @param activeProperty the active property the value is associated with. - * @param value the value to expand. - * - * @return the expanded value. - */ -function _expandValue(activeCtx, activeProperty, value) { - // nothing to expand - if(value === null || value === undefined) { - return null; - } +// Copy static methods from Buffer +copyProps(Buffer, SafeBuffer) - // special-case expand @id and @type (skips '@id' expansion) - var expandedProperty = _expandIri(activeCtx, activeProperty, {vocab: true}); - if(expandedProperty === '@id') { - return _expandIri(activeCtx, value, {base: true}); - } else if(expandedProperty === '@type') { - return _expandIri(activeCtx, value, {vocab: true, base: true}); +SafeBuffer.from = function (arg, encodingOrOffset, length) { + if (typeof arg === 'number') { + throw new TypeError('Argument must not be a number') } + return Buffer(arg, encodingOrOffset, length) +} - // get type definition from context - var type = jsonld.getContextValue(activeCtx, activeProperty, '@type'); - - // do @id expansion (automatic for @graph) - if(type === '@id' || (expandedProperty === '@graph' && _isString(value))) { - return {'@id': _expandIri(activeCtx, value, {base: true})}; +SafeBuffer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') } - // do @id expansion w/vocab - if(type === '@vocab') { - return {'@id': _expandIri(activeCtx, value, {vocab: true, base: true})}; + var buf = Buffer(size) + if (fill !== undefined) { + if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + } else { + buf.fill(0) } + return buf +} - // do not expand keyword values - if(_isKeyword(expandedProperty)) { - return value; +SafeBuffer.allocUnsafe = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') } + return Buffer(size) +} - var rval = {}; - - if(type !== null) { - // other type - rval['@type'] = type; - } else if(_isString(value)) { - // check for language tagging for strings - var language = jsonld.getContextValue( - activeCtx, activeProperty, '@language'); - if(language !== null) { - rval['@language'] = language; - } - } - // do conversion of values that aren't basic JSON types to strings - if(['boolean', 'number', 'string'].indexOf(typeof value) === -1) { - value = value.toString(); +SafeBuffer.allocUnsafeSlow = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') } - rval['@value'] = value; - - return rval; + return buffer.SlowBuffer(size) } -/** - * Creates an array of RDF triples for the given graph. - * - * @param graph the graph to create RDF triples for. - * @param issuer a IdentifierIssuer for assigning blank node names. - * @param options the RDF serialization options. - * - * @return the array of RDF triples for the given graph. - */ -function _graphToRDF(graph, issuer, options) { - var rval = []; - - var ids = Object.keys(graph).sort(); - for(var i = 0; i < ids.length; ++i) { - var id = ids[i]; - var node = graph[id]; - var properties = Object.keys(node).sort(); - for(var pi = 0; pi < properties.length; ++pi) { - var property = properties[pi]; - var items = node[property]; - if(property === '@type') { - property = RDF_TYPE; - } else if(_isKeyword(property)) { - continue; - } - - for(var ii = 0; ii < items.length; ++ii) { - var item = items[ii]; - - // RDF subject - var subject = {}; - subject.type = (id.indexOf('_:') === 0) ? 'blank node' : 'IRI'; - subject.value = id; - - // skip relative IRI subjects - if(!_isAbsoluteIri(id)) { - continue; - } - - // RDF predicate - var predicate = {}; - predicate.type = (property.indexOf('_:') === 0) ? 'blank node' : 'IRI'; - predicate.value = property; +},{"buffer":4}],30:[function(_dereq_,module,exports){ +'use strict'; - // skip relative IRI predicates - if(!_isAbsoluteIri(property)) { - continue; - } +var Buffer = _dereq_('safe-buffer').Buffer; - // skip blank node predicates unless producing generalized RDF - if(predicate.type === 'blank node' && !options.produceGeneralizedRdf) { - continue; - } +var isEncoding = Buffer.isEncoding || function (encoding) { + encoding = '' + encoding; + switch (encoding && encoding.toLowerCase()) { + case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw': + return true; + default: + return false; + } +}; - // convert @list to triples - if(_isList(item)) { - _listToRDF(item['@list'], issuer, subject, predicate, rval); - } else { - // convert value or node object to triple - var object = _objectToRDF(item); - // skip null objects (they are relative IRIs) - if(object) { - rval.push({subject: subject, predicate: predicate, object: object}); - } - } - } +function _normalizeEncoding(enc) { + if (!enc) return 'utf8'; + var retried; + while (true) { + switch (enc) { + case 'utf8': + case 'utf-8': + return 'utf8'; + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return 'utf16le'; + case 'latin1': + case 'binary': + return 'latin1'; + case 'base64': + case 'ascii': + case 'hex': + return enc; + default: + if (retried) return; // undefined + enc = ('' + enc).toLowerCase(); + retried = true; } } +}; - return rval; +// Do not cache `Buffer.isEncoding` when checking encoding names as some +// modules monkey-patch it to support additional encodings +function normalizeEncoding(enc) { + var nenc = _normalizeEncoding(enc); + if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc); + return nenc || enc; } -/** - * Converts a @list value into linked list of blank node RDF triples - * (an RDF collection). - * - * @param list the @list value. - * @param issuer a IdentifierIssuer for assigning blank node names. - * @param subject the subject for the head of the list. - * @param predicate the predicate for the head of the list. - * @param triples the array of triples to append to. - */ -function _listToRDF(list, issuer, subject, predicate, triples) { - var first = {type: 'IRI', value: RDF_FIRST}; - var rest = {type: 'IRI', value: RDF_REST}; - var nil = {type: 'IRI', value: RDF_NIL}; - - for(var i = 0; i < list.length; ++i) { - var item = list[i]; - - var blankNode = {type: 'blank node', value: issuer.getId()}; - triples.push({subject: subject, predicate: predicate, object: blankNode}); - - subject = blankNode; - predicate = first; - var object = _objectToRDF(item); - - // skip null objects (they are relative IRIs) - if(object) { - triples.push({subject: subject, predicate: predicate, object: object}); - } +// StringDecoder provides an interface for efficiently splitting a series of +// buffers into a series of JS strings without breaking apart multi-byte +// characters. +exports.StringDecoder = StringDecoder; +function StringDecoder(encoding) { + this.encoding = normalizeEncoding(encoding); + var nb; + switch (this.encoding) { + case 'utf16le': + this.text = utf16Text; + this.end = utf16End; + nb = 4; + break; + case 'utf8': + this.fillLast = utf8FillLast; + nb = 4; + break; + case 'base64': + this.text = base64Text; + this.end = base64End; + nb = 3; + break; + default: + this.write = simpleWrite; + this.end = simpleEnd; + return; + } + this.lastNeed = 0; + this.lastTotal = 0; + this.lastChar = Buffer.allocUnsafe(nb); +} - predicate = rest; +StringDecoder.prototype.write = function (buf) { + if (buf.length === 0) return ''; + var r; + var i; + if (this.lastNeed) { + r = this.fillLast(buf); + if (r === undefined) return ''; + i = this.lastNeed; + this.lastNeed = 0; + } else { + i = 0; } + if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i); + return r || ''; +}; - triples.push({subject: subject, predicate: predicate, object: nil}); -} +StringDecoder.prototype.end = utf8End; -/** - * Converts a JSON-LD value object to an RDF literal or a JSON-LD string or - * node object to an RDF resource. - * - * @param item the JSON-LD value or node object. - * - * @return the RDF literal or RDF resource. - */ -function _objectToRDF(item) { - var object = {}; +// Returns only complete characters in a Buffer +StringDecoder.prototype.text = utf8Text; - // convert value object to RDF - if(_isValue(item)) { - object.type = 'literal'; - var value = item['@value']; - var datatype = item['@type'] || null; +// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer +StringDecoder.prototype.fillLast = function (buf) { + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); + } + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length); + this.lastNeed -= buf.length; +}; - // convert to XSD datatypes as appropriate - if(_isBoolean(value)) { - object.value = value.toString(); - object.datatype = datatype || XSD_BOOLEAN; - } else if(_isDouble(value) || datatype === XSD_DOUBLE) { - if(!_isDouble(value)) { - value = parseFloat(value); +// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a +// continuation byte. +function utf8CheckByte(byte) { + if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4; + return -1; +} + +// Checks at most 3 bytes at the end of a Buffer in order to detect an +// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4) +// needed to complete the UTF-8 character (if applicable) are returned. +function utf8CheckIncomplete(self, buf, i) { + var j = buf.length - 1; + if (j < i) return 0; + var nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 1; + return nb; + } + if (--j < i) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 2; + return nb; + } + if (--j < i) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) { + if (nb === 2) nb = 0;else self.lastNeed = nb - 3; + } + return nb; + } + return 0; +} + +// Validates as many continuation bytes for a multi-byte UTF-8 character as +// needed or are available. If we see a non-continuation byte where we expect +// one, we "replace" the validated continuation bytes we've seen so far with +// UTF-8 replacement characters ('\ufffd'), to match v8's UTF-8 decoding +// behavior. The continuation byte check is included three times in the case +// where all of the continuation bytes for a character exist in the same buffer. +// It is also done this way as a slight performance increase instead of using a +// loop. +function utf8CheckExtraBytes(self, buf, p) { + if ((buf[0] & 0xC0) !== 0x80) { + self.lastNeed = 0; + return '\ufffd'.repeat(p); + } + if (self.lastNeed > 1 && buf.length > 1) { + if ((buf[1] & 0xC0) !== 0x80) { + self.lastNeed = 1; + return '\ufffd'.repeat(p + 1); + } + if (self.lastNeed > 2 && buf.length > 2) { + if ((buf[2] & 0xC0) !== 0x80) { + self.lastNeed = 2; + return '\ufffd'.repeat(p + 2); } - // canonical double representation - object.value = value.toExponential(15).replace(/(\d)0*e\+?/, '$1E'); - object.datatype = datatype || XSD_DOUBLE; - } else if(_isNumber(value)) { - object.value = value.toFixed(0); - object.datatype = datatype || XSD_INTEGER; - } else if('@language' in item) { - object.value = value; - object.datatype = datatype || RDF_LANGSTRING; - object.language = item['@language']; - } else { - object.value = value; - object.datatype = datatype || XSD_STRING; } - } else { - // convert string/node object to RDF - var id = _isObject(item) ? item['@id'] : item; - object.type = (id.indexOf('_:') === 0) ? 'blank node' : 'IRI'; - object.value = id; } +} - // skip relative IRIs - if(object.type === 'IRI' && !_isAbsoluteIri(object.value)) { - return null; +// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer. +function utf8FillLast(buf) { + var p = this.lastTotal - this.lastNeed; + var r = utf8CheckExtraBytes(this, buf, p); + if (r !== undefined) return r; + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, p, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); } + buf.copy(this.lastChar, p, 0, buf.length); + this.lastNeed -= buf.length; +} - return object; +// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a +// partial character, the character's bytes are buffered until the required +// number of bytes are available. +function utf8Text(buf, i) { + var total = utf8CheckIncomplete(this, buf, i); + if (!this.lastNeed) return buf.toString('utf8', i); + this.lastTotal = total; + var end = buf.length - (total - this.lastNeed); + buf.copy(this.lastChar, 0, end); + return buf.toString('utf8', i, end); +} + +// For UTF-8, a replacement character for each buffered byte of a (partial) +// character needs to be added to the output. +function utf8End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + '\ufffd'.repeat(this.lastTotal - this.lastNeed); + return r; +} + +// UTF-16LE typically needs two bytes per character, but even if we have an even +// number of bytes available, we need to check if we end on a leading/high +// surrogate. In that case, we need to wait for the next two bytes in order to +// decode the last character properly. +function utf16Text(buf, i) { + if ((buf.length - i) % 2 === 0) { + var r = buf.toString('utf16le', i); + if (r) { + var c = r.charCodeAt(r.length - 1); + if (c >= 0xD800 && c <= 0xDBFF) { + this.lastNeed = 2; + this.lastTotal = 4; + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + return r.slice(0, -1); + } + } + return r; + } + this.lastNeed = 1; + this.lastTotal = 2; + this.lastChar[0] = buf[buf.length - 1]; + return buf.toString('utf16le', i, buf.length - 1); +} + +// For UTF-16LE we do not explicitly append special replacement characters if we +// end on a partial character, we simply let v8 handle that. +function utf16End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) { + var end = this.lastTotal - this.lastNeed; + return r + this.lastChar.toString('utf16le', 0, end); + } + return r; +} + +function base64Text(buf, i) { + var n = (buf.length - i) % 3; + if (n === 0) return buf.toString('base64', i); + this.lastNeed = 3 - n; + this.lastTotal = 3; + if (n === 1) { + this.lastChar[0] = buf[buf.length - 1]; + } else { + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + } + return buf.toString('base64', i, buf.length - n); +} + +function base64End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed); + return r; +} + +// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex) +function simpleWrite(buf) { + return buf.toString(this.encoding); +} + +function simpleEnd(buf) { + return buf && buf.length ? this.write(buf) : ''; } +},{"safe-buffer":29}],31:[function(_dereq_,module,exports){ +(function (global){ /** - * Converts an RDF triple object to a JSON-LD object. + * Module exports. + */ + +module.exports = deprecate; + +/** + * Mark that a method should not be used. + * Returns a modified function which warns once by default. * - * @param o the RDF triple object to convert. - * @param useNativeTypes true to output native types, false not to. + * If `localStorage.noDeprecation = true` is set, then it is a no-op. * - * @return the JSON-LD object. + * If `localStorage.throwDeprecation = true` is set, then deprecated functions + * will throw an Error when invoked. + * + * If `localStorage.traceDeprecation = true` is set, then deprecated functions + * will invoke `console.trace()` instead of `console.error()`. + * + * @param {Function} fn - the function to deprecate + * @param {String} msg - the string to print to the console when `fn` is invoked + * @returns {Function} a new "deprecated" version of `fn` + * @api public */ -function _RDFToObject(o, useNativeTypes) { - // convert IRI/blank node object to JSON-LD - if(o.type === 'IRI' || o.type === 'blank node') { - return {'@id': o.value}; - } - // convert literal to JSON-LD - var rval = {'@value': o.value}; +function deprecate (fn, msg) { + if (config('noDeprecation')) { + return fn; + } - // add language - if(o.language) { - rval['@language'] = o.language; - } else { - var type = o.datatype; - if(!type) { - type = XSD_STRING; - } - // use native types for certain xsd types - if(useNativeTypes) { - if(type === XSD_BOOLEAN) { - if(rval['@value'] === 'true') { - rval['@value'] = true; - } else if(rval['@value'] === 'false') { - rval['@value'] = false; - } - } else if(_isNumeric(rval['@value'])) { - if(type === XSD_INTEGER) { - var i = parseInt(rval['@value'], 10); - if(i.toFixed(0) === rval['@value']) { - rval['@value'] = i; - } - } else if(type === XSD_DOUBLE) { - rval['@value'] = parseFloat(rval['@value']); - } - } - // do not add native type - if([XSD_BOOLEAN, XSD_INTEGER, XSD_DOUBLE, XSD_STRING] - .indexOf(type) === -1) { - rval['@type'] = type; + var warned = false; + function deprecated() { + if (!warned) { + if (config('throwDeprecation')) { + throw new Error(msg); + } else if (config('traceDeprecation')) { + console.trace(msg); + } else { + console.warn(msg); } - } else if(type !== XSD_STRING) { - rval['@type'] = type; + warned = true; } + return fn.apply(this, arguments); } - return rval; + return deprecated; } /** - * Compares two RDF triples for equality. - * - * @param t1 the first triple. - * @param t2 the second triple. + * Checks `localStorage` for boolean values for the given `name`. * - * @return true if the triples are the same, false if not. + * @param {String} name + * @returns {Boolean} + * @api private */ -function _compareRDFTriples(t1, t2) { - var attrs = ['subject', 'predicate', 'object']; - for(var i = 0; i < attrs.length; ++i) { - var attr = attrs[i]; - if(t1[attr].type !== t2[attr].type || t1[attr].value !== t2[attr].value) { - return false; - } - } - if(t1.object.language !== t2.object.language) { - return false; - } - if(t1.object.datatype !== t2.object.datatype) { + +function config (name) { + // accessing global.localStorage can trigger a DOMException in sandboxed iframes + try { + if (!global.localStorage) return false; + } catch (_) { return false; } - return true; + var val = global.localStorage[name]; + if (null == val) return false; + return String(val).toLowerCase() === 'true'; } -/////////////////////////////// DEFINE URDNA2015 ////////////////////////////// +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -var URDNA2015 = (function() { +},{}],32:[function(_dereq_,module,exports){ +module.exports = _dereq_('./readable').PassThrough -var POSITIONS = {'subject': 's', 'object': 'o', 'name': 'g'}; +},{"./readable":33}],33:[function(_dereq_,module,exports){ +exports = module.exports = _dereq_('./lib/_stream_readable.js'); +exports.Stream = exports; +exports.Readable = exports; +exports.Writable = _dereq_('./lib/_stream_writable.js'); +exports.Duplex = _dereq_('./lib/_stream_duplex.js'); +exports.Transform = _dereq_('./lib/_stream_transform.js'); +exports.PassThrough = _dereq_('./lib/_stream_passthrough.js'); -var Normalize = function(options) { - options = options || {}; - this.name = 'URDNA2015'; - this.options = options; - this.blankNodeInfo = {}; - this.hashToBlankNodes = {}; - this.canonicalIssuer = new IdentifierIssuer('_:c14n'); - this.quads = []; - this.schedule = {}; - if('maxCallStackDepth' in options) { - this.schedule.MAX_DEPTH = options.maxCallStackDepth; - } else { - this.schedule.MAX_DEPTH = 500; - } - if('maxTotalCallStackDepth' in options) { - this.schedule.MAX_TOTAL_DEPTH = options.maxCallStackDepth; - } else { - this.schedule.MAX_TOTAL_DEPTH = 0xFFFFFFFF; - } - this.schedule.depth = 0; - this.schedule.totalDepth = 0; - if('timeSlice' in options) { - this.schedule.timeSlice = options.timeSlice; - } else { - // milliseconds - this.schedule.timeSlice = 10; - } -}; +},{"./lib/_stream_duplex.js":18,"./lib/_stream_passthrough.js":19,"./lib/_stream_readable.js":20,"./lib/_stream_transform.js":21,"./lib/_stream_writable.js":22}],34:[function(_dereq_,module,exports){ +module.exports = _dereq_('./readable').Transform -// do some work in a time slice, but in serial -Normalize.prototype.doWork = function(fn, callback) { - var schedule = this.schedule; +},{"./readable":33}],35:[function(_dereq_,module,exports){ +module.exports = _dereq_('./lib/_stream_writable.js'); - if(schedule.totalDepth >= schedule.MAX_TOTAL_DEPTH) { - return callback(new Error( - 'Maximum total call stack depth exceeded; normalization aborting.')); - } +},{"./lib/_stream_writable.js":22}],36:[function(_dereq_,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. - (function work() { - if(schedule.depth === schedule.MAX_DEPTH) { - // stack too deep, run on next tick - schedule.depth = 0; - schedule.running = false; - return jsonld.nextTick(work); - } +module.exports = Stream; - // if not yet running, force run - var now = new Date().getTime(); - if(!schedule.running) { - schedule.start = new Date().getTime(); - schedule.deadline = schedule.start + schedule.timeSlice; - } +var EE = _dereq_('events').EventEmitter; +var inherits = _dereq_('inherits'); - // TODO: should also include an estimate of expectedWorkTime - if(now < schedule.deadline) { - schedule.running = true; - schedule.depth++; - schedule.totalDepth++; - return fn(function(err, result) { - schedule.depth--; - schedule.totalDepth--; - callback(err, result); - }); - } +inherits(Stream, EE); +Stream.Readable = _dereq_('readable-stream/readable.js'); +Stream.Writable = _dereq_('readable-stream/writable.js'); +Stream.Duplex = _dereq_('readable-stream/duplex.js'); +Stream.Transform = _dereq_('readable-stream/transform.js'); +Stream.PassThrough = _dereq_('readable-stream/passthrough.js'); - // not enough time left in this slice, run after letting browser - // do some other things - schedule.depth = 0; - schedule.running = false; - jsonld.setImmediate(work); - })(); -}; +// Backwards-compat with node 0.4.x +Stream.Stream = Stream; -// asynchronously loop -Normalize.prototype.forEach = function(iterable, fn, callback) { - var self = this; - var iterator; - var idx = 0; - var length; - if(_isArray(iterable)) { - length = iterable.length; - iterator = function() { - if(idx === length) { - return false; - } - iterator.value = iterable[idx++]; - iterator.key = idx; - return true; - }; - } else { - var keys = Object.keys(iterable); - length = keys.length; - iterator = function() { - if(idx === length) { - return false; - } - iterator.key = keys[idx++]; - iterator.value = iterable[iterator.key]; - return true; - }; - } - (function iterate(err, result) { - if(err) { - return callback(err); - } - if(iterator()) { - return self.doWork(function() { - fn(iterator.value, iterator.key, iterate); - }); - } - callback(); - })(); -}; -// asynchronous waterfall -Normalize.prototype.waterfall = function(fns, callback) { - var self = this; - self.forEach(fns, function(fn, idx, callback) { - self.doWork(fn, callback); - }, callback); -}; +// old-style streams. Note that the pipe method (the only relevant +// part of this class) is overridden in the Readable class. -// asynchronous while -Normalize.prototype.whilst = function(condition, fn, callback) { - var self = this; - (function loop(err) { - if(err) { - return callback(err); - } - if(!condition()) { - return callback(); - } - self.doWork(fn, loop); - })(); -}; +function Stream() { + EE.call(this); +} -// 4.4) Normalization Algorithm -Normalize.prototype.main = function(dataset, callback) { - var self = this; - self.schedule.start = new Date().getTime(); - var result; +Stream.prototype.pipe = function(dest, options) { + var source = this; - // handle invalid output format - if(self.options.format) { - if(self.options.format !== 'application/nquads') { - return callback(new JsonLdError( - 'Unknown output format.', - 'jsonld.UnknownFormat', {format: self.options.format})); + function ondata(chunk) { + if (dest.writable) { + if (false === dest.write(chunk) && source.pause) { + source.pause(); + } } } - // 1) Create the normalization state. - - // Note: Optimize by generating non-normalized blank node map concurrently. - var nonNormalized = {}; + source.on('data', ondata); - self.waterfall([ - function(callback) { - // 2) For every quad in input dataset: - self.forEach(dataset, function(triples, graphName, callback) { - if(graphName === '@default') { - graphName = null; - } - self.forEach(triples, function(quad, idx, callback) { - if(graphName !== null) { - if(graphName.indexOf('_:') === 0) { - quad.name = {type: 'blank node', value: graphName}; - } else { - quad.name = {type: 'IRI', value: graphName}; - } - } - self.quads.push(quad); + function ondrain() { + if (source.readable && source.resume) { + source.resume(); + } + } - // 2.1) For each blank node that occurs in the quad, add a reference - // to the quad using the blank node identifier in the blank node to - // quads map, creating a new entry if necessary. - self.forEachComponent(quad, function(component) { - if(component.type !== 'blank node') { - return; - } - var id = component.value; - if(id in self.blankNodeInfo) { - self.blankNodeInfo[id].quads.push(quad); - } else { - nonNormalized[id] = true; - self.blankNodeInfo[id] = {quads: [quad]}; - } - }); - callback(); - }, callback); - }, callback); - }, - function(callback) { - // 3) Create a list of non-normalized blank node identifiers - // non-normalized identifiers and populate it using the keys from the - // blank node to quads map. - // Note: We use a map here and it was generated during step 2. + dest.on('drain', ondrain); - // 4) Initialize simple, a boolean flag, to true. - var simple = true; + // If the 'end' option is not supplied, dest.end() will be called when + // source gets the 'end' or 'close' events. Only dest.end() once. + if (!dest._isStdio && (!options || options.end !== false)) { + source.on('end', onend); + source.on('close', onclose); + } - // 5) While simple is true, issue canonical identifiers for blank nodes: - self.whilst(function() { return simple; }, function(callback) { - // 5.1) Set simple to false. - simple = false; + var didOnEnd = false; + function onend() { + if (didOnEnd) return; + didOnEnd = true; - // 5.2) Clear hash to blank nodes map. - self.hashToBlankNodes = {}; + dest.end(); + } - self.waterfall([ - function(callback) { - // 5.3) For each blank node identifier identifier in non-normalized - // identifiers: - self.forEach(nonNormalized, function(value, id, callback) { - // 5.3.1) Create a hash, hash, according to the Hash First Degree - // Quads algorithm. - self.hashFirstDegreeQuads(id, function(err, hash) { - if(err) { - return callback(err); - } - // 5.3.2) Add hash and identifier to hash to blank nodes map, - // creating a new entry if necessary. - if(hash in self.hashToBlankNodes) { - self.hashToBlankNodes[hash].push(id); - } else { - self.hashToBlankNodes[hash] = [id]; - } - callback(); - }); - }, callback); - }, - function(callback) { - // 5.4) For each hash to identifier list mapping in hash to blank - // nodes map, lexicographically-sorted by hash: - var hashes = Object.keys(self.hashToBlankNodes).sort(); - self.forEach(hashes, function(hash, i, callback) { - // 5.4.1) If the length of identifier list is greater than 1, - // continue to the next mapping. - var idList = self.hashToBlankNodes[hash]; - if(idList.length > 1) { - return callback(); - } - // 5.4.2) Use the Issue Identifier algorithm, passing canonical - // issuer and the single blank node identifier in identifier - // list, identifier, to issue a canonical replacement identifier - // for identifier. - // TODO: consider changing `getId` to `issue` - var id = idList[0]; - self.canonicalIssuer.getId(id); + function onclose() { + if (didOnEnd) return; + didOnEnd = true; - // 5.4.3) Remove identifier from non-normalized identifiers. - delete nonNormalized[id]; + if (typeof dest.destroy === 'function') dest.destroy(); + } - // 5.4.4) Remove hash from the hash to blank nodes map. - delete self.hashToBlankNodes[hash]; + // don't leave dangling pipes when there are errors. + function onerror(er) { + cleanup(); + if (EE.listenerCount(this, 'error') === 0) { + throw er; // Unhandled stream error in pipe. + } + } - // 5.4.5) Set simple to true. - simple = true; - callback(); - }, callback); - } - ], callback); - }, callback); - }, - function(callback) { - // 6) For each hash to identifier list mapping in hash to blank nodes map, - // lexicographically-sorted by hash: - var hashes = Object.keys(self.hashToBlankNodes).sort(); - self.forEach(hashes, function(hash, idx, callback) { - // 6.1) Create hash path list where each item will be a result of - // running the Hash N-Degree Quads algorithm. - var hashPathList = []; + source.on('error', onerror); + dest.on('error', onerror); - // 6.2) For each blank node identifier identifier in identifier list: - var idList = self.hashToBlankNodes[hash]; - self.waterfall([ - function(callback) { - self.forEach(idList, function(id, idx, callback) { - // 6.2.1) If a canonical identifier has already been issued for - // identifier, continue to the next identifier. - if(self.canonicalIssuer.hasId(id)) { - return callback(); - } + // remove all the event listeners that were added. + function cleanup() { + source.removeListener('data', ondata); + dest.removeListener('drain', ondrain); - // 6.2.2) Create temporary issuer, an identifier issuer - // initialized with the prefix _:b. - var issuer = new IdentifierIssuer('_:b'); + source.removeListener('end', onend); + source.removeListener('close', onclose); - // 6.2.3) Use the Issue Identifier algorithm, passing temporary - // issuer and identifier, to issue a new temporary blank node - // identifier for identifier. - issuer.getId(id); + source.removeListener('error', onerror); + dest.removeListener('error', onerror); - // 6.2.4) Run the Hash N-Degree Quads algorithm, passing - // temporary issuer, and append the result to the hash path list. - self.hashNDegreeQuads(id, issuer, function(err, result) { - if(err) { - return callback(err); - } - hashPathList.push(result); - callback(); - }); - }, callback); - }, - function(callback) { - // 6.3) For each result in the hash path list, - // lexicographically-sorted by the hash in result: - hashPathList.sort(function(a, b) { - return (a.hash < b.hash) ? -1 : ((a.hash > b.hash) ? 1 : 0); - }); - self.forEach(hashPathList, function(result, idx, callback) { - // 6.3.1) For each blank node identifier, existing identifier, - // that was issued a temporary identifier by identifier issuer - // in result, issue a canonical identifier, in the same order, - // using the Issue Identifier algorithm, passing canonical - // issuer and existing identifier. - for(var existing in result.issuer.existing) { - self.canonicalIssuer.getId(existing); - } - callback(); - }, callback); - } - ], callback); - }, callback); - }, function(callback) { - /* Note: At this point all blank nodes in the set of RDF quads have been - assigned canonical identifiers, which have been stored in the canonical - issuer. Here each quad is updated by assigning each of its blank nodes - its new identifier. */ + source.removeListener('end', cleanup); + source.removeListener('close', cleanup); - // 7) For each quad, quad, in input dataset: - var normalized = []; - self.waterfall([ - function(callback) { - self.forEach(self.quads, function(quad, idx, callback) { - // 7.1) Create a copy, quad copy, of quad and replace any existing - // blank node identifiers using the canonical identifiers - // previously issued by canonical issuer. - // Note: We optimize away the copy here. - self.forEachComponent(quad, function(component) { - if(component.type === 'blank node' && - component.value.indexOf(self.canonicalIssuer.prefix) !== 0) { - component.value = self.canonicalIssuer.getId(component.value); - } - }); - // 7.2) Add quad copy to the normalized dataset. - normalized.push(_toNQuad(quad)); - callback(); - }, callback); - }, - function(callback) { - // sort normalized output - normalized.sort(); + dest.removeListener('close', cleanup); + } - // 8) Return the normalized dataset. - if(self.options.format === 'application/nquads') { - result = normalized.join(''); - return callback(); - } + source.on('end', cleanup); + source.on('close', cleanup); - result = _parseNQuads(normalized.join('')); - callback(); - } - ], callback); - } - ], function(err) { - callback(err, result); - }); -}; + dest.on('close', cleanup); -// 4.6) Hash First Degree Quads -Normalize.prototype.hashFirstDegreeQuads = function(id, callback) { - var self = this; + dest.emit('pipe', source); - // return cached hash - var info = self.blankNodeInfo[id]; - if('hash' in info) { - return callback(null, info.hash); - } + // Allow for unix-like usage: A.pipe(B).pipe(C) + return dest; +}; - // 1) Initialize nquads to an empty list. It will be used to store quads in - // N-Quads format. - var nquads = []; +},{"events":8,"inherits":10,"readable-stream/duplex.js":17,"readable-stream/passthrough.js":32,"readable-stream/readable.js":33,"readable-stream/transform.js":34,"readable-stream/writable.js":35}],37:[function(_dereq_,module,exports){ +var ClientRequest = _dereq_('./lib/request') +var extend = _dereq_('xtend') +var statusCodes = _dereq_('builtin-status-codes') +var url = _dereq_('url') - // 2) Get the list of quads quads associated with the reference blank node - // identifier in the blank node to quads map. - var quads = info.quads; +var http = exports - // 3) For each quad quad in quads: - self.forEach(quads, function(quad, idx, callback) { - // 3.1) Serialize the quad in N-Quads format with the following special - // rule: +http.request = function (opts, cb) { + if (typeof opts === 'string') + opts = url.parse(opts) + else + opts = extend(opts) - // 3.1.1) If any component in quad is an blank node, then serialize it - // using a special identifier as follows: - var copy = {predicate: quad.predicate}; - self.forEachComponent(quad, function(component, key) { - // 3.1.2) If the blank node's existing blank node identifier matches the - // reference blank node identifier then use the blank node identifier _:a, - // otherwise, use the blank node identifier _:z. - copy[key] = self.modifyFirstDegreeComponent(id, component, key); - }); - nquads.push(_toNQuad(copy)); - callback(); - }, function(err) { - if(err) { - return callback(err); - } - // 4) Sort nquads in lexicographical order. - nquads.sort(); + var protocol = opts.protocol || '' + var host = opts.hostname || opts.host + var port = opts.port + var path = opts.path || '/' - // 5) Return the hash that results from passing the sorted, joined nquads - // through the hash algorithm. - info.hash = NormalizeHash.hashNQuads(self.name, nquads); - callback(null, info.hash); - }); -}; + // Necessary for IPv6 addresses + if (host && host.indexOf(':') !== -1) + host = '[' + host + ']' -// helper for modifying component during Hash First Degree Quads -Normalize.prototype.modifyFirstDegreeComponent = function(id, component) { - if(component.type !== 'blank node') { - return component; - } - component = _clone(component); - component.value = (component.value === id ? '_:a' : '_:z'); - return component; -}; + // This may be a relative url. The browser should always be able to interpret it correctly. + opts.url = (host ? (protocol + '//' + host) : '') + (port ? ':' + port : '') + path + opts.method = (opts.method || 'GET').toUpperCase() + opts.headers = opts.headers || {} -// 4.7) Hash Related Blank Node -Normalize.prototype.hashRelatedBlankNode = function( - related, quad, issuer, position, callback) { - var self = this; + // Also valid opts.auth, opts.mode - // 1) Set the identifier to use for related, preferring first the canonical - // identifier for related if issued, second the identifier issued by issuer - // if issued, and last, if necessary, the result of the Hash First Degree - // Quads algorithm, passing related. - var id; - self.waterfall([ - function(callback) { - if(self.canonicalIssuer.hasId(related)) { - id = self.canonicalIssuer.getId(related); - return callback(); - } - if(issuer.hasId(related)) { - id = issuer.getId(related); - return callback(); - } - self.hashFirstDegreeQuads(related, function(err, hash) { - if(err) { - return callback(err); - } - id = hash; - callback(); - }); - } - ], function(err) { - if(err) { - return callback(err); - } + var req = new ClientRequest(opts) + if (cb) + req.on('response', cb) + return req +} - // 2) Initialize a string input to the value of position. - // Note: We use a hash object instead. - var md = new NormalizeHash(self.name); - md.update(position); +http.get = function get (opts, cb) { + var req = http.request(opts, cb) + req.end() + return req +} - // 3) If position is not g, append <, the value of the predicate in quad, - // and > to input. - if(position !== 'g') { - md.update(self.getRelatedPredicate(quad)); - } +http.Agent = function () {} +http.Agent.defaultMaxSockets = 4 - // 4) Append identifier to input. - md.update(id); +http.STATUS_CODES = statusCodes - // 5) Return the hash that results from passing input through the hash - // algorithm. - return callback(null, md.digest()); - }); -}; +http.METHODS = [ + 'CHECKOUT', + 'CONNECT', + 'COPY', + 'DELETE', + 'GET', + 'HEAD', + 'LOCK', + 'M-SEARCH', + 'MERGE', + 'MKACTIVITY', + 'MKCOL', + 'MOVE', + 'NOTIFY', + 'OPTIONS', + 'PATCH', + 'POST', + 'PROPFIND', + 'PROPPATCH', + 'PURGE', + 'PUT', + 'REPORT', + 'SEARCH', + 'SUBSCRIBE', + 'TRACE', + 'UNLOCK', + 'UNSUBSCRIBE' +] +},{"./lib/request":39,"builtin-status-codes":41,"url":48,"xtend":52}],38:[function(_dereq_,module,exports){ +(function (global){ +exports.fetch = isFunction(global.fetch) && isFunction(global.ReadableByteStream) -// helper for getting a related predicate -Normalize.prototype.getRelatedPredicate = function(quad) { - return '<' + quad.predicate.value + '>'; -}; +exports.blobConstructor = false +try { + new Blob([new ArrayBuffer(1)]) + exports.blobConstructor = true +} catch (e) {} -// 4.8) Hash N-Degree Quads -Normalize.prototype.hashNDegreeQuads = function(id, issuer, callback) { - var self = this; +var xhr = new global.XMLHttpRequest() +// If location.host is empty, e.g. if this page/worker was loaded +// from a Blob, then use example.com to avoid an error +xhr.open('GET', global.location.host ? '/' : 'https://example.com') - // 1) Create a hash to related blank nodes map for storing hashes that - // identify related blank nodes. - // Note: 2) and 3) handled within `createHashToRelated` - var hashToRelated; - var md = new NormalizeHash(self.name); - self.waterfall([ - function(callback) { - self.createHashToRelated(id, issuer, function(err, result) { - if(err) { - return callback(err); - } - hashToRelated = result; - callback(); - }); - }, - function(callback) { - // 4) Create an empty string, data to hash. - // Note: We created a hash object `md` above instead. +function checkTypeSupport (type) { + try { + xhr.responseType = type + return xhr.responseType === type + } catch (e) {} + return false +} - // 5) For each related hash to blank node list mapping in hash to related - // blank nodes map, sorted lexicographically by related hash: - var hashes = Object.keys(hashToRelated).sort(); - self.forEach(hashes, function(hash, idx, callback) { - // 5.1) Append the related hash to the data to hash. - md.update(hash); +// For some strange reason, Safari 7.0 reports typeof global.ArrayBuffer === 'object'. +// Safari 7.1 appears to have fixed this bug. +var haveArrayBuffer = typeof global.ArrayBuffer !== 'undefined' +var haveSlice = haveArrayBuffer && isFunction(global.ArrayBuffer.prototype.slice) - // 5.2) Create a string chosen path. - var chosenPath = ''; +exports.arraybuffer = haveArrayBuffer && checkTypeSupport('arraybuffer') +// These next two tests unavoidably show warnings in Chrome. Since fetch will always +// be used if it's available, just return false for these to avoid the warnings. +exports.msstream = !exports.fetch && haveSlice && checkTypeSupport('ms-stream') +exports.mozchunkedarraybuffer = !exports.fetch && haveArrayBuffer && + checkTypeSupport('moz-chunked-arraybuffer') +exports.overrideMimeType = isFunction(xhr.overrideMimeType) +exports.vbArray = isFunction(global.VBArray) - // 5.3) Create an unset chosen issuer variable. - var chosenIssuer; +function isFunction (value) { + return typeof value === 'function' +} - // 5.4) For each permutation of blank node list: - var permutator = new Permutator(hashToRelated[hash]); - self.whilst( - function() { return permutator.hasNext(); }, - function(nextPermutation) { - var permutation = permutator.next(); +xhr = null // Help gc - // 5.4.1) Create a copy of issuer, issuer copy. - var issuerCopy = issuer.clone(); +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) - // 5.4.2) Create a string path. - var path = ''; +},{}],39:[function(_dereq_,module,exports){ +(function (process,global,Buffer){ +// var Base64 = require('Base64') +var capability = _dereq_('./capability') +var foreach = _dereq_('foreach') +var indexOf = _dereq_('indexof') +var inherits = _dereq_('inherits') +var keys = _dereq_('object-keys') +var response = _dereq_('./response') +var stream = _dereq_('stream') - // 5.4.3) Create a recursion list, to store blank node identifiers - // that must be recursively processed by this algorithm. - var recursionList = []; +var IncomingMessage = response.IncomingMessage +var rStates = response.readyStates - self.waterfall([ - function(callback) { - // 5.4.4) For each related in permutation: - self.forEach(permutation, function(related, idx, callback) { - // 5.4.4.1) If a canonical identifier has been issued for - // related, append it to path. - if(self.canonicalIssuer.hasId(related)) { - path += self.canonicalIssuer.getId(related); - } else { - // 5.4.4.2) Otherwise: - // 5.4.4.2.1) If issuer copy has not issued an identifier for - // related, append related to recursion list. - if(!issuerCopy.hasId(related)) { - recursionList.push(related); - } - // 5.4.4.2.2) Use the Issue Identifier algorithm, passing - // issuer copy and related and append the result to path. - path += issuerCopy.getId(related); - } +function decideMode (preferBinary) { + if (capability.fetch) { + return 'fetch' + } else if (capability.mozchunkedarraybuffer) { + return 'moz-chunked-arraybuffer' + } else if (capability.msstream) { + return 'ms-stream' + } else if (capability.arraybuffer && preferBinary) { + return 'arraybuffer' + } else if (capability.vbArray && preferBinary) { + return 'text:vbarray' + } else { + return 'text' + } +} - // 5.4.4.3) If chosen path is not empty and the length of path - // is greater than or equal to the length of chosen path and - // path is lexicographically greater than chosen path, then - // skip to the next permutation. - if(chosenPath.length !== 0 && - path.length >= chosenPath.length && path > chosenPath) { - // FIXME: may cause inaccurate total depth calculation - return nextPermutation(); - } - callback(); - }, callback); - }, - function(callback) { - // 5.4.5) For each related in recursion list: - self.forEach(recursionList, function(related, idx, callback) { - // 5.4.5.1) Set result to the result of recursively executing - // the Hash N-Degree Quads algorithm, passing related for - // identifier and issuer copy for path identifier issuer. - self.hashNDegreeQuads( - related, issuerCopy, function(err, result) { - if(err) { - return callback(err); - } +var ClientRequest = module.exports = function (opts) { + var self = this + stream.Writable.call(self) - // 5.4.5.2) Use the Issue Identifier algorithm, passing issuer - // copy and related and append the result to path. - path += issuerCopy.getId(related); + self._opts = opts + self._body = [] + self._headers = {} + if (opts.auth) + self.setHeader('Authorization', 'Basic ' + new Buffer(opts.auth).toString('base64')) + foreach(keys(opts.headers), function (name) { + self.setHeader(name, opts.headers[name]) + }) - // 5.4.5.3) Append <, the hash in result, and > to path. - path += '<' + result.hash + '>'; + var preferBinary + if (opts.mode === 'prefer-streaming') { + // If streaming is a high priority but binary compatibility and + // the accuracy of the 'content-type' header aren't + preferBinary = false + } else if (opts.mode === 'allow-wrong-content-type') { + // If streaming is more important than preserving the 'content-type' header + preferBinary = !capability.overrideMimeType + } else if (!opts.mode || opts.mode === 'default' || opts.mode === 'prefer-fast') { + // Use binary if text streaming may corrupt data or the content-type header, or for speed + preferBinary = true + } else { + throw new Error('Invalid value for opts.mode') + } + self._mode = decideMode(preferBinary) - // 5.4.5.4) Set issuer copy to the identifier issuer in - // result. - issuerCopy = result.issuer; + self.on('finish', function () { + self._onFinish() + }) +} - // 5.4.5.5) If chosen path is not empty and the length of path - // is greater than or equal to the length of chosen path and - // path is lexicographically greater than chosen path, then - // skip to the next permutation. - if(chosenPath.length !== 0 && - path.length >= chosenPath.length && path > chosenPath) { - // FIXME: may cause inaccurate total depth calculation - return nextPermutation(); - } - callback(); - }); - }, callback); - }, - function(callback) { - // 5.4.6) If chosen path is empty or path is lexicographically - // less than chosen path, set chosen path to path and chosen - // issuer to issuer copy. - if(chosenPath.length === 0 || path < chosenPath) { - chosenPath = path; - chosenIssuer = issuerCopy; - } - callback(); - } - ], nextPermutation); - }, function(err) { - if(err) { - return callback(err); - } +inherits(ClientRequest, stream.Writable) - // 5.5) Append chosen path to data to hash. - md.update(chosenPath); +ClientRequest.prototype.setHeader = function (name, value) { + var self = this + var lowerName = name.toLowerCase() + // This check is not necessary, but it prevents warnings from browsers about setting unsafe + // headers. To be honest I'm not entirely sure hiding these warnings is a good thing, but + // http-browserify did it, so I will too. + if (indexOf(unsafeHeaders, lowerName) !== -1) + return - // 5.6) Replace issuer, by reference, with chosen issuer. - issuer = chosenIssuer; - callback(); - }); - }, callback); - } - ], function(err) { - // 6) Return issuer and the hash that results from passing data to hash - // through the hash algorithm. - callback(err, {hash: md.digest(), issuer: issuer}); - }); -}; + self._headers[lowerName] = { + name: name, + value: value + } +} -// helper for creating hash to related blank nodes map -Normalize.prototype.createHashToRelated = function(id, issuer, callback) { - var self = this; +ClientRequest.prototype.getHeader = function (name) { + var self = this + return self._headers[name.toLowerCase()].value +} - // 1) Create a hash to related blank nodes map for storing hashes that - // identify related blank nodes. - var hashToRelated = {}; +ClientRequest.prototype.removeHeader = function (name) { + var self = this + delete self._headers[name.toLowerCase()] +} - // 2) Get a reference, quads, to the list of quads in the blank node to - // quads map for the key identifier. - var quads = self.blankNodeInfo[id].quads; +ClientRequest.prototype._onFinish = function () { + var self = this - // 3) For each quad in quads: - self.forEach(quads, function(quad, idx, callback) { - // 3.1) For each component in quad, if component is the subject, object, - // and graph name and it is a blank node that is not identified by - // identifier: - self.forEach(quad, function(component, key, callback) { - if(key === 'predicate' || - !(component.type === 'blank node' && component.value !== id)) { - return callback(); - } - // 3.1.1) Set hash to the result of the Hash Related Blank Node - // algorithm, passing the blank node identifier for component as - // related, quad, path identifier issuer as issuer, and position as - // either s, o, or g based on whether component is a subject, object, - // graph name, respectively. - var related = component.value; - var position = POSITIONS[key]; - self.hashRelatedBlankNode( - related, quad, issuer, position, function(err, hash) { - if(err) { - return callback(err); - } - // 3.1.2) Add a mapping of hash to the blank node identifier for - // component to hash to related blank nodes map, adding an entry as - // necessary. - if(hash in hashToRelated) { - hashToRelated[hash].push(related); - } else { - hashToRelated[hash] = [related]; - } - callback(); - }); - }, callback); - }, function(err) { - callback(err, hashToRelated); - }); -}; + if (self._destroyed) + return + var opts = self._opts -// helper that iterates over quad components (skips predicate) -Normalize.prototype.forEachComponent = function(quad, op) { - for(var key in quad) { - // skip `predicate` - if(key === 'predicate') { - continue; - } - op(quad[key], key, quad); - } -}; + var headersObj = self._headers + var body + if (opts.method === 'POST' || opts.method === 'PUT') { + if (capability.blobConstructor) { + body = new global.Blob(self._body.map(function (buffer) { + return buffer.toArrayBuffer() + }), { + type: (headersObj['content-type'] || {}).value || '' + }) + } else { + // get utf8 string + body = Buffer.concat(self._body).toString() + } + } -return Normalize; + if (self._mode === 'fetch') { + var headers = keys(headersObj).map(function (name) { + return [headersObj[name].name, headersObj[name].value] + }) -})(); // end of define URDNA2015 + global.fetch(self._opts.url, { + method: self._opts.method, + headers: headers, + body: body, + mode: 'cors', + credentials: opts.withCredentials ? 'include' : 'same-origin' + }).then(function (response) { + self._fetchResponse = response + self._connect() + }).then(undefined, function (reason) { + self.emit('error', reason) + }) + } else { + var xhr = self._xhr = new global.XMLHttpRequest() + try { + xhr.open(self._opts.method, self._opts.url, true) + } catch (err) { + process.nextTick(function () { + self.emit('error', err) + }) + return + } -/////////////////////////////// DEFINE URGNA2012 ////////////////////////////// + // Can't set responseType on really old browsers + if ('responseType' in xhr) + xhr.responseType = self._mode.split(':')[0] -var URGNA2012 = (function() { + if ('withCredentials' in xhr) + xhr.withCredentials = !!opts.withCredentials -var Normalize = function(options) { - URDNA2015.call(this, options); - this.name = 'URGNA2012'; -}; -Normalize.prototype = new URDNA2015(); + if (self._mode === 'text' && 'overrideMimeType' in xhr) + xhr.overrideMimeType('text/plain; charset=x-user-defined') -// helper for modifying component during Hash First Degree Quads -Normalize.prototype.modifyFirstDegreeComponent = function(id, component, key) { - if(component.type !== 'blank node') { - return component; - } - component = _clone(component); - if(key === 'name') { - component.value = '_:g'; - } else { - component.value = (component.value === id ? '_:a' : '_:z'); - } - return component; -}; + foreach(keys(headersObj), function (name) { + xhr.setRequestHeader(headersObj[name].name, headersObj[name].value) + }) -// helper for getting a related predicate -Normalize.prototype.getRelatedPredicate = function(quad) { - return quad.predicate.value; -}; + self._response = null + xhr.onreadystatechange = function () { + switch (xhr.readyState) { + case rStates.LOADING: + case rStates.DONE: + self._onXHRProgress() + break + } + } + // Necessary for streaming in Firefox, since xhr.response is ONLY defined + // in onprogress, not in onreadystatechange with xhr.readyState = 3 + if (self._mode === 'moz-chunked-arraybuffer') { + xhr.onprogress = function () { + self._onXHRProgress() + } + } -// helper for creating hash to related blank nodes map -Normalize.prototype.createHashToRelated = function(id, issuer, callback) { - var self = this; + xhr.onerror = function () { + if (self._destroyed) + return + self.emit('error', new Error('XHR error')) + } - // 1) Create a hash to related blank nodes map for storing hashes that - // identify related blank nodes. - var hashToRelated = {}; + try { + xhr.send(body) + } catch (err) { + process.nextTick(function () { + self.emit('error', err) + }) + return + } + } +} - // 2) Get a reference, quads, to the list of quads in the blank node to - // quads map for the key identifier. - var quads = self.blankNodeInfo[id].quads; +/** + * Checks if xhr.status is readable. Even though the spec says it should + * be available in readyState 3, accessing it throws an exception in IE8 + */ +function statusValid (xhr) { + try { + return (xhr.status !== null) + } catch (e) { + return false + } +} - // 3) For each quad in quads: - self.forEach(quads, function(quad, idx, callback) { - // 3.1) If the quad's subject is a blank node that does not match - // identifier, set hash to the result of the Hash Related Blank Node - // algorithm, passing the blank node identifier for subject as related, - // quad, path identifier issuer as issuer, and p as position. - var position; - var related; - if(quad.subject.type === 'blank node' && quad.subject.value !== id) { - related = quad.subject.value; - position = 'p'; - } else if(quad.object.type === 'blank node' && quad.object.value !== id) { - // 3.2) Otherwise, if quad's object is a blank node that does not match - // identifier, to the result of the Hash Related Blank Node algorithm, - // passing the blank node identifier for object as related, quad, path - // identifier issuer as issuer, and r as position. - related = quad.object.value; - position = 'r'; - } else { - // 3.3) Otherwise, continue to the next quad. - return callback(); - } - // 3.4) Add a mapping of hash to the blank node identifier for the - // component that matched (subject or object) to hash to related blank - // nodes map, adding an entry as necessary. - self.hashRelatedBlankNode( - related, quad, issuer, position, function(err, hash) { - if(hash in hashToRelated) { - hashToRelated[hash].push(related); - } else { - hashToRelated[hash] = [related]; - } - callback(); - }); - }, function(err) { - callback(err, hashToRelated); - }); -}; +ClientRequest.prototype._onXHRProgress = function () { + var self = this -return Normalize; + if (!statusValid(self._xhr) || self._destroyed) + return -})(); // end of define URGNA2012 + if (!self._response) + self._connect() -/** - * Recursively flattens the subjects in the given JSON-LD expanded input - * into a node map. - * - * @param input the JSON-LD expanded input. - * @param graphs a map of graph name to subject map. - * @param graph the name of the current graph. - * @param issuer the blank node identifier issuer. - * @param name the name assigned to the current input if it is a bnode. - * @param list the list to append to, null for none. - */ -function _createNodeMap(input, graphs, graph, issuer, name, list) { - // recurse through array - if(_isArray(input)) { - for(var i = 0; i < input.length; ++i) { - _createNodeMap(input[i], graphs, graph, issuer, undefined, list); - } - return; - } + self._response._onXHRProgress() +} - // add non-object to list - if(!_isObject(input)) { - if(list) { - list.push(input); - } - return; - } +ClientRequest.prototype._connect = function () { + var self = this - // add values to list - if(_isValue(input)) { - if('@type' in input) { - var type = input['@type']; - // rename @type blank node - if(type.indexOf('_:') === 0) { - input['@type'] = type = issuer.getId(type); - } - } - if(list) { - list.push(input); - } - return; - } + if (self._destroyed) + return - // Note: At this point, input must be a subject. + self._response = new IncomingMessage(self._xhr, self._fetchResponse, self._mode) + self.emit('response', self._response) +} - // spec requires @type to be named first, so assign names early - if('@type' in input) { - var types = input['@type']; - for(var i = 0; i < types.length; ++i) { - var type = types[i]; - if(type.indexOf('_:') === 0) { - issuer.getId(type); - } - } - } +ClientRequest.prototype._write = function (chunk, encoding, cb) { + var self = this - // get name for subject - if(_isUndefined(name)) { - name = _isBlankNode(input) ? issuer.getId(input['@id']) : input['@id']; - } + self._body.push(chunk) + cb() +} - // add subject reference to list - if(list) { - list.push({'@id': name}); - } +ClientRequest.prototype.abort = ClientRequest.prototype.destroy = function () { + var self = this + self._destroyed = true + if (self._response) + self._response._destroyed = true + if (self._xhr) + self._xhr.abort() + // Currently, there isn't a way to truly abort a fetch. + // If you like bikeshedding, see https://github.com/whatwg/fetch/issues/27 +} - // create new subject or merge into existing one - var subjects = graphs[graph]; - var subject = subjects[name] = subjects[name] || {}; - subject['@id'] = name; - var properties = Object.keys(input).sort(); - for(var pi = 0; pi < properties.length; ++pi) { - var property = properties[pi]; +ClientRequest.prototype.end = function (data, encoding, cb) { + var self = this + if (typeof data === 'function') { + cb = data + data = undefined + } - // skip @id - if(property === '@id') { - continue; - } + stream.Writable.prototype.end.call(self, data, encoding, cb) +} - // handle reverse properties - if(property === '@reverse') { - var referencedNode = {'@id': name}; - var reverseMap = input['@reverse']; - for(var reverseProperty in reverseMap) { - var items = reverseMap[reverseProperty]; - for(var ii = 0; ii < items.length; ++ii) { - var item = items[ii]; - var itemName = item['@id']; - if(_isBlankNode(item)) { - itemName = issuer.getId(itemName); - } - _createNodeMap(item, graphs, graph, issuer, itemName); - jsonld.addValue( - subjects[itemName], reverseProperty, referencedNode, - {propertyIsArray: true, allowDuplicate: false}); - } - } - continue; - } - - // recurse into graph - if(property === '@graph') { - // add graph subjects map entry - if(!(name in graphs)) { - graphs[name] = {}; - } - var g = (graph === '@merged') ? graph : name; - _createNodeMap(input[property], graphs, g, issuer); - continue; - } +ClientRequest.prototype.flushHeaders = function () {} +ClientRequest.prototype.setTimeout = function () {} +ClientRequest.prototype.setNoDelay = function () {} +ClientRequest.prototype.setSocketKeepAlive = function () {} - // copy non-@type keywords - if(property !== '@type' && _isKeyword(property)) { - if(property === '@index' && property in subject && - (input[property] !== subject[property] || - input[property]['@id'] !== subject[property]['@id'])) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; conflicting @index property detected.', - 'jsonld.SyntaxError', - {code: 'conflicting indexes', subject: subject}); - } - subject[property] = input[property]; - continue; - } +// Taken from http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader%28%29-method +var unsafeHeaders = [ + 'accept-charset', + 'accept-encoding', + 'access-control-request-headers', + 'access-control-request-method', + 'connection', + 'content-length', + 'cookie', + 'cookie2', + 'date', + 'dnt', + 'expect', + 'host', + 'keep-alive', + 'origin', + 'referer', + 'te', + 'trailer', + 'transfer-encoding', + 'upgrade', + 'user-agent', + 'via' +] - // iterate over objects - var objects = input[property]; +}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},_dereq_("buffer").Buffer) - // if property is a bnode, assign it a new id - if(property.indexOf('_:') === 0) { - property = issuer.getId(property); - } +},{"./capability":38,"./response":40,"_process":12,"buffer":4,"foreach":42,"indexof":43,"inherits":10,"object-keys":44,"stream":36}],40:[function(_dereq_,module,exports){ +(function (process,global,Buffer){ +var capability = _dereq_('./capability') +var foreach = _dereq_('foreach') +var inherits = _dereq_('inherits') +var stream = _dereq_('stream') - // ensure property is added for empty arrays - if(objects.length === 0) { - jsonld.addValue(subject, property, [], {propertyIsArray: true}); - continue; - } - for(var oi = 0; oi < objects.length; ++oi) { - var o = objects[oi]; +var rStates = exports.readyStates = { + UNSENT: 0, + OPENED: 1, + HEADERS_RECEIVED: 2, + LOADING: 3, + DONE: 4 +} - if(property === '@type') { - // rename @type blank nodes - o = (o.indexOf('_:') === 0) ? issuer.getId(o) : o; - } +var IncomingMessage = exports.IncomingMessage = function (xhr, response, mode) { + var self = this + stream.Readable.call(self) - // handle embedded subject or subject reference - if(_isSubject(o) || _isSubjectReference(o)) { - // relabel blank node @id - var id = _isBlankNode(o) ? issuer.getId(o['@id']) : o['@id']; + self._mode = mode + self.headers = {} + self.rawHeaders = [] + self.trailers = {} + self.rawTrailers = [] - // add reference and recurse - jsonld.addValue( - subject, property, {'@id': id}, - {propertyIsArray: true, allowDuplicate: false}); - _createNodeMap(o, graphs, graph, issuer, id); - } else if(_isList(o)) { - // handle @list - var _list = []; - _createNodeMap(o['@list'], graphs, graph, issuer, name, _list); - o = {'@list': _list}; - jsonld.addValue( - subject, property, o, - {propertyIsArray: true, allowDuplicate: false}); - } else { - // handle @value - _createNodeMap(o, graphs, graph, issuer, name); - jsonld.addValue( - subject, property, o, {propertyIsArray: true, allowDuplicate: false}); - } - } - } -} + // Fake the 'close' event, but only once 'end' fires + self.on('end', function () { + // The nextTick is necessary to prevent the 'request' module from causing an infinite loop + process.nextTick(function () { + self.emit('close') + }) + }) -function _mergeNodeMaps(graphs) { - // add all non-default graphs to default graph - var defaultGraph = graphs['@default']; - var graphNames = Object.keys(graphs).sort(); - for(var i = 0; i < graphNames.length; ++i) { - var graphName = graphNames[i]; - if(graphName === '@default') { - continue; - } - var nodeMap = graphs[graphName]; - var subject = defaultGraph[graphName]; - if(!subject) { - defaultGraph[graphName] = subject = { - '@id': graphName, - '@graph': [] - }; - } else if(!('@graph' in subject)) { - subject['@graph'] = []; - } - var graph = subject['@graph']; - var ids = Object.keys(nodeMap).sort(); - for(var ii = 0; ii < ids.length; ++ii) { - var node = nodeMap[ids[ii]]; - // only add full subjects - if(!_isSubjectReference(node)) { - graph.push(node); - } - } - } - return defaultGraph; -} + if (mode === 'fetch') { + self._fetchResponse = response -/** - * Frames subjects according to the given frame. - * - * @param state the current framing state. - * @param subjects the subjects to filter. - * @param frame the frame. - * @param parent the parent subject or top-level array. - * @param property the parent property, initialized to null. - */ -function _frame(state, subjects, frame, parent, property) { - // validate the frame - _validateFrame(frame); - frame = frame[0]; + self.statusCode = response.status + self.statusMessage = response.statusText + // backwards compatible version of for ( of ): + // for (var ,_i,_it = [Symbol.iterator](); = (_i = _it.next()).value,!_i.done;) + for (var header, _i, _it = response.headers[Symbol.iterator](); header = (_i = _it.next()).value, !_i.done;) { + self.headers[header[0].toLowerCase()] = header[1] + self.rawHeaders.push(header[0], header[1]) + } - // get flags for current frame - var options = state.options; - var flags = { - embed: _getFrameFlag(frame, options, 'embed'), - explicit: _getFrameFlag(frame, options, 'explicit'), - requireAll: _getFrameFlag(frame, options, 'requireAll') - }; + // TODO: this doesn't respect backpressure. Once WritableStream is available, this can be fixed + var reader = response.body.getReader() + function read () { + reader.read().then(function (result) { + if (self._destroyed) + return + if (result.done) { + self.push(null) + return + } + self.push(new Buffer(result.value)) + read() + }) + } + read() - // filter out subjects that match the frame - var matches = _filterSubjects(state, subjects, frame, flags); + } else { + self._xhr = xhr + self._pos = 0 - // add matches to output - var ids = Object.keys(matches).sort(); - for(var idx = 0; idx < ids.length; ++idx) { - var id = ids[idx]; - var subject = matches[id]; + self.statusCode = xhr.status + self.statusMessage = xhr.statusText + var headers = xhr.getAllResponseHeaders().split(/\r?\n/) + foreach(headers, function (header) { + var matches = header.match(/^([^:]+):\s*(.*)/) + if (matches) { + var key = matches[1].toLowerCase() + if (self.headers[key] !== undefined) + self.headers[key] += ', ' + matches[2] + else + self.headers[key] = matches[2] + self.rawHeaders.push(matches[1], matches[2]) + } + }) - if(flags.embed === '@link' && id in state.link) { - // TODO: may want to also match an existing linked subject against - // the current frame ... so different frames could produce different - // subjects that are only shared in-memory when the frames are the same + self._charset = 'x-user-defined' + if (!capability.overrideMimeType) { + var mimeType = self.rawHeaders['mime-type'] + if (mimeType) { + var charsetMatch = mimeType.match(/;\s*charset=([^;])(;|$)/) + if (charsetMatch) { + self._charset = charsetMatch[1].toLowerCase() + } + } + if (!self._charset) + self._charset = 'utf-8' // best guess + } + } +} - // add existing linked subject - _addFrameOutput(parent, property, state.link[id]); - continue; - } +inherits(IncomingMessage, stream.Readable) - /* Note: In order to treat each top-level match as a compartmentalized - result, clear the unique embedded subjects map when the property is null, - which only occurs at the top-level. */ - if(property === null) { - state.uniqueEmbeds = {}; - } +IncomingMessage.prototype._read = function () {} - // start output for subject - var output = {}; - output['@id'] = id; - state.link[id] = output; +IncomingMessage.prototype._onXHRProgress = function () { + var self = this - // if embed is @never or if a circular reference would be created by an - // embed, the subject cannot be embedded, just add the reference; - // note that a circular reference won't occur when the embed flag is - // `@link` as the above check will short-circuit before reaching this point - if(flags.embed === '@never' || - _createsCircularReference(subject, state.subjectStack)) { - _addFrameOutput(parent, property, output); - continue; - } + var xhr = self._xhr - // if only the last match should be embedded - if(flags.embed === '@last') { - // remove any existing embed - if(id in state.uniqueEmbeds) { - _removeEmbed(state, id); - } - state.uniqueEmbeds[id] = {parent: parent, property: property}; - } + var response = null + switch (self._mode) { + case 'text:vbarray': // For IE9 + if (xhr.readyState !== rStates.DONE) + break + try { + // This fails in IE8 + response = new global.VBArray(xhr.responseBody).toArray() + } catch (e) {} + if (response !== null) { + self.push(new Buffer(response)) + break + } + // Falls through in IE8 + case 'text': + try { // This will fail when readyState = 3 in IE9. Switch mode and wait for readyState = 4 + response = xhr.responseText + } catch (e) { + self._mode = 'text:vbarray' + break + } + if (response.length > self._pos) { + var newData = response.substr(self._pos) + if (self._charset === 'x-user-defined') { + var buffer = new Buffer(newData.length) + for (var i = 0; i < newData.length; i++) + buffer[i] = newData.charCodeAt(i) & 0xff - // push matching subject onto stack to enable circular embed checks - state.subjectStack.push(subject); + self.push(buffer) + } else { + self.push(newData, self._charset) + } + self._pos = response.length + } + break + case 'arraybuffer': + if (xhr.readyState !== rStates.DONE) + break + response = xhr.response + self.push(new Buffer(new Uint8Array(response))) + break + case 'moz-chunked-arraybuffer': // take whole + response = xhr.response + if (xhr.readyState !== rStates.LOADING || !response) + break + self.push(new Buffer(new Uint8Array(response))) + break + case 'ms-stream': + response = xhr.response + if (xhr.readyState !== rStates.LOADING) + break + var reader = new global.MSStreamReader() + reader.onprogress = function () { + if (reader.result.byteLength > self._pos) { + self.push(new Buffer(new Uint8Array(reader.result.slice(self._pos)))) + self._pos = reader.result.byteLength + } + } + reader.onload = function () { + self.push(null) + } + // reader.onerror = ??? // TODO: this + reader.readAsArrayBuffer(response) + break + } - // iterate over subject properties - var props = Object.keys(subject).sort(); - for(var i = 0; i < props.length; i++) { - var prop = props[i]; + // The ms-stream case handles end separately in reader.onload() + if (self._xhr.readyState === rStates.DONE && self._mode !== 'ms-stream') { + self.push(null) + } +} - // copy keywords to output - if(_isKeyword(prop)) { - output[prop] = _clone(subject[prop]); - continue; - } +}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},_dereq_("buffer").Buffer) - // explicit is on and property isn't in the frame, skip processing - if(flags.explicit && !(prop in frame)) { - continue; - } +},{"./capability":38,"_process":12,"buffer":4,"foreach":42,"inherits":10,"stream":36}],41:[function(_dereq_,module,exports){ +module.exports = { + "100": "Continue", + "101": "Switching Protocols", + "102": "Processing", + "200": "OK", + "201": "Created", + "202": "Accepted", + "203": "Non-Authoritative Information", + "204": "No Content", + "205": "Reset Content", + "206": "Partial Content", + "207": "Multi-Status", + "300": "Multiple Choices", + "301": "Moved Permanently", + "302": "Moved Temporarily", + "303": "See Other", + "304": "Not Modified", + "305": "Use Proxy", + "307": "Temporary Redirect", + "308": "Permanent Redirect", + "400": "Bad Request", + "401": "Unauthorized", + "402": "Payment Required", + "403": "Forbidden", + "404": "Not Found", + "405": "Method Not Allowed", + "406": "Not Acceptable", + "407": "Proxy Authentication Required", + "408": "Request Time-out", + "409": "Conflict", + "410": "Gone", + "411": "Length Required", + "412": "Precondition Failed", + "413": "Request Entity Too Large", + "414": "Request-URI Too Large", + "415": "Unsupported Media Type", + "416": "Requested Range Not Satisfiable", + "417": "Expectation Failed", + "418": "I'm a teapot", + "422": "Unprocessable Entity", + "423": "Locked", + "424": "Failed Dependency", + "425": "Unordered Collection", + "426": "Upgrade Required", + "428": "Precondition Required", + "429": "Too Many Requests", + "431": "Request Header Fields Too Large", + "500": "Internal Server Error", + "501": "Not Implemented", + "502": "Bad Gateway", + "503": "Service Unavailable", + "504": "Gateway Time-out", + "505": "HTTP Version Not Supported", + "506": "Variant Also Negotiates", + "507": "Insufficient Storage", + "509": "Bandwidth Limit Exceeded", + "510": "Not Extended", + "511": "Network Authentication Required" +} - // add objects - var objects = subject[prop]; - for(var oi = 0; oi < objects.length; ++oi) { - var o = objects[oi]; +},{}],42:[function(_dereq_,module,exports){ - // recurse into list - if(_isList(o)) { - // add empty list - var list = {'@list': []}; - _addFrameOutput(output, prop, list); +var hasOwn = Object.prototype.hasOwnProperty; +var toString = Object.prototype.toString; - // add list objects - var src = o['@list']; - for(var n in src) { - o = src[n]; - if(_isSubjectReference(o)) { - var subframe = (prop in frame ? - frame[prop][0]['@list'] : _createImplicitFrame(flags)); - // recurse into subject reference - _frame(state, [o['@id']], subframe, list, '@list'); - } else { - // include other values automatically - _addFrameOutput(list, '@list', _clone(o)); - } - } - continue; +module.exports = function forEach (obj, fn, ctx) { + if (toString.call(fn) !== '[object Function]') { + throw new TypeError('iterator must be a function'); + } + var l = obj.length; + if (l === +l) { + for (var i = 0; i < l; i++) { + fn.call(ctx, obj[i], i, obj); } - - if(_isSubjectReference(o)) { - // recurse into subject reference - var subframe = (prop in frame ? - frame[prop] : _createImplicitFrame(flags)); - _frame(state, [o['@id']], subframe, output, prop); - } else { - // include other values automatically - _addFrameOutput(output, prop, _clone(o)); + } else { + for (var k in obj) { + if (hasOwn.call(obj, k)) { + fn.call(ctx, obj[k], k, obj); + } } - } } +}; - // handle defaults - var props = Object.keys(frame).sort(); - for(var i = 0; i < props.length; ++i) { - var prop = props[i]; - - // skip keywords - if(_isKeyword(prop)) { - continue; - } - // if omit default is off, then include default values for properties - // that appear in the next frame but are not in the matching subject - var next = frame[prop][0]; - var omitDefaultOn = _getFrameFlag(next, options, 'omitDefault'); - if(!omitDefaultOn && !(prop in output)) { - var preserve = '@null'; - if('@default' in next) { - preserve = _clone(next['@default']); - } - if(!_isArray(preserve)) { - preserve = [preserve]; - } - output[prop] = [{'@preserve': preserve}]; - } - } +},{}],43:[function(_dereq_,module,exports){ - // add output to parent - _addFrameOutput(parent, property, output); +var indexOf = [].indexOf; - // pop matching subject from circular ref-checking stack - state.subjectStack.pop(); +module.exports = function(arr, obj){ + if (indexOf) return arr.indexOf(obj); + for (var i = 0; i < arr.length; ++i) { + if (arr[i] === obj) return i; } -} + return -1; +}; +},{}],44:[function(_dereq_,module,exports){ +'use strict'; -/** - * Creates an implicit frame when recursing through subject matches. If - * a frame doesn't have an explicit frame for a particular property, then - * a wildcard child frame will be created that uses the same flags that the - * parent frame used. - * - * @param flags the current framing flags. - * - * @return the implicit frame. - */ -function _createImplicitFrame(flags) { - var frame = {}; - for(var key in flags) { - if(flags[key] !== undefined) { - frame['@' + key] = [flags[key]]; - } - } - return [frame]; -} +// modified from https://github.com/es-shims/es5-shim +var has = Object.prototype.hasOwnProperty; +var toStr = Object.prototype.toString; +var slice = Array.prototype.slice; +var isArgs = _dereq_('./isArguments'); +var isEnumerable = Object.prototype.propertyIsEnumerable; +var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString'); +var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype'); +var dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' +]; +var equalsConstructorPrototype = function (o) { + var ctor = o.constructor; + return ctor && ctor.prototype === o; +}; +var excludedKeys = { + $console: true, + $external: true, + $frame: true, + $frameElement: true, + $frames: true, + $innerHeight: true, + $innerWidth: true, + $outerHeight: true, + $outerWidth: true, + $pageXOffset: true, + $pageYOffset: true, + $parent: true, + $scrollLeft: true, + $scrollTop: true, + $scrollX: true, + $scrollY: true, + $self: true, + $webkitIndexedDB: true, + $webkitStorageInfo: true, + $window: true +}; +var hasAutomationEqualityBug = (function () { + /* global window */ + if (typeof window === 'undefined') { return false; } + for (var k in window) { + try { + if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { + try { + equalsConstructorPrototype(window[k]); + } catch (e) { + return true; + } + } + } catch (e) { + return true; + } + } + return false; +}()); +var equalsConstructorPrototypeIfNotBuggy = function (o) { + /* global window */ + if (typeof window === 'undefined' || !hasAutomationEqualityBug) { + return equalsConstructorPrototype(o); + } + try { + return equalsConstructorPrototype(o); + } catch (e) { + return false; + } +}; -/** - * Checks the current subject stack to see if embedding the given subject - * would cause a circular reference. - * - * @param subjectToEmbed the subject to embed. - * @param subjectStack the current stack of subjects. - * - * @return true if a circular reference would be created, false if not. - */ -function _createsCircularReference(subjectToEmbed, subjectStack) { - for(var i = subjectStack.length - 1; i >= 0; --i) { - if(subjectStack[i]['@id'] === subjectToEmbed['@id']) { - return true; - } - } - return false; -} +var keysShim = function keys(object) { + var isObject = object !== null && typeof object === 'object'; + var isFunction = toStr.call(object) === '[object Function]'; + var isArguments = isArgs(object); + var isString = isObject && toStr.call(object) === '[object String]'; + var theKeys = []; -/** - * Gets the frame flag value for the given flag name. - * - * @param frame the frame. - * @param options the framing options. - * @param name the flag name. - * - * @return the flag value. - */ -function _getFrameFlag(frame, options, name) { - var flag = '@' + name; - var rval = (flag in frame ? frame[flag][0] : options[name]); - if(name === 'embed') { - // default is "@last" - // backwards-compatibility support for "embed" maps: - // true => "@last" - // false => "@never" - if(rval === true) { - rval = '@last'; - } else if(rval === false) { - rval = '@never'; - } else if(rval !== '@always' && rval !== '@never' && rval !== '@link') { - rval = '@last'; - } - } - return rval; -} + if (!isObject && !isFunction && !isArguments) { + throw new TypeError('Object.keys called on a non-object'); + } -/** - * Validates a JSON-LD frame, throwing an exception if the frame is invalid. - * - * @param frame the frame to validate. - */ -function _validateFrame(frame) { - if(!_isArray(frame) || frame.length !== 1 || !_isObject(frame[0])) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; a JSON-LD frame must be a single object.', - 'jsonld.SyntaxError', {frame: frame}); - } -} + var skipProto = hasProtoEnumBug && isFunction; + if (isString && object.length > 0 && !has.call(object, 0)) { + for (var i = 0; i < object.length; ++i) { + theKeys.push(String(i)); + } + } -/** - * Returns a map of all of the subjects that match a parsed frame. - * - * @param state the current framing state. - * @param subjects the set of subjects to filter. - * @param frame the parsed frame. - * @param flags the frame flags. - * - * @return all of the matched subjects. - */ -function _filterSubjects(state, subjects, frame, flags) { - // filter subjects in @id order - var rval = {}; - for(var i = 0; i < subjects.length; ++i) { - var id = subjects[i]; - var subject = state.subjects[id]; - if(_filterSubject(subject, frame, flags)) { - rval[id] = subject; - } + if (isArguments && object.length > 0) { + for (var j = 0; j < object.length; ++j) { + theKeys.push(String(j)); + } + } else { + for (var name in object) { + if (!(skipProto && name === 'prototype') && has.call(object, name)) { + theKeys.push(String(name)); + } + } + } + + if (hasDontEnumBug) { + var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); + + for (var k = 0; k < dontEnums.length; ++k) { + if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { + theKeys.push(dontEnums[k]); + } + } + } + return theKeys; +}; + +keysShim.shim = function shimObjectKeys() { + if (Object.keys) { + var keysWorksWithArguments = (function () { + // Safari 5.0 bug + return (Object.keys(arguments) || '').length === 2; + }(1, 2)); + if (!keysWorksWithArguments) { + var originalKeys = Object.keys; + Object.keys = function keys(object) { + if (isArgs(object)) { + return originalKeys(slice.call(object)); + } else { + return originalKeys(object); + } + }; + } + } else { + Object.keys = keysShim; + } + return Object.keys || keysShim; +}; + +module.exports = keysShim; + +},{"./isArguments":45}],45:[function(_dereq_,module,exports){ +'use strict'; + +var toStr = Object.prototype.toString; + +module.exports = function isArguments(value) { + var str = toStr.call(value); + var isArgs = str === '[object Arguments]'; + if (!isArgs) { + isArgs = str !== '[object Array]' && + value !== null && + typeof value === 'object' && + typeof value.length === 'number' && + value.length >= 0 && + toStr.call(value.callee) === '[object Function]'; + } + return isArgs; +}; + +},{}],46:[function(_dereq_,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var Buffer = _dereq_('buffer').Buffer; + +var isBufferEncoding = Buffer.isEncoding + || function(encoding) { + switch (encoding && encoding.toLowerCase()) { + case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true; + default: return false; + } + } + + +function assertEncoding(encoding) { + if (encoding && !isBufferEncoding(encoding)) { + throw new Error('Unknown encoding: ' + encoding); } - return rval; } -/** - * Returns true if the given subject matches the given frame. - * - * @param subject the subject to check. - * @param frame the frame to check. - * @param flags the frame flags. - * - * @return true if the subject matches, false if not. - */ -function _filterSubject(subject, frame, flags) { - // check @type (object value means 'any' type, fall through to ducktyping) - if('@type' in frame && - !(frame['@type'].length === 1 && _isObject(frame['@type'][0]))) { - var types = frame['@type']; - for(var i = 0; i < types.length; ++i) { - // any matching @type is a match - if(jsonld.hasValue(subject, '@type', types[i])) { - return true; - } - } - return false; +// StringDecoder provides an interface for efficiently splitting a series of +// buffers into a series of JS strings without breaking apart multi-byte +// characters. CESU-8 is handled as part of the UTF-8 encoding. +// +// @TODO Handling all encodings inside a single object makes it very difficult +// to reason about this code, so it should be split up in the future. +// @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code +// points as used by CESU-8. +var StringDecoder = exports.StringDecoder = function(encoding) { + this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); + assertEncoding(encoding); + switch (this.encoding) { + case 'utf8': + // CESU-8 represents each of Surrogate Pair by 3-bytes + this.surrogateSize = 3; + break; + case 'ucs2': + case 'utf16le': + // UTF-16 represents each of Surrogate Pair by 2-bytes + this.surrogateSize = 2; + this.detectIncompleteChar = utf16DetectIncompleteChar; + break; + case 'base64': + // Base-64 stores 3 bytes in 4 chars, and pads the remainder. + this.surrogateSize = 3; + this.detectIncompleteChar = base64DetectIncompleteChar; + break; + default: + this.write = passThroughWrite; + return; } - // check ducktype - var wildcard = true; - var matchesSome = false; - for(var key in frame) { - if(_isKeyword(key)) { - // skip non-@id and non-@type - if(key !== '@id' && key !== '@type') { - continue; - } - wildcard = false; + // Enough space to store all bytes of a single character. UTF-8 needs 4 + // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate). + this.charBuffer = new Buffer(6); + // Number of bytes received for the current incomplete multi-byte character. + this.charReceived = 0; + // Number of bytes expected for the current incomplete multi-byte character. + this.charLength = 0; +}; - // check @id for a specific @id value - if(key === '@id' && _isString(frame[key])) { - if(subject[key] !== frame[key]) { - return false; - } - matchesSome = true; - continue; - } + +// write decodes the given buffer and returns it as JS string that is +// guaranteed to not contain any partial multi-byte characters. Any partial +// character found at the end of the buffer is buffered up, and will be +// returned when calling write again with the remaining bytes. +// +// Note: Converting a Buffer containing an orphan surrogate to a String +// currently works, but converting a String to a Buffer (via `new Buffer`, or +// Buffer#write) will replace incomplete surrogates with the unicode +// replacement character. See https://codereview.chromium.org/121173009/ . +StringDecoder.prototype.write = function(buffer) { + var charStr = ''; + // if our last write ended with an incomplete multibyte character + while (this.charLength) { + // determine how many remaining bytes this buffer has to offer for this char + var available = (buffer.length >= this.charLength - this.charReceived) ? + this.charLength - this.charReceived : + buffer.length; + + // add the new bytes to the char buffer + buffer.copy(this.charBuffer, this.charReceived, 0, available); + this.charReceived += available; + + if (this.charReceived < this.charLength) { + // still not enough chars in this buffer? wait for more ... + return ''; } - wildcard = false; + // remove bytes belonging to the current character from the buffer + buffer = buffer.slice(available, buffer.length); - if(key in subject) { - // frame[key] === [] means do not match if property is present - if(_isArray(frame[key]) && frame[key].length === 0 && - subject[key] !== undefined) { - return false; - } - matchesSome = true; + // get the character that was split + charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); + + // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character + var charCode = charStr.charCodeAt(charStr.length - 1); + if (charCode >= 0xD800 && charCode <= 0xDBFF) { + this.charLength += this.surrogateSize; + charStr = ''; continue; } + this.charReceived = this.charLength = 0; - // all properties must match to be a duck unless a @default is specified - var hasDefault = (_isArray(frame[key]) && _isObject(frame[key][0]) && - '@default' in frame[key][0]); - if(flags.requireAll && !hasDefault) { - return false; + // if there are no more bytes in this buffer, just emit our char + if (buffer.length === 0) { + return charStr; } + break; } - // return true if wildcard or subject matches some properties - return wildcard || matchesSome; -} + // determine and set charLength / charReceived + this.detectIncompleteChar(buffer); -/** - * Removes an existing embed. - * - * @param state the current framing state. - * @param id the @id of the embed to remove. - */ -function _removeEmbed(state, id) { - // get existing embed - var embeds = state.uniqueEmbeds; - var embed = embeds[id]; - var parent = embed.parent; - var property = embed.property; + var end = buffer.length; + if (this.charLength) { + // buffer the incomplete character bytes we got + buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end); + end -= this.charReceived; + } - // create reference to replace embed - var subject = {'@id': id}; + charStr += buffer.toString(this.encoding, 0, end); - // remove existing embed - if(_isArray(parent)) { - // replace subject with reference - for(var i = 0; i < parent.length; ++i) { - if(jsonld.compareValues(parent[i], subject)) { - parent[i] = subject; - break; - } - } - } else { - // replace subject with reference - var useArray = _isArray(parent[property]); - jsonld.removeValue(parent, property, subject, {propertyIsArray: useArray}); - jsonld.addValue(parent, property, subject, {propertyIsArray: useArray}); + var end = charStr.length - 1; + var charCode = charStr.charCodeAt(end); + // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character + if (charCode >= 0xD800 && charCode <= 0xDBFF) { + var size = this.surrogateSize; + this.charLength += size; + this.charReceived += size; + this.charBuffer.copy(this.charBuffer, size, 0, size); + buffer.copy(this.charBuffer, 0, 0, size); + return charStr.substring(0, end); } - // recursively remove dependent dangling embeds - var removeDependents = function(id) { - // get embed keys as a separate array to enable deleting keys in map - var ids = Object.keys(embeds); - for(var i = 0; i < ids.length; ++i) { - var next = ids[i]; - if(next in embeds && _isObject(embeds[next].parent) && - embeds[next].parent['@id'] === id) { - delete embeds[next]; - removeDependents(next); - } - } - }; - removeDependents(id); -} + // or just emit the charStr + return charStr; +}; -/** - * Adds framing output to the given parent. - * - * @param parent the parent to add to. - * @param property the parent property. - * @param output the output to add. - */ -function _addFrameOutput(parent, property, output) { - if(_isObject(parent)) { - jsonld.addValue(parent, property, output, {propertyIsArray: true}); - } else { - parent.push(output); - } -} +// detectIncompleteChar determines if there is an incomplete UTF-8 character at +// the end of the given buffer. If so, it sets this.charLength to the byte +// length that character, and sets this.charReceived to the number of bytes +// that are available for this character. +StringDecoder.prototype.detectIncompleteChar = function(buffer) { + // determine how many bytes we have to check at the end of this buffer + var i = (buffer.length >= 3) ? 3 : buffer.length; -/** - * Removes the @preserve keywords as the last step of the framing algorithm. - * - * @param ctx the active context used to compact the input. - * @param input the framed, compacted output. - * @param options the compaction options used. - * - * @return the resulting output. - */ -function _removePreserve(ctx, input, options) { - // recurse through arrays - if(_isArray(input)) { - var output = []; - for(var i = 0; i < input.length; ++i) { - var result = _removePreserve(ctx, input[i], options); - // drop nulls from arrays - if(result !== null) { - output.push(result); - } - } - input = output; - } else if(_isObject(input)) { - // remove @preserve - if('@preserve' in input) { - if(input['@preserve'] === '@null') { - return null; - } - return input['@preserve']; - } + // Figure out if one of the last i bytes of our buffer announces an + // incomplete char. + for (; i > 0; i--) { + var c = buffer[buffer.length - i]; - // skip @values - if(_isValue(input)) { - return input; - } + // See http://en.wikipedia.org/wiki/UTF-8#Description - // recurse through @lists - if(_isList(input)) { - input['@list'] = _removePreserve(ctx, input['@list'], options); - return input; + // 110XXXXX + if (i == 1 && c >> 5 == 0x06) { + this.charLength = 2; + break; } - // handle in-memory linked nodes - var idAlias = _compactIri(ctx, '@id'); - if(idAlias in input) { - var id = input[idAlias]; - if(id in options.link) { - var idx = options.link[id].indexOf(input); - if(idx === -1) { - // prevent circular visitation - options.link[id].push(input); - } else { - // already visited - return options.link[id][idx]; - } - } else { - // prevent circular visitation - options.link[id] = [input]; - } + // 1110XXXX + if (i <= 2 && c >> 4 == 0x0E) { + this.charLength = 3; + break; } - // recurse through properties - for(var prop in input) { - var result = _removePreserve(ctx, input[prop], options); - var container = jsonld.getContextValue(ctx, prop, '@container'); - if(options.compactArrays && _isArray(result) && result.length === 1 && - container === null) { - result = result[0]; - } - input[prop] = result; + // 11110XXX + if (i <= 3 && c >> 3 == 0x1E) { + this.charLength = 4; + break; } } - return input; -} + this.charReceived = i; +}; -/** - * Compares two strings first based on length and then lexicographically. - * - * @param a the first string. - * @param b the second string. - * - * @return -1 if a < b, 1 if a > b, 0 if a == b. - */ -function _compareShortestLeast(a, b) { - if(a.length < b.length) { - return -1; - } - if(b.length < a.length) { - return 1; - } - if(a === b) { - return 0; - } - return (a < b) ? -1 : 1; -} +StringDecoder.prototype.end = function(buffer) { + var res = ''; + if (buffer && buffer.length) + res = this.write(buffer); -/** - * Picks the preferred compaction term from the given inverse context entry. - * - * @param activeCtx the active context. - * @param iri the IRI to pick the term for. - * @param value the value to pick the term for. - * @param containers the preferred containers. - * @param typeOrLanguage either '@type' or '@language'. - * @param typeOrLanguageValue the preferred value for '@type' or '@language'. - * - * @return the preferred term. - */ -function _selectTerm( - activeCtx, iri, value, containers, typeOrLanguage, typeOrLanguageValue) { - if(typeOrLanguageValue === null) { - typeOrLanguageValue = '@null'; + if (this.charReceived) { + var cr = this.charReceived; + var buf = this.charBuffer; + var enc = this.encoding; + res += buf.slice(0, cr).toString(enc); } - // preferences for the value of @type or @language - var prefs = []; + return res; +}; - // determine prefs for @id based on whether or not value compacts to a term - if((typeOrLanguageValue === '@id' || typeOrLanguageValue === '@reverse') && - _isSubjectReference(value)) { - // prefer @reverse first - if(typeOrLanguageValue === '@reverse') { - prefs.push('@reverse'); - } - // try to compact value to a term - var term = _compactIri(activeCtx, value['@id'], null, {vocab: true}); - if(term in activeCtx.mappings && - activeCtx.mappings[term] && - activeCtx.mappings[term]['@id'] === value['@id']) { - // prefer @vocab - prefs.push.apply(prefs, ['@vocab', '@id']); - } else { - // prefer @id - prefs.push.apply(prefs, ['@id', '@vocab']); - } - } else { - prefs.push(typeOrLanguageValue); - } - prefs.push('@none'); +function passThroughWrite(buffer) { + return buffer.toString(this.encoding); +} - var containerMap = activeCtx.inverse[iri]; - for(var ci = 0; ci < containers.length; ++ci) { - // if container not available in the map, continue - var container = containers[ci]; - if(!(container in containerMap)) { - continue; - } +function utf16DetectIncompleteChar(buffer) { + this.charReceived = buffer.length % 2; + this.charLength = this.charReceived ? 2 : 0; +} - var typeOrLanguageValueMap = containerMap[container][typeOrLanguage]; - for(var pi = 0; pi < prefs.length; ++pi) { - // if type/language option not available in the map, continue - var pref = prefs[pi]; - if(!(pref in typeOrLanguageValueMap)) { - continue; - } +function base64DetectIncompleteChar(buffer) { + this.charReceived = buffer.length % 3; + this.charLength = this.charReceived ? 3 : 0; +} - // select term - return typeOrLanguageValueMap[pref]; - } - } +},{"buffer":4}],47:[function(_dereq_,module,exports){ +var nextTick = _dereq_('process/browser.js').nextTick; +var apply = Function.prototype.apply; +var slice = Array.prototype.slice; +var immediateIds = {}; +var nextImmediateId = 0; - return null; +// DOM APIs, for completeness + +exports.setTimeout = function() { + return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout); +}; +exports.setInterval = function() { + return new Timeout(apply.call(setInterval, window, arguments), clearInterval); +}; +exports.clearTimeout = +exports.clearInterval = function(timeout) { timeout.close(); }; + +function Timeout(id, clearFn) { + this._id = id; + this._clearFn = clearFn; } +Timeout.prototype.unref = Timeout.prototype.ref = function() {}; +Timeout.prototype.close = function() { + this._clearFn.call(window, this._id); +}; -/** - * Compacts an IRI or keyword into a term or prefix if it can be. If the - * IRI has an associated value it may be passed. - * - * @param activeCtx the active context to use. - * @param iri the IRI to compact. - * @param value the value to check or null. - * @param relativeTo options for how to compact IRIs: - * vocab: true to split after @vocab, false not to. - * @param reverse true if a reverse property is being compacted, false if not. - * - * @return the compacted term, prefix, keyword alias, or the original IRI. - */ -function _compactIri(activeCtx, iri, value, relativeTo, reverse) { - // can't compact null - if(iri === null) { - return iri; - } +// Does not start the time, just sets up the members needed. +exports.enroll = function(item, msecs) { + clearTimeout(item._idleTimeoutId); + item._idleTimeout = msecs; +}; - // default value and parent to null - if(_isUndefined(value)) { - value = null; - } - // default reverse to false - if(_isUndefined(reverse)) { - reverse = false; - } - relativeTo = relativeTo || {}; +exports.unenroll = function(item) { + clearTimeout(item._idleTimeoutId); + item._idleTimeout = -1; +}; - var inverseCtx = activeCtx.getInverse(); +exports._unrefActive = exports.active = function(item) { + clearTimeout(item._idleTimeoutId); - // if term is a keyword, it can only be compacted to a simple alias - if(_isKeyword(iri)) { - if(iri in inverseCtx) { - return inverseCtx[iri]['@none']['@type']['@none']; - } - return iri; + var msecs = item._idleTimeout; + if (msecs >= 0) { + item._idleTimeoutId = setTimeout(function onTimeout() { + if (item._onTimeout) + item._onTimeout(); + }, msecs); } +}; - // use inverse context to pick a term if iri is relative to vocab - if(relativeTo.vocab && iri in inverseCtx) { - var defaultLanguage = activeCtx['@language'] || '@none'; - - // prefer @index if available in value - var containers = []; - if(_isObject(value) && '@index' in value) { - containers.push('@index'); - } +// That's not how node.js implements it but the exposed api is the same. +exports.setImmediate = typeof setImmediate === "function" ? setImmediate : function(fn) { + var id = nextImmediateId++; + var args = arguments.length < 2 ? false : slice.call(arguments, 1); - // defaults for term selection based on type/language - var typeOrLanguage = '@language'; - var typeOrLanguageValue = '@null'; + immediateIds[id] = true; - if(reverse) { - typeOrLanguage = '@type'; - typeOrLanguageValue = '@reverse'; - containers.push('@set'); - } else if(_isList(value)) { - // choose the most specific term that works for all elements in @list - // only select @list containers if @index is NOT in value - if(!('@index' in value)) { - containers.push('@list'); - } - var list = value['@list']; - var commonLanguage = (list.length === 0) ? defaultLanguage : null; - var commonType = null; - for(var i = 0; i < list.length; ++i) { - var item = list[i]; - var itemLanguage = '@none'; - var itemType = '@none'; - if(_isValue(item)) { - if('@language' in item) { - itemLanguage = item['@language']; - } else if('@type' in item) { - itemType = item['@type']; - } else { - // plain literal - itemLanguage = '@null'; - } - } else { - itemType = '@id'; - } - if(commonLanguage === null) { - commonLanguage = itemLanguage; - } else if(itemLanguage !== commonLanguage && _isValue(item)) { - commonLanguage = '@none'; - } - if(commonType === null) { - commonType = itemType; - } else if(itemType !== commonType) { - commonType = '@none'; - } - // there are different languages and types in the list, so choose - // the most generic term, no need to keep iterating the list - if(commonLanguage === '@none' && commonType === '@none') { - break; - } - } - commonLanguage = commonLanguage || '@none'; - commonType = commonType || '@none'; - if(commonType !== '@none') { - typeOrLanguage = '@type'; - typeOrLanguageValue = commonType; - } else { - typeOrLanguageValue = commonLanguage; - } - } else { - if(_isValue(value)) { - if('@language' in value && !('@index' in value)) { - containers.push('@language'); - typeOrLanguageValue = value['@language']; - } else if('@type' in value) { - typeOrLanguage = '@type'; - typeOrLanguageValue = value['@type']; - } + nextTick(function onNextTick() { + if (immediateIds[id]) { + // fn.call() is faster so we optimize for the common use-case + // @see http://jsperf.com/call-apply-segu + if (args) { + fn.apply(null, args); } else { - typeOrLanguage = '@type'; - typeOrLanguageValue = '@id'; + fn.call(null); } - containers.push('@set'); - } - - // do term selection - containers.push('@none'); - var term = _selectTerm( - activeCtx, iri, value, containers, typeOrLanguage, typeOrLanguageValue); - if(term !== null) { - return term; + // Prevent ids from leaking + exports.clearImmediate(id); } - } + }); - // no term match, use @vocab if available - if(relativeTo.vocab) { - if('@vocab' in activeCtx) { - // determine if vocab is a prefix of the iri - var vocab = activeCtx['@vocab']; - if(iri.indexOf(vocab) === 0 && iri !== vocab) { - // use suffix as relative iri if it is not a term in the active context - var suffix = iri.substr(vocab.length); - if(!(suffix in activeCtx.mappings)) { - return suffix; - } - } - } - } + return id; +}; - // no term or @vocab match, check for possible CURIEs - var choice = null; - var idx = 0; - var partialMatches = []; - var iriMap = activeCtx.fastCurieMap; - // check for partial matches of against `iri`, which means look until - // iri.length - 1, not full length - var maxPartialLength = iri.length - 1; - for(; idx < maxPartialLength && iri[idx] in iriMap; ++idx) { - iriMap = iriMap[iri[idx]]; - if('' in iriMap) { - partialMatches.push(iriMap[''][0]); - } - } - // check partial matches in reverse order to prefer longest ones first - for(var i = partialMatches.length - 1; i >= 0; --i) { - var entry = partialMatches[i]; - var terms = entry.terms; - for(var ti = 0; ti < terms.length; ++ti) { - // a CURIE is usable if: - // 1. it has no mapping, OR - // 2. value is null, which means we're not compacting an @value, AND - // the mapping matches the IRI - var curie = terms[ti] + ':' + iri.substr(entry.iri.length); - var isUsableCurie = (!(curie in activeCtx.mappings) || - (value === null && activeCtx.mappings[curie]['@id'] === iri)); +exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : function(id) { + delete immediateIds[id]; +}; +},{"process/browser.js":12}],48:[function(_dereq_,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. - // select curie if it is shorter or the same length but lexicographically - // less than the current choice - if(isUsableCurie && (choice === null || - _compareShortestLeast(curie, choice) < 0)) { - choice = curie; - } - } - } +var punycode = _dereq_('punycode'); - // return chosen curie - if(choice !== null) { - return choice; - } +exports.parse = urlParse; +exports.resolve = urlResolve; +exports.resolveObject = urlResolveObject; +exports.format = urlFormat; - // compact IRI relative to base - if(!relativeTo.vocab) { - return _removeBase(activeCtx['@base'], iri); - } +exports.Url = Url; - // return IRI as is - return iri; +function Url() { + this.protocol = null; + this.slashes = null; + this.auth = null; + this.host = null; + this.port = null; + this.hostname = null; + this.hash = null; + this.search = null; + this.query = null; + this.pathname = null; + this.path = null; + this.href = null; } -/** - * Performs value compaction on an object with '@value' or '@id' as the only - * property. - * - * @param activeCtx the active context. - * @param activeProperty the active property that points to the value. - * @param value the value to compact. - * - * @return the compaction result. - */ -function _compactValue(activeCtx, activeProperty, value) { - // value is a @value - if(_isValue(value)) { - // get context rules - var type = jsonld.getContextValue(activeCtx, activeProperty, '@type'); - var language = jsonld.getContextValue( - activeCtx, activeProperty, '@language'); - var container = jsonld.getContextValue( - activeCtx, activeProperty, '@container'); - - // whether or not the value has an @index that must be preserved - var preserveIndex = (('@index' in value) && - container !== '@index'); - - // if there's no @index to preserve ... - if(!preserveIndex) { - // matching @type or @language specified in context, compact value - if(value['@type'] === type || value['@language'] === language) { - return value['@value']; - } - } +// Reference: RFC 3986, RFC 1808, RFC 2396 - // return just the value of @value if all are true: - // 1. @value is the only key or @index isn't being preserved - // 2. there is no default language or @value is not a string or - // the key has a mapping with a null @language - var keyCount = Object.keys(value).length; - var isValueOnlyKey = (keyCount === 1 || - (keyCount === 2 && ('@index' in value) && !preserveIndex)); - var hasDefaultLanguage = ('@language' in activeCtx); - var isValueString = _isString(value['@value']); - var hasNullMapping = (activeCtx.mappings[activeProperty] && - activeCtx.mappings[activeProperty]['@language'] === null); - if(isValueOnlyKey && - (!hasDefaultLanguage || !isValueString || hasNullMapping)) { - return value['@value']; - } +// define these here so at least they only have to be +// compiled once on the first module load. +var protocolPattern = /^([a-z0-9.+-]+:)/i, + portPattern = /:[0-9]*$/, - var rval = {}; + // RFC 2396: characters reserved for delimiting URLs. + // We actually just auto-escape these. + delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'], - // preserve @index - if(preserveIndex) { - rval[_compactIri(activeCtx, '@index')] = value['@index']; - } + // RFC 2396: characters not allowed for various reasons. + unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims), - if('@type' in value) { - // compact @type IRI - rval[_compactIri(activeCtx, '@type')] = _compactIri( - activeCtx, value['@type'], null, {vocab: true}); - } else if('@language' in value) { - // alias @language - rval[_compactIri(activeCtx, '@language')] = value['@language']; - } - - // alias @value - rval[_compactIri(activeCtx, '@value')] = value['@value']; - - return rval; - } - - // value is a subject reference - var expandedProperty = _expandIri(activeCtx, activeProperty, {vocab: true}); - var type = jsonld.getContextValue(activeCtx, activeProperty, '@type'); - var compacted = _compactIri( - activeCtx, value['@id'], null, {vocab: type === '@vocab'}); + // Allowed by RFCs, but cause of XSS attacks. Always escape these. + autoEscape = ['\''].concat(unwise), + // Characters that are never ever allowed in a hostname. + // Note that any invalid chars are also handled, but these + // are the ones that are *expected* to be seen, so we fast-path + // them. + nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape), + hostEndingChars = ['/', '?', '#'], + hostnameMaxLen = 255, + hostnamePartPattern = /^[a-z0-9A-Z_-]{0,63}$/, + hostnamePartStart = /^([a-z0-9A-Z_-]{0,63})(.*)$/, + // protocols that can allow "unsafe" and "unwise" chars. + unsafeProtocol = { + 'javascript': true, + 'javascript:': true + }, + // protocols that never have a hostname. + hostlessProtocol = { + 'javascript': true, + 'javascript:': true + }, + // protocols that always contain a // bit. + slashedProtocol = { + 'http': true, + 'https': true, + 'ftp': true, + 'gopher': true, + 'file': true, + 'http:': true, + 'https:': true, + 'ftp:': true, + 'gopher:': true, + 'file:': true + }, + querystring = _dereq_('querystring'); - // compact to scalar - if(type === '@id' || type === '@vocab' || expandedProperty === '@graph') { - return compacted; - } +function urlParse(url, parseQueryString, slashesDenoteHost) { + if (url && isObject(url) && url instanceof Url) return url; - var rval = {}; - rval[_compactIri(activeCtx, '@id')] = compacted; - return rval; + var u = new Url; + u.parse(url, parseQueryString, slashesDenoteHost); + return u; } -/** - * Creates a term definition during context processing. - * - * @param activeCtx the current active context. - * @param localCtx the local context being processed. - * @param term the term in the local context to define the mapping for. - * @param defined a map of defining/defined keys to detect cycles and prevent - * double definitions. - */ -function _createTermDefinition(activeCtx, localCtx, term, defined) { - if(term in defined) { - // term already defined - if(defined[term]) { - return; - } - // cycle detected - throw new JsonLdError( - 'Cyclical context definition detected.', - 'jsonld.CyclicalContext', - {code: 'cyclic IRI mapping', context: localCtx, term: term}); +Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { + if (!isString(url)) { + throw new TypeError("Parameter 'url' must be a string, not " + typeof url); } - // now defining term - defined[term] = false; - - if(_isKeyword(term)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; keywords cannot be overridden.', - 'jsonld.SyntaxError', - {code: 'keyword redefinition', context: localCtx, term: term}); - } + var rest = url; - if(term === '') { - throw new JsonLdError( - 'Invalid JSON-LD syntax; a term cannot be an empty string.', - 'jsonld.SyntaxError', - {code: 'invalid term definition', context: localCtx}); - } + // trim before proceeding. + // This is to support parse stuff like " http://foo.com \n" + rest = rest.trim(); - // remove old mapping - if(activeCtx.mappings[term]) { - delete activeCtx.mappings[term]; + var proto = protocolPattern.exec(rest); + if (proto) { + proto = proto[0]; + var lowerProto = proto.toLowerCase(); + this.protocol = lowerProto; + rest = rest.substr(proto.length); } - // get context term value - var value = localCtx[term]; - - // clear context entry - if(value === null || (_isObject(value) && value['@id'] === null)) { - activeCtx.mappings[term] = null; - defined[term] = true; - return; + // figure out if it's got a host + // user@server is *always* interpreted as a hostname, and url + // resolution will treat //foo/bar as host=foo,path=bar because that's + // how the browser resolves relative URLs. + if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) { + var slashes = rest.substr(0, 2) === '//'; + if (slashes && !(proto && hostlessProtocol[proto])) { + rest = rest.substr(2); + this.slashes = true; + } } - // convert short-hand value to object w/@id - if(_isString(value)) { - value = {'@id': value}; - } + if (!hostlessProtocol[proto] && + (slashes || (proto && !slashedProtocol[proto]))) { - if(!_isObject(value)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; @context property values must be ' + - 'strings or objects.', - 'jsonld.SyntaxError', - {code: 'invalid term definition', context: localCtx}); - } + // there's a hostname. + // the first instance of /, ?, ;, or # ends the host. + // + // If there is an @ in the hostname, then non-host chars *are* allowed + // to the left of the last @ sign, unless some host-ending character + // comes *before* the @-sign. + // URLs are obnoxious. + // + // ex: + // http://a@b@c/ => user:a@b host:c + // http://a@b?@c => user:a host:c path:/?@c - // create new mapping - var mapping = activeCtx.mappings[term] = {}; - mapping.reverse = false; + // v0.12 TODO(isaacs): This is not quite how Chrome does things. + // Review our test case against browsers more comprehensively. - if('@reverse' in value) { - if('@id' in value) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; a @reverse term definition must not ' + - 'contain @id.', 'jsonld.SyntaxError', - {code: 'invalid reverse property', context: localCtx}); - } - var reverse = value['@reverse']; - if(!_isString(reverse)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; a @context @reverse value must be a string.', - 'jsonld.SyntaxError', {code: 'invalid IRI mapping', context: localCtx}); + // find the first instance of any hostEndingChars + var hostEnd = -1; + for (var i = 0; i < hostEndingChars.length; i++) { + var hec = rest.indexOf(hostEndingChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) + hostEnd = hec; } - // expand and add @id mapping - var id = _expandIri( - activeCtx, reverse, {vocab: true, base: false}, localCtx, defined); - if(!_isAbsoluteIri(id)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; a @context @reverse value must be an ' + - 'absolute IRI or a blank node identifier.', - 'jsonld.SyntaxError', {code: 'invalid IRI mapping', context: localCtx}); + // at this point, either we have an explicit point where the + // auth portion cannot go past, or the last @ char is the decider. + var auth, atSign; + if (hostEnd === -1) { + // atSign can be anywhere. + atSign = rest.lastIndexOf('@'); + } else { + // atSign must be in auth portion. + // http://a@b/c@d => host:b auth:a path:/c@d + atSign = rest.lastIndexOf('@', hostEnd); } - mapping['@id'] = id; - mapping.reverse = true; - } else if('@id' in value) { - var id = value['@id']; - if(!_isString(id)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; a @context @id value must be an array ' + - 'of strings or a string.', - 'jsonld.SyntaxError', {code: 'invalid IRI mapping', context: localCtx}); + + // Now we have a portion which is definitely the auth. + // Pull that off. + if (atSign !== -1) { + auth = rest.slice(0, atSign); + rest = rest.slice(atSign + 1); + this.auth = decodeURIComponent(auth); } - if(id !== term) { - // expand and add @id mapping - id = _expandIri( - activeCtx, id, {vocab: true, base: false}, localCtx, defined); - if(!_isAbsoluteIri(id) && !_isKeyword(id)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; a @context @id value must be an ' + - 'absolute IRI, a blank node identifier, or a keyword.', - 'jsonld.SyntaxError', - {code: 'invalid IRI mapping', context: localCtx}); - } - mapping['@id'] = id; + + // the host is the remaining to the left of the first non-host char + hostEnd = -1; + for (var i = 0; i < nonHostChars.length; i++) { + var hec = rest.indexOf(nonHostChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) + hostEnd = hec; } - } + // if we still have not hit it, then the entire thing is a host. + if (hostEnd === -1) + hostEnd = rest.length; - // always compute whether term has a colon as an optimization for - // _compactIri - var colon = term.indexOf(':'); - mapping._termHasColon = (colon !== -1); + this.host = rest.slice(0, hostEnd); + rest = rest.slice(hostEnd); - if(!('@id' in mapping)) { - // see if the term has a prefix - if(mapping._termHasColon) { - var prefix = term.substr(0, colon); - if(prefix in localCtx) { - // define parent prefix - _createTermDefinition(activeCtx, localCtx, prefix, defined); - } + // pull out port. + this.parseHost(); - if(activeCtx.mappings[prefix]) { - // set @id based on prefix parent - var suffix = term.substr(colon + 1); - mapping['@id'] = activeCtx.mappings[prefix]['@id'] + suffix; - } else { - // term is an absolute IRI - mapping['@id'] = term; - } - } else { - // non-IRIs *must* define @ids if @vocab is not available - if(!('@vocab' in activeCtx)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; @context terms must define an @id.', - 'jsonld.SyntaxError', - {code: 'invalid IRI mapping', context: localCtx, term: term}); + // we've indicated that there is a hostname, + // so even if it's empty, it has to be present. + this.hostname = this.hostname || ''; + + // if hostname begins with [ and ends with ] + // assume that it's an IPv6 address. + var ipv6Hostname = this.hostname[0] === '[' && + this.hostname[this.hostname.length - 1] === ']'; + + // validate a little. + if (!ipv6Hostname) { + var hostparts = this.hostname.split(/\./); + for (var i = 0, l = hostparts.length; i < l; i++) { + var part = hostparts[i]; + if (!part) continue; + if (!part.match(hostnamePartPattern)) { + var newpart = ''; + for (var j = 0, k = part.length; j < k; j++) { + if (part.charCodeAt(j) > 127) { + // we replace non-ASCII char with a temporary placeholder + // we need this to make sure size of hostname is not + // broken by replacing non-ASCII by nothing + newpart += 'x'; + } else { + newpart += part[j]; + } + } + // we test again with ASCII char only + if (!newpart.match(hostnamePartPattern)) { + var validParts = hostparts.slice(0, i); + var notHost = hostparts.slice(i + 1); + var bit = part.match(hostnamePartStart); + if (bit) { + validParts.push(bit[1]); + notHost.unshift(bit[2]); + } + if (notHost.length) { + rest = '/' + notHost.join('.') + rest; + } + this.hostname = validParts.join('.'); + break; + } + } } - // prepend vocab to term - mapping['@id'] = activeCtx['@vocab'] + term; } - } - - // IRI mapping now defined - defined[term] = true; - if('@type' in value) { - var type = value['@type']; - if(!_isString(type)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; an @context @type values must be a string.', - 'jsonld.SyntaxError', - {code: 'invalid type mapping', context: localCtx}); + if (this.hostname.length > hostnameMaxLen) { + this.hostname = ''; + } else { + // hostnames are always lower case. + this.hostname = this.hostname.toLowerCase(); } - if(type !== '@id' && type !== '@vocab') { - // expand @type to full IRI - type = _expandIri( - activeCtx, type, {vocab: true, base: false}, localCtx, defined); - if(!_isAbsoluteIri(type)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; an @context @type value must be an ' + - 'absolute IRI.', - 'jsonld.SyntaxError', - {code: 'invalid type mapping', context: localCtx}); - } - if(type.indexOf('_:') === 0) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; an @context @type values must be an IRI, ' + - 'not a blank node identifier.', - 'jsonld.SyntaxError', - {code: 'invalid type mapping', context: localCtx}); + if (!ipv6Hostname) { + // IDNA Support: Returns a puny coded representation of "domain". + // It only converts the part of the domain name that + // has non ASCII characters. I.e. it dosent matter if + // you call it with a domain that already is in ASCII. + var domainArray = this.hostname.split('.'); + var newOut = []; + for (var i = 0; i < domainArray.length; ++i) { + var s = domainArray[i]; + newOut.push(s.match(/[^A-Za-z0-9_-]/) ? + 'xn--' + punycode.encode(s) : s); } + this.hostname = newOut.join('.'); } - // add @type to mapping - mapping['@type'] = type; - } + var p = this.port ? ':' + this.port : ''; + var h = this.hostname || ''; + this.host = h + p; + this.href += this.host; - if('@container' in value) { - var container = value['@container']; - if(container !== '@list' && container !== '@set' && - container !== '@index' && container !== '@language') { - throw new JsonLdError( - 'Invalid JSON-LD syntax; @context @container value must be ' + - 'one of the following: @list, @set, @index, or @language.', - 'jsonld.SyntaxError', - {code: 'invalid container mapping', context: localCtx}); - } - if(mapping.reverse && container !== '@index' && container !== '@set' && - container !== null) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; @context @container value for a @reverse ' + - 'type definition must be @index or @set.', 'jsonld.SyntaxError', - {code: 'invalid reverse property', context: localCtx}); + // strip [ and ] from the hostname + // the host field still retains them, though + if (ipv6Hostname) { + this.hostname = this.hostname.substr(1, this.hostname.length - 2); + if (rest[0] !== '/') { + rest = '/' + rest; + } } - - // add @container to mapping - mapping['@container'] = container; } - if('@language' in value && !('@type' in value)) { - var language = value['@language']; - if(language !== null && !_isString(language)) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; @context @language value must be ' + - 'a string or null.', 'jsonld.SyntaxError', - {code: 'invalid language mapping', context: localCtx}); - } + // now rest is set to the post-host stuff. + // chop off any delim chars. + if (!unsafeProtocol[lowerProto]) { - // add @language to mapping - if(language !== null) { - language = language.toLowerCase(); + // First, make 100% sure that any "autoEscape" chars get + // escaped, even if encodeURIComponent doesn't think they + // need to be. + for (var i = 0, l = autoEscape.length; i < l; i++) { + var ae = autoEscape[i]; + var esc = encodeURIComponent(ae); + if (esc === ae) { + esc = escape(ae); + } + rest = rest.split(ae).join(esc); } - mapping['@language'] = language; } - // disallow aliasing @context and @preserve - var id = mapping['@id']; - if(id === '@context' || id === '@preserve') { - throw new JsonLdError( - 'Invalid JSON-LD syntax; @context and @preserve cannot be aliased.', - 'jsonld.SyntaxError', {code: 'invalid keyword alias', context: localCtx}); + + // chop off from the tail first. + var hash = rest.indexOf('#'); + if (hash !== -1) { + // got a fragment string. + this.hash = rest.substr(hash); + rest = rest.slice(0, hash); + } + var qm = rest.indexOf('?'); + if (qm !== -1) { + this.search = rest.substr(qm); + this.query = rest.substr(qm + 1); + if (parseQueryString) { + this.query = querystring.parse(this.query); + } + rest = rest.slice(0, qm); + } else if (parseQueryString) { + // no query string, but parseQueryString still requested + this.search = ''; + this.query = {}; + } + if (rest) this.pathname = rest; + if (slashedProtocol[lowerProto] && + this.hostname && !this.pathname) { + this.pathname = '/'; } -} -/** - * Expands a string to a full IRI. The string may be a term, a prefix, a - * relative IRI, or an absolute IRI. The associated absolute IRI will be - * returned. - * - * @param activeCtx the current active context. - * @param value the string to expand. - * @param relativeTo options for how to resolve relative IRIs: - * base: true to resolve against the base IRI, false not to. - * vocab: true to concatenate after @vocab, false not to. - * @param localCtx the local context being processed (only given if called - * during context processing). - * @param defined a map for tracking cycles in context definitions (only given - * if called during context processing). - * - * @return the expanded value. - */ -function _expandIri(activeCtx, value, relativeTo, localCtx, defined) { - // already expanded - if(value === null || _isKeyword(value)) { - return value; + //to support http.request + if (this.pathname || this.search) { + var p = this.pathname || ''; + var s = this.search || ''; + this.path = p + s; } - // ensure value is interpreted as a string - value = String(value); + // finally, reconstruct the href based on what has been validated. + this.href = this.format(); + return this; +}; - // define term dependency if not defined - if(localCtx && value in localCtx && defined[value] !== true) { - _createTermDefinition(activeCtx, localCtx, value, defined); +// format a parsed object into a url string +function urlFormat(obj) { + // ensure it's an object, and not a string url. + // If it's an obj, this is a no-op. + // this way, you can call url_format() on strings + // to clean up potentially wonky urls. + if (isString(obj)) obj = urlParse(obj); + if (!(obj instanceof Url)) return Url.prototype.format.call(obj); + return obj.format(); +} + +Url.prototype.format = function() { + var auth = this.auth || ''; + if (auth) { + auth = encodeURIComponent(auth); + auth = auth.replace(/%3A/i, ':'); + auth += '@'; } - relativeTo = relativeTo || {}; - if(relativeTo.vocab) { - var mapping = activeCtx.mappings[value]; + var protocol = this.protocol || '', + pathname = this.pathname || '', + hash = this.hash || '', + host = false, + query = ''; - // value is explicitly ignored with a null mapping - if(mapping === null) { - return null; + if (this.host) { + host = auth + this.host; + } else if (this.hostname) { + host = auth + (this.hostname.indexOf(':') === -1 ? + this.hostname : + '[' + this.hostname + ']'); + if (this.port) { + host += ':' + this.port; } + } - if(mapping) { - // value is a term - return mapping['@id']; - } + if (this.query && + isObject(this.query) && + Object.keys(this.query).length) { + query = querystring.stringify(this.query); } - // split value into prefix:suffix - var colon = value.indexOf(':'); - if(colon !== -1) { - var prefix = value.substr(0, colon); - var suffix = value.substr(colon + 1); + var search = this.search || (query && ('?' + query)) || ''; - // do not expand blank nodes (prefix of '_') or already-absolute - // IRIs (suffix of '//') - if(prefix === '_' || suffix.indexOf('//') === 0) { - return value; - } + if (protocol && protocol.substr(-1) !== ':') protocol += ':'; - // prefix dependency not defined, define it - if(localCtx && prefix in localCtx) { - _createTermDefinition(activeCtx, localCtx, prefix, defined); - } + // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. + // unless they had them to begin with. + if (this.slashes || + (!protocol || slashedProtocol[protocol]) && host !== false) { + host = '//' + (host || ''); + if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname; + } else if (!host) { + host = ''; + } - // use mapping if prefix is defined - var mapping = activeCtx.mappings[prefix]; - if(mapping) { - return mapping['@id'] + suffix; - } + if (hash && hash.charAt(0) !== '#') hash = '#' + hash; + if (search && search.charAt(0) !== '?') search = '?' + search; - // already absolute IRI - return value; - } + pathname = pathname.replace(/[?#]/g, function(match) { + return encodeURIComponent(match); + }); + search = search.replace('#', '%23'); - // prepend vocab - if(relativeTo.vocab && '@vocab' in activeCtx) { - return activeCtx['@vocab'] + value; - } + return protocol + host + pathname + search + hash; +}; - // prepend base - var rval = value; - if(relativeTo.base) { - rval = jsonld.prependBase(activeCtx['@base'], rval); - } +function urlResolve(source, relative) { + return urlParse(source, false, true).resolve(relative); +} - return rval; +Url.prototype.resolve = function(relative) { + return this.resolveObject(urlParse(relative, false, true)).format(); +}; + +function urlResolveObject(source, relative) { + if (!source) return relative; + return urlParse(source, false, true).resolveObject(relative); } -function _prependBase(base, iri) { - // skip IRI processing - if(base === null) { - return iri; - } - // already an absolute IRI - if(iri.indexOf(':') !== -1) { - return iri; +Url.prototype.resolveObject = function(relative) { + if (isString(relative)) { + var rel = new Url(); + rel.parse(relative, false, true); + relative = rel; } - // parse base if it is a string - if(_isString(base)) { - base = jsonld.url.parse(base || ''); + var result = new Url(); + Object.keys(this).forEach(function(k) { + result[k] = this[k]; + }, this); + + // hash is always overridden, no matter what. + // even href="" will remove it. + result.hash = relative.hash; + + // if the relative url is empty, then there's nothing left to do here. + if (relative.href === '') { + result.href = result.format(); + return result; } - // parse given IRI - var rel = jsonld.url.parse(iri); + // hrefs like //foo/bar always cut to the protocol. + if (relative.slashes && !relative.protocol) { + // take everything except the protocol from relative + Object.keys(relative).forEach(function(k) { + if (k !== 'protocol') + result[k] = relative[k]; + }); - // per RFC3986 5.2.2 - var transform = { - protocol: base.protocol || '' - }; + //urlParse appends trailing / to urls like http://www.example.com + if (slashedProtocol[result.protocol] && + result.hostname && !result.pathname) { + result.path = result.pathname = '/'; + } - if(rel.authority !== null) { - transform.authority = rel.authority; - transform.path = rel.path; - transform.query = rel.query; - } else { - transform.authority = base.authority; + result.href = result.format(); + return result; + } - if(rel.path === '') { - transform.path = base.path; - if(rel.query !== null) { - transform.query = rel.query; - } else { - transform.query = base.query; - } + if (relative.protocol && relative.protocol !== result.protocol) { + // if it's a known url protocol, then changing + // the protocol does weird things + // first, if it's not file:, then we MUST have a host, + // and if there was a path + // to begin with, then we MUST have a path. + // if it is file:, then the host is dropped, + // because that's known to be hostless. + // anything else is assumed to be absolute. + if (!slashedProtocol[relative.protocol]) { + Object.keys(relative).forEach(function(k) { + result[k] = relative[k]; + }); + result.href = result.format(); + return result; + } + + result.protocol = relative.protocol; + if (!relative.host && !hostlessProtocol[relative.protocol]) { + var relPath = (relative.pathname || '').split('/'); + while (relPath.length && !(relative.host = relPath.shift())); + if (!relative.host) relative.host = ''; + if (!relative.hostname) relative.hostname = ''; + if (relPath[0] !== '') relPath.unshift(''); + if (relPath.length < 2) relPath.unshift(''); + result.pathname = relPath.join('/'); } else { - if(rel.path.indexOf('/') === 0) { - // IRI represents an absolute path - transform.path = rel.path; - } else { - // merge paths - var path = base.path; + result.pathname = relative.pathname; + } + result.search = relative.search; + result.query = relative.query; + result.host = relative.host || ''; + result.auth = relative.auth; + result.hostname = relative.hostname || relative.host; + result.port = relative.port; + // to support http.request + if (result.pathname || result.search) { + var p = result.pathname || ''; + var s = result.search || ''; + result.path = p + s; + } + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; + } - // append relative path to the end of the last directory from base - if(rel.path !== '') { - path = path.substr(0, path.lastIndexOf('/') + 1); - if(path.length > 0 && path.substr(-1) !== '/') { - path += '/'; - } - path += rel.path; - } + var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'), + isRelAbs = ( + relative.host || + relative.pathname && relative.pathname.charAt(0) === '/' + ), + mustEndAbs = (isRelAbs || isSourceAbs || + (result.host && relative.pathname)), + removeAllDots = mustEndAbs, + srcPath = result.pathname && result.pathname.split('/') || [], + relPath = relative.pathname && relative.pathname.split('/') || [], + psychotic = result.protocol && !slashedProtocol[result.protocol]; - transform.path = path; + // if the url is a non-slashed url, then relative + // links like ../.. should be able + // to crawl up to the hostname, as well. This is strange. + // result.protocol has already been set by now. + // Later on, put the first path part into the host field. + if (psychotic) { + result.hostname = ''; + result.port = null; + if (result.host) { + if (srcPath[0] === '') srcPath[0] = result.host; + else srcPath.unshift(result.host); + } + result.host = ''; + if (relative.protocol) { + relative.hostname = null; + relative.port = null; + if (relative.host) { + if (relPath[0] === '') relPath[0] = relative.host; + else relPath.unshift(relative.host); } - transform.query = rel.query; + relative.host = null; } + mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); } - // remove slashes and dots in path - transform.path = _removeDotSegments(transform.path, !!transform.authority); - - // construct URL - var rval = transform.protocol; - if(transform.authority !== null) { - rval += '//' + transform.authority; - } - rval += transform.path; - if(transform.query !== null) { - rval += '?' + transform.query; - } - if(rel.fragment !== null) { - rval += '#' + rel.fragment; + if (isRelAbs) { + // it's absolute. + result.host = (relative.host || relative.host === '') ? + relative.host : result.host; + result.hostname = (relative.hostname || relative.hostname === '') ? + relative.hostname : result.hostname; + result.search = relative.search; + result.query = relative.query; + srcPath = relPath; + // fall through to the dot-handling below. + } else if (relPath.length) { + // it's relative + // throw away the existing file, and take the new path instead. + if (!srcPath) srcPath = []; + srcPath.pop(); + srcPath = srcPath.concat(relPath); + result.search = relative.search; + result.query = relative.query; + } else if (!isNullOrUndefined(relative.search)) { + // just pull out the search. + // like href='?foo'. + // Put this after the other two cases because it simplifies the booleans + if (psychotic) { + result.hostname = result.host = srcPath.shift(); + //occationaly the auth can get stuck only in host + //this especialy happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + var authInHost = result.host && result.host.indexOf('@') > 0 ? + result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } + result.search = relative.search; + result.query = relative.query; + //to support http.request + if (!isNull(result.pathname) || !isNull(result.search)) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); + } + result.href = result.format(); + return result; } - // handle empty base - if(rval === '') { - rval = './'; + if (!srcPath.length) { + // no path at all. easy. + // we've already handled the other stuff above. + result.pathname = null; + //to support http.request + if (result.search) { + result.path = '/' + result.search; + } else { + result.path = null; + } + result.href = result.format(); + return result; } - return rval; -} + // if a url ENDs in . or .., then it must get a trailing slash. + // however, if it ends in anything else non-slashy, + // then it must NOT get a trailing slash. + var last = srcPath.slice(-1)[0]; + var hasTrailingSlash = ( + (result.host || relative.host) && (last === '.' || last === '..') || + last === ''); -/** - * Removes a base IRI from the given absolute IRI. - * - * @param base the base IRI. - * @param iri the absolute IRI. - * - * @return the relative IRI if relative to base, otherwise the absolute IRI. - */ -function _removeBase(base, iri) { - // skip IRI processing - if(base === null) { - return iri; + // strip single dots, resolve double dots to parent dir + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = srcPath.length; i >= 0; i--) { + last = srcPath[i]; + if (last == '.') { + srcPath.splice(i, 1); + } else if (last === '..') { + srcPath.splice(i, 1); + up++; + } else if (up) { + srcPath.splice(i, 1); + up--; + } } - if(_isString(base)) { - base = jsonld.url.parse(base || ''); + // if the path is allowed to go above the root, restore leading ..s + if (!mustEndAbs && !removeAllDots) { + for (; up--; up) { + srcPath.unshift('..'); + } } - // establish base root - var root = ''; - if(base.href !== '') { - root += (base.protocol || '') + '//' + (base.authority || ''); - } else if(iri.indexOf('//')) { - // support network-path reference with empty base - root += '//'; + if (mustEndAbs && srcPath[0] !== '' && + (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { + srcPath.unshift(''); } - // IRI not relative to base - if(iri.indexOf(root) !== 0) { - return iri; + if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) { + srcPath.push(''); } - // remove root from IRI and parse remainder - var rel = jsonld.url.parse(iri.substr(root.length)); + var isAbsolute = srcPath[0] === '' || + (srcPath[0] && srcPath[0].charAt(0) === '/'); - // remove path segments that match (do not remove last segment unless there - // is a hash or query) - var baseSegments = base.normalizedPath.split('/'); - var iriSegments = rel.normalizedPath.split('/'); - var last = (rel.fragment || rel.query) ? 0 : 1; - while(baseSegments.length > 0 && iriSegments.length > last) { - if(baseSegments[0] !== iriSegments[0]) { - break; + // put the host back + if (psychotic) { + result.hostname = result.host = isAbsolute ? '' : + srcPath.length ? srcPath.shift() : ''; + //occationaly the auth can get stuck only in host + //this especialy happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + var authInHost = result.host && result.host.indexOf('@') > 0 ? + result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); } - baseSegments.shift(); - iriSegments.shift(); } - // use '../' for each non-matching base segment - var rval = ''; - if(baseSegments.length > 0) { - // don't count the last segment (if it ends with '/' last path doesn't - // count and if it doesn't end with '/' it isn't a path) - baseSegments.pop(); - for(var i = 0; i < baseSegments.length; ++i) { - rval += '../'; - } - } + mustEndAbs = mustEndAbs || (result.host && srcPath.length); - // prepend remaining segments - rval += iriSegments.join('/'); + if (mustEndAbs && !isAbsolute) { + srcPath.unshift(''); + } - // add query and hash - if(rel.query !== null) { - rval += '?' + rel.query; + if (!srcPath.length) { + result.pathname = null; + result.path = null; + } else { + result.pathname = srcPath.join('/'); } - if(rel.fragment !== null) { - rval += '#' + rel.fragment; + + //to support request.http + if (!isNull(result.pathname) || !isNull(result.search)) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); } + result.auth = relative.auth || result.auth; + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; +}; - // handle empty base - if(rval === '') { - rval = './'; +Url.prototype.parseHost = function() { + var host = this.host; + var port = portPattern.exec(host); + if (port) { + port = port[0]; + if (port !== ':') { + this.port = port.substr(1); + } + host = host.substr(0, host.length - port.length); } + if (host) this.hostname = host; +}; - return rval; +function isString(arg) { + return typeof arg === "string"; } -/** - * Gets the initial context. - * - * @param options the options to use: - * [base] the document base IRI. - * - * @return the initial context. - */ -function _getInitialContext(options) { - var base = jsonld.url.parse(options.base || ''); - return { - '@base': base, - mappings: {}, - inverse: null, - getInverse: _createInverseContext, - clone: _cloneActiveContext - }; +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} - /** - * Generates an inverse context for use in the compaction algorithm, if - * not already generated for the given active context. - * - * @return the inverse context. - */ - function _createInverseContext() { - var activeCtx = this; +function isNull(arg) { + return arg === null; +} +function isNullOrUndefined(arg) { + return arg == null; +} - // lazily create inverse - if(activeCtx.inverse) { - return activeCtx.inverse; - } - var inverse = activeCtx.inverse = {}; +},{"punycode":13,"querystring":16}],49:[function(_dereq_,module,exports){ +arguments[4][10][0].apply(exports,arguments) +},{"dup":10}],50:[function(_dereq_,module,exports){ +module.exports = function isBuffer(arg) { + return arg && typeof arg === 'object' + && typeof arg.copy === 'function' + && typeof arg.fill === 'function' + && typeof arg.readUInt8 === 'function'; +} +},{}],51:[function(_dereq_,module,exports){ +(function (process,global){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. - // variables for building fast CURIE map - var fastCurieMap = activeCtx.fastCurieMap = {}; - var irisToTerms = {}; - - // handle default language - var defaultLanguage = activeCtx['@language'] || '@none'; - - // create term selections for each mapping in the context, ordered by - // shortest and then lexicographically least - var mappings = activeCtx.mappings; - var terms = Object.keys(mappings).sort(_compareShortestLeast); - for(var i = 0; i < terms.length; ++i) { - var term = terms[i]; - var mapping = mappings[term]; - if(mapping === null) { - continue; - } - - var container = mapping['@container'] || '@none'; - - // iterate over every IRI in the mapping - var ids = mapping['@id']; - if(!_isArray(ids)) { - ids = [ids]; - } - for(var ii = 0; ii < ids.length; ++ii) { - var iri = ids[ii]; - var entry = inverse[iri]; - var isKeyword = _isKeyword(iri); - - if(!entry) { - // initialize entry - inverse[iri] = entry = {}; - - if(!isKeyword && !mapping._termHasColon) { - // init IRI to term map and fast CURIE prefixes - irisToTerms[iri] = [term]; - var fastCurieEntry = {iri: iri, terms: irisToTerms[iri]}; - if(iri[0] in fastCurieMap) { - fastCurieMap[iri[0]].push(fastCurieEntry); - } else { - fastCurieMap[iri[0]] = [fastCurieEntry]; - } - } - } else if(!isKeyword && !mapping._termHasColon) { - // add IRI to term match - irisToTerms[iri].push(term); - } - - // add new entry - if(!entry[container]) { - entry[container] = { - '@language': {}, - '@type': {} - }; - } - entry = entry[container]; - - if(mapping.reverse) { - // term is preferred for values using @reverse - _addPreferredTerm(mapping, term, entry['@type'], '@reverse'); - } else if('@type' in mapping) { - // term is preferred for values using specific type - _addPreferredTerm(mapping, term, entry['@type'], mapping['@type']); - } else if('@language' in mapping) { - // term is preferred for values using specific language - var language = mapping['@language'] || '@null'; - _addPreferredTerm(mapping, term, entry['@language'], language); - } else { - // term is preferred for values w/default language or no type and - // no language - // add an entry for the default language - _addPreferredTerm(mapping, term, entry['@language'], defaultLanguage); +var formatRegExp = /%[sdj%]/g; +exports.format = function(f) { + if (!isString(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } - // add entries for no type and no language - _addPreferredTerm(mapping, term, entry['@type'], '@none'); - _addPreferredTerm(mapping, term, entry['@language'], '@none'); + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; } - } + default: + return x; } - - // build fast CURIE map - for(var key in fastCurieMap) { - _buildIriMap(fastCurieMap, key, 1); + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); } + } + return str; +}; - return inverse; + +// Mark that a method should not be used. +// Returns a modified function which warns once by default. +// If --no-deprecation is set, then it is a no-op. +exports.deprecate = function(fn, msg) { + // Allow for deprecating things in the process of starting up. + if (isUndefined(global.process)) { + return function() { + return exports.deprecate(fn, msg).apply(this, arguments); + }; } - /** - * Runs a recursive algorithm to build a lookup map for quickly finding - * potential CURIEs. - * - * @param iriMap the map to build. - * @param key the current key in the map to work on. - * @param idx the index into the IRI to compare. - */ - function _buildIriMap(iriMap, key, idx) { - var entries = iriMap[key]; - var next = iriMap[key] = {}; + if (process.noDeprecation === true) { + return fn; + } - var iri; - var letter; - for(var i = 0; i < entries.length; ++i) { - iri = entries[i].iri; - if(idx >= iri.length) { - letter = ''; - } else { - letter = iri[idx]; - } - if(letter in next) { - next[letter].push(entries[i]); + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); } else { - next[letter] = [entries[i]]; - } - } - - for(var key in next) { - if(key === '') { - continue; + console.error(msg); } - _buildIriMap(next, key, idx + 1); + warned = true; } + return fn.apply(this, arguments); } - /** - * Adds the term for the given entry if not already added. - * - * @param mapping the term mapping. - * @param term the term to add. - * @param entry the inverse context typeOrLanguage entry to add to. - * @param typeOrLanguageValue the key in the entry to add to. - */ - function _addPreferredTerm(mapping, term, entry, typeOrLanguageValue) { - if(!(typeOrLanguageValue in entry)) { - entry[typeOrLanguageValue] = term; - } - } + return deprecated; +}; - /** - * Clones an active context, creating a child active context. - * - * @return a clone (child) of the active context. - */ - function _cloneActiveContext() { - var child = {}; - child['@base'] = this['@base']; - child.mappings = _clone(this.mappings); - child.clone = this.clone; - child.inverse = null; - child.getInverse = this.getInverse; - if('@language' in this) { - child['@language'] = this['@language']; - } - if('@vocab' in this) { - child['@vocab'] = this['@vocab']; + +var debugs = {}; +var debugEnviron; +exports.debuglog = function(set) { + if (isUndefined(debugEnviron)) + debugEnviron = process.env.NODE_DEBUG || ''; + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = process.pid; + debugs[set] = function() { + var msg = exports.format.apply(exports, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; } - return child; } -} + return debugs[set]; +}; + /** - * Returns whether or not the given value is a keyword. - * - * @param v the value to check. + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. * - * @return true if the value is a keyword, false if not. + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. */ -function _isKeyword(v) { - if(!_isString(v)) { - return false; - } - switch(v) { - case '@base': - case '@context': - case '@container': - case '@default': - case '@embed': - case '@explicit': - case '@graph': - case '@id': - case '@index': - case '@language': - case '@list': - case '@omitDefault': - case '@preserve': - case '@requireAll': - case '@reverse': - case '@set': - case '@type': - case '@value': - case '@vocab': - return true; +/* legacy: obj, showHidden, depth, colors*/ +function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + exports._extend(ctx, opts); } - return false; + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); } +exports.inspect = inspect; -/** - * Returns true if the given value is an Object. - * - * @param v the value to check. - * - * @return true if the value is an Object, false if not. - */ -function _isObject(v) { - return (Object.prototype.toString.call(v) === '[object Object]'); -} -/** - * Returns true if the given value is an empty Object. - * - * @param v the value to check. - * - * @return true if the value is an empty Object, false if not. - */ -function _isEmptyObject(v) { - return _isObject(v) && Object.keys(v).length === 0; -} +// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics +inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] +}; -/** - * Returns true if the given value is an Array. - * - * @param v the value to check. - * - * @return true if the value is an Array, false if not. - */ -function _isArray(v) { - return Array.isArray(v); -} +// Don't use 'blue' not visible on cmd.exe +inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' +}; -/** - * Throws an exception if the given value is not a valid @type value. - * - * @param v the value to check. - */ -function _validateTypeValue(v) { - // can be a string or an empty object - if(_isString(v) || _isEmptyObject(v)) { - return; - } - // must be an array - var isValid = false; - if(_isArray(v)) { - // must contain only strings - isValid = true; - for(var i = 0; i < v.length; ++i) { - if(!(_isString(v[i]))) { - isValid = false; - break; - } - } - } +function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; - if(!isValid) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; "@type" value must a string, an array of ' + - 'strings, or an empty object.', 'jsonld.SyntaxError', - {code: 'invalid type value', value: v}); + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; } } -/** - * Returns true if the given value is a String. - * - * @param v the value to check. - * - * @return true if the value is a String, false if not. - */ -function _isString(v) { - return (typeof v === 'string' || - Object.prototype.toString.call(v) === '[object String]'); -} -/** - * Returns true if the given value is a Number. - * - * @param v the value to check. - * - * @return true if the value is a Number, false if not. - */ -function _isNumber(v) { - return (typeof v === 'number' || - Object.prototype.toString.call(v) === '[object Number]'); +function stylizeNoColor(str, styleType) { + return str; } -/** - * Returns true if the given value is a double. - * - * @param v the value to check. - * - * @return true if the value is a double, false if not. - */ -function _isDouble(v) { - return _isNumber(v) && String(v).indexOf('.') !== -1; -} -/** - * Returns true if the given value is numeric. - * - * @param v the value to check. - * - * @return true if the value is numeric, false if not. - */ -function _isNumeric(v) { - return !isNaN(parseFloat(v)) && isFinite(v); -} +function arrayToHash(array) { + var hash = {}; -/** - * Returns true if the given value is a Boolean. - * - * @param v the value to check. - * - * @return true if the value is a Boolean, false if not. - */ -function _isBoolean(v) { - return (typeof v === 'boolean' || - Object.prototype.toString.call(v) === '[object Boolean]'); -} + array.forEach(function(val, idx) { + hash[val] = true; + }); -/** - * Returns true if the given value is undefined. - * - * @param v the value to check. - * - * @return true if the value is undefined, false if not. - */ -function _isUndefined(v) { - return (typeof v === 'undefined'); + return hash; } -/** - * Returns true if the given value is a subject with properties. - * - * @param v the value to check. - * - * @return true if the value is a subject with properties, false if not. - */ -function _isSubject(v) { - // Note: A value is a subject if all of these hold true: - // 1. It is an Object. - // 2. It is not a @value, @set, or @list. - // 3. It has more than 1 key OR any existing key is not @id. - var rval = false; - if(_isObject(v) && - !(('@value' in v) || ('@set' in v) || ('@list' in v))) { - var keyCount = Object.keys(v).length; - rval = (keyCount > 1 || !('@id' in v)); + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; } - return rval; -} -/** - * Returns true if the given value is a subject reference. - * - * @param v the value to check. - * - * @return true if the value is a subject reference, false if not. - */ -function _isSubjectReference(v) { - // Note: A value is a subject reference if all of these hold true: - // 1. It is an Object. - // 2. It has a single key: @id. - return (_isObject(v) && Object.keys(v).length === 1 && ('@id' in v)); -} + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } -/** - * Returns true if the given value is a @value. - * - * @param v the value to check. - * - * @return true if the value is a @value, false if not. - */ -function _isValue(v) { - // Note: A value is a @value if all of these hold true: - // 1. It is an Object. - // 2. It has the @value property. - return _isObject(v) && ('@value' in v); -} + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); -/** - * Returns true if the given value is a @list. - * - * @param v the value to check. - * - * @return true if the value is a @list, false if not. - */ -function _isList(v) { - // Note: A value is a @list if all of these hold true: - // 1. It is an Object. - // 2. It has the @list property. - return _isObject(v) && ('@list' in v); -} - -/** - * Returns true if the given value is a blank node. - * - * @param v the value to check. - * - * @return true if the value is a blank node, false if not. - */ -function _isBlankNode(v) { - // Note: A value is a blank node if all of these hold true: - // 1. It is an Object. - // 2. If it has an @id key its value begins with '_:'. - // 3. It has no keys OR is not a @value, @set, or @list. - var rval = false; - if(_isObject(v)) { - if('@id' in v) { - rval = (v['@id'].indexOf('_:') === 0); - } else { - rval = (Object.keys(v).length === 0 || - !(('@value' in v) || ('@set' in v) || ('@list' in v))); - } + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); } - return rval; -} -/** - * Returns true if the given value is an absolute IRI, false if not. - * - * @param v the value to check. - * - * @return true if the value is an absolute IRI, false if not. - */ -function _isAbsoluteIri(v) { - return _isString(v) && v.indexOf(':') !== -1; -} + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } -/** - * Clones an object, array, or string/number. If a typed JavaScript object - * is given, such as a Date, it will be converted to a string. - * - * @param value the value to clone. - * - * @return the cloned value. - */ -function _clone(value) { - if(value && typeof value === 'object') { - var rval; - if(_isArray(value)) { - rval = []; - for(var i = 0; i < value.length; ++i) { - rval[i] = _clone(value[i]); - } - } else if(_isObject(value)) { - rval = {}; - for(var key in value) { - rval[key] = _clone(value[key]); - } - } else { - rval = value.toString(); + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); } - return rval; } - return value; -} -/** - * Finds all @context URLs in the given JSON-LD input. - * - * @param input the JSON-LD input. - * @param urls a map of URLs (url => false/@contexts). - * @param replace true to replace the URLs in the given input with the - * @contexts from the urls map, false not to. - * @param base the base IRI to use to resolve relative IRIs. - * - * @return true if new URLs to retrieve were found, false if not. - */ -function _findContextUrls(input, urls, replace, base) { - var count = Object.keys(urls).length; - if(_isArray(input)) { - for(var i = 0; i < input.length; ++i) { - _findContextUrls(input[i], urls, replace, base); - } - return (count < Object.keys(urls).length); - } else if(_isObject(input)) { - for(var key in input) { - if(key !== '@context') { - _findContextUrls(input[key], urls, replace, base); - continue; - } + var base = '', array = false, braces = ['{', '}']; - // get @context - var ctx = input[key]; + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } - // array @context - if(_isArray(ctx)) { - var length = ctx.length; - for(var i = 0; i < length; ++i) { - var _ctx = ctx[i]; - if(_isString(_ctx)) { - _ctx = jsonld.prependBase(base, _ctx); - // replace w/@context if requested - if(replace) { - _ctx = urls[_ctx]; - if(_isArray(_ctx)) { - // add flattened context - Array.prototype.splice.apply(ctx, [i, 1].concat(_ctx)); - i += _ctx.length - 1; - length = ctx.length; - } else { - ctx[i] = _ctx; - } - } else if(!(_ctx in urls)) { - // @context URL found - urls[_ctx] = false; - } - } - } - } else if(_isString(ctx)) { - // string @context - ctx = jsonld.prependBase(base, ctx); - // replace w/@context if requested - if(replace) { - input[key] = urls[ctx]; - } else if(!(ctx in urls)) { - // @context URL found - urls[ctx] = false; - } - } - } - return (count < Object.keys(urls).length); + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; } - return false; -} -/** - * Retrieves external @context URLs using the given document loader. Every - * instance of @context in the input that refers to a URL will be replaced - * with the JSON @context found at that URL. - * - * @param input the JSON-LD input with possible contexts. - * @param options the options to use: - * documentLoader(url, callback(err, remoteDoc)) the document loader. - * @param callback(err, input) called once the operation completes. - */ -function _retrieveContextUrls(input, options, callback) { - // if any error occurs during URL resolution, quit - var error = null; + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } - // recursive document loader - var documentLoader = options.documentLoader; - var retrieve = function(input, cycles, documentLoader, base, callback) { - if(Object.keys(cycles).length > MAX_CONTEXT_URLS) { - error = new JsonLdError( - 'Maximum number of @context URLs exceeded.', - 'jsonld.ContextUrlError', - {code: 'loading remote context failed', max: MAX_CONTEXT_URLS}); - return callback(error); - } + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } - // for tracking the URLs to retrieve - var urls = {}; + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } - // finished will be called once the URL queue is empty - var finished = function() { - // replace all URLs in the input - _findContextUrls(input, urls, true, base); - callback(null, input); - }; + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } - // find all URLs in the given input - if(!_findContextUrls(input, urls, false, base)) { - // no new URLs in input - return finished(); + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); } + } - // queue all unretrieved URLs - var queue = []; - for(var url in urls) { - if(urls[url] === false) { - queue.push(url); - } - } + ctx.seen.push(value); - // retrieve URLs in queue - var count = queue.length; - for(var i = 0; i < queue.length; ++i) { - (function(url) { - // check for context URL cycle - if(url in cycles) { - error = new JsonLdError( - 'Cyclical @context URLs detected.', - 'jsonld.ContextUrlError', - {code: 'recursive context inclusion', url: url}); - return callback(error); - } - var _cycles = _clone(cycles); - _cycles[url] = true; - var done = function(err, remoteDoc) { - // short-circuit if there was an error with another URL - if(error) { - return; - } + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } - var ctx = remoteDoc ? remoteDoc.document : null; + ctx.seen.pop(); - // parse string context as JSON - if(!err && _isString(ctx)) { - try { - ctx = JSON.parse(ctx); - } catch(ex) { - err = ex; - } - } + return reduceToSingleString(output, base, braces); +} - // ensure ctx is an object - if(err) { - err = new JsonLdError( - 'Dereferencing a URL did not result in a valid JSON-LD object. ' + - 'Possible causes are an inaccessible URL perhaps due to ' + - 'a same-origin policy (ensure the server uses CORS if you are ' + - 'using client-side JavaScript), too many redirects, a ' + - 'non-JSON response, or more than one HTTP Link Header was ' + - 'provided for a remote context.', - 'jsonld.InvalidUrl', - {code: 'loading remote context failed', url: url, cause: err}); - } else if(!_isObject(ctx)) { - err = new JsonLdError( - 'Dereferencing a URL did not result in a JSON object. The ' + - 'response was valid JSON, but it was not a JSON object.', - 'jsonld.InvalidUrl', - {code: 'invalid remote context', url: url, cause: err}); - } - if(err) { - error = err; - return callback(error); - } - // use empty context if no @context key is present - if(!('@context' in ctx)) { - ctx = {'@context': {}}; - } else { - ctx = {'@context': ctx['@context']}; - } +function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + } + if (isNumber(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); +} - // append context URL to context if given - if(remoteDoc.contextUrl) { - if(!_isArray(ctx['@context'])) { - ctx['@context'] = [ctx['@context']]; - } - ctx['@context'].push(remoteDoc.contextUrl); - } - // recurse - retrieve(ctx, _cycles, documentLoader, url, function(err, ctx) { - if(err) { - return callback(err); - } - urls[url] = ctx['@context']; - count -= 1; - if(count === 0) { - finished(); - } - }); - }; - var promise = documentLoader(url, done); - if(promise && 'then' in promise) { - promise.then(done.bind(null, null), done); - } - }(queue[i])); - } - }; - retrieve(input, {}, documentLoader, options.base, callback); +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; } -// define js 1.8.5 Object.keys method if not present -if(!Object.keys) { - Object.keys = function(o) { - if(o !== Object(o)) { - throw new TypeError('Object.keys called on non-object'); + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); } - var rval = []; - for(var p in o) { - if(Object.prototype.hasOwnProperty.call(o, p)) { - rval.push(p); - } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); } - return rval; - }; + }); + return output; } -/** - * Parses RDF in the form of N-Quads. - * - * @param input the N-Quads input to parse. - * - * @return an RDF dataset. - */ -function _parseNQuads(input) { - // define partial regexes - var iri = '(?:<([^:]+:[^>]*)>)'; - var bnode = '(_:(?:[A-Za-z0-9]+))'; - var plain = '"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"'; - var datatype = '(?:\\^\\^' + iri + ')'; - var language = '(?:@([a-z]+(?:-[a-z0-9]+)*))'; - var literal = '(?:' + plain + '(?:' + datatype + '|' + language + ')?)'; - var comment = '(?:#.*)?'; - var ws = '[ \\t]+'; - var wso = '[ \\t]*'; - var eoln = /(?:\r\n)|(?:\n)|(?:\r)/g; - var empty = new RegExp('^' + wso + comment + '$'); - // define quad part regexes - var subject = '(?:' + iri + '|' + bnode + ')' + ws; - var property = iri + ws; - var object = '(?:' + iri + '|' + bnode + '|' + literal + ')' + wso; - var graphName = '(?:\\.|(?:(?:' + iri + '|' + bnode + ')' + wso + '\\.))'; +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } + } + if (!hasOwnProperty(visibleKeys, key)) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } - // full quad regex - var quad = new RegExp( - '^' + wso + subject + property + object + graphName + wso + comment + '$'); + return name + ': ' + str; +} - // build RDF dataset - var dataset = {}; - // split N-Quad input into lines - var lines = input.split(eoln); - var lineNumber = 0; - for(var li = 0; li < lines.length; ++li) { - var line = lines[li]; - lineNumber++; +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); - // skip empty lines - if(empty.test(line)) { - continue; - } + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } - // parse quad - var match = line.match(quad); - if(match === null) { - throw new JsonLdError( - 'Error while parsing N-Quads; invalid quad.', - 'jsonld.ParseError', {line: lineNumber}); - } + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} - // create RDF triple - var triple = {}; - // get subject - if(!_isUndefined(match[1])) { - triple.subject = {type: 'IRI', value: match[1]}; - } else { - triple.subject = {type: 'blank node', value: match[2]}; - } +// NOTE: These type checking functions intentionally don't use `instanceof` +// because it is fragile and can be easily faked with `Object.create()`. +function isArray(ar) { + return Array.isArray(ar); +} +exports.isArray = isArray; - // get predicate - triple.predicate = {type: 'IRI', value: match[3]}; +function isBoolean(arg) { + return typeof arg === 'boolean'; +} +exports.isBoolean = isBoolean; - // get object - if(!_isUndefined(match[4])) { - triple.object = {type: 'IRI', value: match[4]}; - } else if(!_isUndefined(match[5])) { - triple.object = {type: 'blank node', value: match[5]}; - } else { - triple.object = {type: 'literal'}; - if(!_isUndefined(match[7])) { - triple.object.datatype = match[7]; - } else if(!_isUndefined(match[8])) { - triple.object.datatype = RDF_LANGSTRING; - triple.object.language = match[8]; - } else { - triple.object.datatype = XSD_STRING; - } - var unescaped = match[6] - .replace(/\\"/g, '"') - .replace(/\\t/g, '\t') - .replace(/\\n/g, '\n') - .replace(/\\r/g, '\r') - .replace(/\\\\/g, '\\'); - triple.object.value = unescaped; - } - - // get graph name ('@default' is used for the default graph) - var name = '@default'; - if(!_isUndefined(match[9])) { - name = match[9]; - } else if(!_isUndefined(match[10])) { - name = match[10]; - } - - // initialize graph in dataset - if(!(name in dataset)) { - dataset[name] = [triple]; - } else { - // add triple if unique to its graph - var unique = true; - var triples = dataset[name]; - for(var ti = 0; unique && ti < triples.length; ++ti) { - if(_compareRDFTriples(triples[ti], triple)) { - unique = false; - } - } - if(unique) { - triples.push(triple); - } - } - } - - return dataset; +function isNull(arg) { + return arg === null; } +exports.isNull = isNull; -// register the N-Quads RDF parser -jsonld.registerRDFParser('application/nquads', _parseNQuads); - -/** - * Converts an RDF dataset to N-Quads. - * - * @param dataset the RDF dataset to convert. - * - * @return the N-Quads string. - */ -function _toNQuads(dataset) { - var quads = []; - for(var graphName in dataset) { - var triples = dataset[graphName]; - for(var ti = 0; ti < triples.length; ++ti) { - var triple = triples[ti]; - if(graphName === '@default') { - graphName = null; - } - quads.push(_toNQuad(triple, graphName)); - } - } - return quads.sort().join(''); +function isNullOrUndefined(arg) { + return arg == null; } +exports.isNullOrUndefined = isNullOrUndefined; -/** - * Converts an RDF triple and graph name to an N-Quad string (a single quad). - * - * @param triple the RDF triple or quad to convert (a triple or quad may be - * passed, if a triple is passed then `graphName` should be given - * to specify the name of the graph the triple is in, `null` for - * the default graph). - * @param graphName the name of the graph containing the triple, null for - * the default graph. - * - * @return the N-Quad string. - */ -function _toNQuad(triple, graphName) { - var s = triple.subject; - var p = triple.predicate; - var o = triple.object; - var g = graphName || null; - if('name' in triple && triple.name) { - g = triple.name.value; - } - - var quad = ''; +function isNumber(arg) { + return typeof arg === 'number'; +} +exports.isNumber = isNumber; - // subject is an IRI - if(s.type === 'IRI') { - quad += '<' + s.value + '>'; - } else { - quad += s.value; - } - quad += ' '; +function isString(arg) { + return typeof arg === 'string'; +} +exports.isString = isString; - // predicate is an IRI - if(p.type === 'IRI') { - quad += '<' + p.value + '>'; - } else { - quad += p.value; - } - quad += ' '; +function isSymbol(arg) { + return typeof arg === 'symbol'; +} +exports.isSymbol = isSymbol; - // object is IRI, bnode, or literal - if(o.type === 'IRI') { - quad += '<' + o.value + '>'; - } else if(o.type === 'blank node') { - quad += o.value; - } else { - var escaped = o.value - .replace(/\\/g, '\\\\') - .replace(/\t/g, '\\t') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/\"/g, '\\"'); - quad += '"' + escaped + '"'; - if(o.datatype === RDF_LANGSTRING) { - if(o.language) { - quad += '@' + o.language; - } - } else if(o.datatype !== XSD_STRING) { - quad += '^^<' + o.datatype + '>'; - } - } +function isUndefined(arg) { + return arg === void 0; +} +exports.isUndefined = isUndefined; - // graph - if(g !== null && g !== undefined) { - if(g.indexOf('_:') !== 0) { - quad += ' <' + g + '>'; - } else { - quad += ' ' + g; - } - } +function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; +} +exports.isRegExp = isRegExp; - quad += ' .\n'; - return quad; +function isObject(arg) { + return typeof arg === 'object' && arg !== null; } +exports.isObject = isObject; -/** - * Parses the RDF dataset found via the data object from the RDFa API. - * - * @param data the RDFa API data object. - * - * @return the RDF dataset. - */ -function _parseRdfaApiData(data) { - var dataset = {}; - dataset['@default'] = []; +function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; +} +exports.isDate = isDate; - var subjects = data.getSubjects(); - for(var si = 0; si < subjects.length; ++si) { - var subject = subjects[si]; - if(subject === null) { - continue; - } +function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); +} +exports.isError = isError; - // get all related triples - var triples = data.getSubjectTriples(subject); - if(triples === null) { - continue; - } - var predicates = triples.predicates; - for(var predicate in predicates) { - // iterate over objects - var objects = predicates[predicate].objects; - for(var oi = 0; oi < objects.length; ++oi) { - var object = objects[oi]; +function isFunction(arg) { + return typeof arg === 'function'; +} +exports.isFunction = isFunction; - // create RDF triple - var triple = {}; +function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; +} +exports.isPrimitive = isPrimitive; - // add subject - if(subject.indexOf('_:') === 0) { - triple.subject = {type: 'blank node', value: subject}; - } else { - triple.subject = {type: 'IRI', value: subject}; - } +exports.isBuffer = _dereq_('./support/isBuffer'); - // add predicate - if(predicate.indexOf('_:') === 0) { - triple.predicate = {type: 'blank node', value: predicate}; - } else { - triple.predicate = {type: 'IRI', value: predicate}; - } +function objectToString(o) { + return Object.prototype.toString.call(o); +} - // serialize XML literal - var value = object.value; - if(object.type === RDF_XML_LITERAL) { - // initialize XMLSerializer - if(!XMLSerializer) { - _defineXMLSerializer(); - } - var serializer = new XMLSerializer(); - value = ''; - for(var x = 0; x < object.value.length; x++) { - if(object.value[x].nodeType === Node.ELEMENT_NODE) { - value += serializer.serializeToString(object.value[x]); - } else if(object.value[x].nodeType === Node.TEXT_NODE) { - value += object.value[x].nodeValue; - } - } - } - // add object - triple.object = {}; +function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); +} - // object is an IRI - if(object.type === RDF_OBJECT) { - if(object.value.indexOf('_:') === 0) { - triple.object.type = 'blank node'; - } else { - triple.object.type = 'IRI'; - } - } else { - // object is a literal - triple.object.type = 'literal'; - if(object.type === RDF_PLAIN_LITERAL) { - if(object.language) { - triple.object.datatype = RDF_LANGSTRING; - triple.object.language = object.language; - } else { - triple.object.datatype = XSD_STRING; - } - } else { - triple.object.datatype = object.type; - } - } - triple.object.value = value; - // add triple to dataset in default graph - dataset['@default'].push(triple); - } - } - } +var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; - return dataset; +// 26 Feb 16:19:34 +function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); } -// register the RDFa API RDF parser -jsonld.registerRDFParser('rdfa-api', _parseRdfaApiData); - -/** - * Creates a new IdentifierIssuer. A IdentifierIssuer issues unique - * identifiers, keeping track of any previously issued identifiers. - * - * @param prefix the prefix to use (''). - */ -function IdentifierIssuer(prefix) { - this.prefix = prefix; - this.counter = 0; - this.existing = {}; -} -jsonld.IdentifierIssuer = IdentifierIssuer; -// backwards-compability -jsonld.UniqueNamer = IdentifierIssuer; -/** - * Copies this IdentifierIssuer. - * - * @return a copy of this IdentifierIssuer. - */ -IdentifierIssuer.prototype.clone = function() { - var copy = new IdentifierIssuer(this.prefix); - copy.counter = this.counter; - copy.existing = _clone(this.existing); - return copy; +// log is just a thin wrapper to console.log that prepends a timestamp +exports.log = function() { + console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); }; + /** - * Gets the new identifier for the given old identifier, where if no old - * identifier is given a new identifier will be generated. + * Inherit the prototype methods from one constructor into another. * - * @param [old] the old identifier to get the new identifier for. + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). * - * @return the new identifier. + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. */ -IdentifierIssuer.prototype.getId = function(old) { - // return existing old identifier - if(old && old in this.existing) { - return this.existing[old]; - } +exports.inherits = _dereq_('inherits'); - // get next identifier - var identifier = this.prefix + this.counter; - this.counter += 1; +exports._extend = function(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; - // save mapping - if(old) { - this.existing[old] = identifier; + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; } - - return identifier; -}; -// alias -IdentifierIssuer.prototype.getName = IdentifierIssuer.prototype.getName; - -/** - * Returns true if the given old identifer has already been assigned a new - * identifier. - * - * @param old the old identifier to check. - * - * @return true if the old identifier has been assigned a new identifier, false - * if not. - */ -IdentifierIssuer.prototype.hasId = function(old) { - return (old in this.existing); + return origin; }; -// alias -IdentifierIssuer.prototype.isNamed = IdentifierIssuer.prototype.hasId; -/** - * A Permutator iterates over all possible permutations of the given array - * of elements. - * - * @param list the array of elements to iterate over. - */ -var Permutator = function(list) { - // original array - this.list = list.sort(); - // indicates whether there are more permutations - this.done = false; - // directional info for permutation algorithm - this.left = {}; - for(var i = 0; i < list.length; ++i) { - this.left[list[i]] = true; - } -}; +function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} -/** - * Returns true if there is another permutation. - * - * @return true if there is another permutation, false if not. - */ -Permutator.prototype.hasNext = function() { - return !this.done; -}; +}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -/** - * Gets the next permutation. Call hasNext() to ensure there is another one - * first. - * - * @return the next permutation. - */ -Permutator.prototype.next = function() { - // copy current permutation - var rval = this.list.slice(); +},{"./support/isBuffer":50,"_process":12,"inherits":49}],52:[function(_dereq_,module,exports){ +module.exports = extend - /* Calculate the next permutation using the Steinhaus-Johnson-Trotter - permutation algorithm. */ +var hasOwnProperty = Object.prototype.hasOwnProperty; - // get largest mobile element k - // (mobile: element is greater than the one it is looking at) - var k = null; - var pos = 0; - var length = this.list.length; - for(var i = 0; i < length; ++i) { - var element = this.list[i]; - var left = this.left[element]; - if((k === null || element > k) && - ((left && i > 0 && element > this.list[i - 1]) || - (!left && i < (length - 1) && element > this.list[i + 1]))) { - k = element; - pos = i; - } - } +function extend() { + var target = {} - // no more permutations - if(k === null) { - this.done = true; - } else { - // swap k and the element it is looking at - var swap = this.left[k] ? pos - 1 : pos + 1; - this.list[pos] = this.list[swap]; - this.list[swap] = k; + for (var i = 0; i < arguments.length; i++) { + var source = arguments[i] - // reverse the direction of all elements larger than k - for(var i = 0; i < length; ++i) { - if(this.list[i] > k) { - this.left[this.list[i]] = !this.left[this.list[i]]; - } + for (var key in source) { + if (hasOwnProperty.call(source, key)) { + target[key] = source[key] + } + } } - } - return rval; -}; - -//////////////////////// DEFINE NORMALIZATION HASH API //////////////////////// + return target +} -/** - * Creates a new NormalizeHash for use by the given normalization algorithm. - * - * @param algorithm the RDF Dataset Normalization algorithm to use: - * 'URDNA2015' or 'URGNA2012'. +},{}],53:[function(_dereq_,module,exports){ +(function (process,global){ +/*! + * @overview es6-promise - a tiny implementation of Promises/A+. + * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) + * @license Licensed under MIT license + * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE + * @version 2.3.0 */ -var NormalizeHash = function(algorithm) { - if(!(this instanceof NormalizeHash)) { - return new NormalizeHash(algorithm); - } - if(['URDNA2015', 'URGNA2012'].indexOf(algorithm) === -1) { - throw new Error( - 'Invalid RDF Dataset Normalization algorithm: ' + algorithm); - } - NormalizeHash._init.call(this, algorithm); -}; -NormalizeHash.hashNQuads = function(algorithm, nquads) { - var md = new NormalizeHash(algorithm); - for(var i = 0; i < nquads.length; ++i) { - md.update(nquads[i]); - } - return md.digest(); -}; -// switch definition of NormalizeHash based on environment -(function(_nodejs) { +(function() { + "use strict"; + function lib$es6$promise$utils$$objectOrFunction(x) { + return typeof x === 'function' || (typeof x === 'object' && x !== null); + } -if(_nodejs) { - // define NormalizeHash using native crypto lib - var crypto = _dereq_('crypto'); - NormalizeHash._init = function(algorithm) { - if(algorithm === 'URDNA2015') { - algorithm = 'sha256'; - } else { - // assume URGNA2012 - algorithm = 'sha1'; + function lib$es6$promise$utils$$isFunction(x) { + return typeof x === 'function'; } - this.md = crypto.createHash(algorithm); - }; - NormalizeHash.prototype.update = function(msg) { - return this.md.update(msg, 'utf8'); - }; - NormalizeHash.prototype.digest = function() { - return this.md.digest('hex'); - }; - return; -} - -// define NormalizeHash using JavaScript -NormalizeHash._init = function(algorithm) { - if(algorithm === 'URDNA2015') { - algorithm = new sha256.Algorithm(); - } else { - // assume URGNA2012 - algorithm = new sha1.Algorithm(); - } - this.md = new MessageDigest(algorithm); -}; -NormalizeHash.prototype.update = function(msg) { - return this.md.update(msg); -}; -NormalizeHash.prototype.digest = function() { - return this.md.digest().toHex(); -}; -/////////////////////////// DEFINE MESSAGE DIGEST API ///////////////////////// + function lib$es6$promise$utils$$isMaybeThenable(x) { + return typeof x === 'object' && x !== null; + } -/** - * Creates a new MessageDigest. - * - * @param algorithm the algorithm to use. - */ -var MessageDigest = function(algorithm) { - if(!(this instanceof MessageDigest)) { - return new MessageDigest(algorithm); - } + var lib$es6$promise$utils$$_isArray; + if (!Array.isArray) { + lib$es6$promise$utils$$_isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; + } else { + lib$es6$promise$utils$$_isArray = Array.isArray; + } - this._algorithm = algorithm; + var lib$es6$promise$utils$$isArray = lib$es6$promise$utils$$_isArray; + var lib$es6$promise$asap$$len = 0; + var lib$es6$promise$asap$$toString = {}.toString; + var lib$es6$promise$asap$$vertxNext; + var lib$es6$promise$asap$$customSchedulerFn; - // create shared padding as needed - if(!MessageDigest._padding || - MessageDigest._padding.length < this._algorithm.blockSize) { - MessageDigest._padding = String.fromCharCode(128); - var c = String.fromCharCode(0x00); - var n = 64; - while(n > 0) { - if(n & 1) { - MessageDigest._padding += c; - } - n >>>= 1; - if(n > 0) { - c += c; + var lib$es6$promise$asap$$asap = function asap(callback, arg) { + lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len] = callback; + lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len + 1] = arg; + lib$es6$promise$asap$$len += 2; + if (lib$es6$promise$asap$$len === 2) { + // If len is 2, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + if (lib$es6$promise$asap$$customSchedulerFn) { + lib$es6$promise$asap$$customSchedulerFn(lib$es6$promise$asap$$flush); + } else { + lib$es6$promise$asap$$scheduleFlush(); + } } } - } - // start digest automatically for first time - this.start(); -}; + function lib$es6$promise$asap$$setScheduler(scheduleFn) { + lib$es6$promise$asap$$customSchedulerFn = scheduleFn; + } -/** - * Starts the digest. - * - * @return this digest object. - */ -MessageDigest.prototype.start = function() { - // up to 56-bit message length for convenience - this.messageLength = 0; + function lib$es6$promise$asap$$setAsap(asapFn) { + lib$es6$promise$asap$$asap = asapFn; + } - // full message length - this.fullMessageLength = []; - var int32s = this._algorithm.messageLengthSize / 4; - for(var i = 0; i < int32s; ++i) { - this.fullMessageLength.push(0); - } + var lib$es6$promise$asap$$browserWindow = (typeof window !== 'undefined') ? window : undefined; + var lib$es6$promise$asap$$browserGlobal = lib$es6$promise$asap$$browserWindow || {}; + var lib$es6$promise$asap$$BrowserMutationObserver = lib$es6$promise$asap$$browserGlobal.MutationObserver || lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver; + var lib$es6$promise$asap$$isNode = typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'; - // input buffer - this._input = new MessageDigest.ByteBuffer(); + // test for web worker but not in IE10 + var lib$es6$promise$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' && + typeof importScripts !== 'undefined' && + typeof MessageChannel !== 'undefined'; - // get starting state - this.state = this._algorithm.start(); + // node + function lib$es6$promise$asap$$useNextTick() { + var nextTick = process.nextTick; + // node version 0.10.x displays a deprecation warning when nextTick is used recursively + // setImmediate should be used instead instead + var version = process.versions.node.match(/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/); + if (Array.isArray(version) && version[1] === '0' && version[2] === '10') { + nextTick = setImmediate; + } + return function() { + nextTick(lib$es6$promise$asap$$flush); + }; + } - return this; -}; + // vertx + function lib$es6$promise$asap$$useVertxTimer() { + return function() { + lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush); + }; + } -/** - * Updates the digest with the given message input. The input must be - * a string of characters. - * - * @param msg the message input to update with (ByteBuffer or string). - * - * @return this digest object. - */ -MessageDigest.prototype.update = function(msg) { - // encode message as a UTF-8 encoded binary string - msg = new MessageDigest.ByteBuffer(unescape(encodeURIComponent(msg))); + function lib$es6$promise$asap$$useMutationObserver() { + var iterations = 0; + var observer = new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); - // update message length - this.messageLength += msg.length(); - var len = msg.length(); - len = [(len / 0x100000000) >>> 0, len >>> 0]; - for(var i = this.fullMessageLength.length - 1; i >= 0; --i) { - this.fullMessageLength[i] += len[1]; - len[1] = len[0] + ((this.fullMessageLength[i] / 0x100000000) >>> 0); - this.fullMessageLength[i] = this.fullMessageLength[i] >>> 0; - len[0] = ((len[1] / 0x100000000) >>> 0); - } + return function() { + node.data = (iterations = ++iterations % 2); + }; + } - // add bytes to input buffer - this._input.putBytes(msg.bytes()); + // web worker + function lib$es6$promise$asap$$useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = lib$es6$promise$asap$$flush; + return function () { + channel.port2.postMessage(0); + }; + } - // digest blocks - while(this._input.length() >= this._algorithm.blockSize) { - this.state = this._algorithm.digest(this.state, this._input); - } + function lib$es6$promise$asap$$useSetTimeout() { + return function() { + setTimeout(lib$es6$promise$asap$$flush, 1); + }; + } - // compact input buffer every 2K or if empty - if(this._input.read > 2048 || this._input.length() === 0) { - this._input.compact(); - } + var lib$es6$promise$asap$$queue = new Array(1000); + function lib$es6$promise$asap$$flush() { + for (var i = 0; i < lib$es6$promise$asap$$len; i+=2) { + var callback = lib$es6$promise$asap$$queue[i]; + var arg = lib$es6$promise$asap$$queue[i+1]; - return this; -}; + callback(arg); -/** - * Produces the digest. - * - * @return a byte buffer containing the digest value. - */ -MessageDigest.prototype.digest = function() { - /* Note: Here we copy the remaining bytes in the input buffer and add the - appropriate padding. Then we do the final update on a copy of the state so - that if the user wants to get intermediate digests they can do so. */ + lib$es6$promise$asap$$queue[i] = undefined; + lib$es6$promise$asap$$queue[i+1] = undefined; + } - /* Determine the number of bytes that must be added to the message to - ensure its length is appropriately congruent. In other words, the data to - be digested must be a multiple of `blockSize`. This data includes the - message, some padding, and the length of the message. Since the length of - the message will be encoded as `messageLengthSize` bytes, that means that - the last segment of the data must have `blockSize` - `messageLengthSize` - bytes of message and padding. Therefore, the length of the message plus the - padding must be congruent to X mod `blockSize` because - `blockSize` - `messageLengthSize` = X. + lib$es6$promise$asap$$len = 0; + } - For example, SHA-1 is congruent to 448 mod 512 and SHA-512 is congruent to - 896 mod 1024. SHA-1 uses a `blockSize` of 64 bytes (512 bits) and a - `messageLengthSize` of 8 bytes (64 bits). SHA-512 uses a `blockSize` of - 128 bytes (1024 bits) and a `messageLengthSize` of 16 bytes (128 bits). + function lib$es6$promise$asap$$attemptVertex() { + try { + var r = _dereq_; + var vertx = r('vertx'); + lib$es6$promise$asap$$vertxNext = vertx.runOnLoop || vertx.runOnContext; + return lib$es6$promise$asap$$useVertxTimer(); + } catch(e) { + return lib$es6$promise$asap$$useSetTimeout(); + } + } - In order to fill up the message length it must be filled with padding that - begins with 1 bit followed by all 0 bits. Padding must *always* be present, - so if the message length is already congruent, then `blockSize` padding bits - must be added. */ + var lib$es6$promise$asap$$scheduleFlush; + // Decide what async method to use to triggering processing of queued callbacks: + if (lib$es6$promise$asap$$isNode) { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useNextTick(); + } else if (lib$es6$promise$asap$$BrowserMutationObserver) { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMutationObserver(); + } else if (lib$es6$promise$asap$$isWorker) { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMessageChannel(); + } else if (lib$es6$promise$asap$$browserWindow === undefined && typeof _dereq_ === 'function') { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$attemptVertex(); + } else { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useSetTimeout(); + } - // create final block - var finalBlock = new MessageDigest.ByteBuffer(); - finalBlock.putBytes(this._input.bytes()); + function lib$es6$promise$$internal$$noop() {} - // compute remaining size to be digested (include message length size) - var remaining = ( - this.fullMessageLength[this.fullMessageLength.length - 1] + - this._algorithm.messageLengthSize); + var lib$es6$promise$$internal$$PENDING = void 0; + var lib$es6$promise$$internal$$FULFILLED = 1; + var lib$es6$promise$$internal$$REJECTED = 2; - // add padding for overflow blockSize - overflow - // _padding starts with 1 byte with first bit is set (byte value 128), then - // there may be up to (blockSize - 1) other pad bytes - var overflow = remaining & (this._algorithm.blockSize - 1); - finalBlock.putBytes(MessageDigest._padding.substr( - 0, this._algorithm.blockSize - overflow)); + var lib$es6$promise$$internal$$GET_THEN_ERROR = new lib$es6$promise$$internal$$ErrorObject(); - // serialize message length in bits in big-endian order; since length - // is stored in bytes we multiply by 8 (left shift by 3 and merge in - // remainder from ) - var messageLength = new MessageDigest.ByteBuffer(); - for(var i = 0; i < this.fullMessageLength.length; ++i) { - messageLength.putInt32((this.fullMessageLength[i] << 3) | - (this.fullMessageLength[i + 1] >>> 28)); - } + function lib$es6$promise$$internal$$selfFullfillment() { + return new TypeError("You cannot resolve a promise with itself"); + } - // write the length of the message (algorithm-specific) - this._algorithm.writeMessageLength(finalBlock, messageLength); + function lib$es6$promise$$internal$$cannotReturnOwn() { + return new TypeError('A promises callback cannot return that same promise.'); + } - // digest final block - var state = this._algorithm.digest(this.state.copy(), finalBlock); + function lib$es6$promise$$internal$$getThen(promise) { + try { + return promise.then; + } catch(error) { + lib$es6$promise$$internal$$GET_THEN_ERROR.error = error; + return lib$es6$promise$$internal$$GET_THEN_ERROR; + } + } - // write state to buffer - var rval = new MessageDigest.ByteBuffer(); - state.write(rval); - return rval; -}; + function lib$es6$promise$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) { + try { + then.call(value, fulfillmentHandler, rejectionHandler); + } catch(e) { + return e; + } + } -/** - * Creates a simple byte buffer for message digest operations. - * - * @param data the data to put in the buffer. - */ -MessageDigest.ByteBuffer = function(data) { - if(typeof data === 'string') { - this.data = data; - } else { - this.data = ''; - } - this.read = 0; -}; + function lib$es6$promise$$internal$$handleForeignThenable(promise, thenable, then) { + lib$es6$promise$asap$$asap(function(promise) { + var sealed = false; + var error = lib$es6$promise$$internal$$tryThen(then, thenable, function(value) { + if (sealed) { return; } + sealed = true; + if (thenable !== value) { + lib$es6$promise$$internal$$resolve(promise, value); + } else { + lib$es6$promise$$internal$$fulfill(promise, value); + } + }, function(reason) { + if (sealed) { return; } + sealed = true; -/** - * Puts a 32-bit integer into this buffer in big-endian order. - * - * @param i the 32-bit integer. - */ -MessageDigest.ByteBuffer.prototype.putInt32 = function(i) { - this.data += ( - String.fromCharCode(i >> 24 & 0xFF) + - String.fromCharCode(i >> 16 & 0xFF) + - String.fromCharCode(i >> 8 & 0xFF) + - String.fromCharCode(i & 0xFF)); -}; + lib$es6$promise$$internal$$reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); -/** - * Gets a 32-bit integer from this buffer in big-endian order and - * advances the read pointer by 4. - * - * @return the word. - */ -MessageDigest.ByteBuffer.prototype.getInt32 = function() { - var rval = ( - this.data.charCodeAt(this.read) << 24 ^ - this.data.charCodeAt(this.read + 1) << 16 ^ - this.data.charCodeAt(this.read + 2) << 8 ^ - this.data.charCodeAt(this.read + 3)); - this.read += 4; - return rval; -}; + if (!sealed && error) { + sealed = true; + lib$es6$promise$$internal$$reject(promise, error); + } + }, promise); + } -/** - * Puts the given bytes into this buffer. - * - * @param bytes the bytes as a binary-encoded string. - */ -MessageDigest.ByteBuffer.prototype.putBytes = function(bytes) { - this.data += bytes; -}; + function lib$es6$promise$$internal$$handleOwnThenable(promise, thenable) { + if (thenable._state === lib$es6$promise$$internal$$FULFILLED) { + lib$es6$promise$$internal$$fulfill(promise, thenable._result); + } else if (thenable._state === lib$es6$promise$$internal$$REJECTED) { + lib$es6$promise$$internal$$reject(promise, thenable._result); + } else { + lib$es6$promise$$internal$$subscribe(thenable, undefined, function(value) { + lib$es6$promise$$internal$$resolve(promise, value); + }, function(reason) { + lib$es6$promise$$internal$$reject(promise, reason); + }); + } + } -/** - * Gets the bytes in this buffer. - * - * @return a string full of UTF-8 encoded characters. - */ -MessageDigest.ByteBuffer.prototype.bytes = function() { - return this.data.slice(this.read); -}; + function lib$es6$promise$$internal$$handleMaybeThenable(promise, maybeThenable) { + if (maybeThenable.constructor === promise.constructor) { + lib$es6$promise$$internal$$handleOwnThenable(promise, maybeThenable); + } else { + var then = lib$es6$promise$$internal$$getThen(maybeThenable); -/** - * Gets the number of bytes in this buffer. - * - * @return the number of bytes in this buffer. - */ -MessageDigest.ByteBuffer.prototype.length = function() { - return this.data.length - this.read; -}; + if (then === lib$es6$promise$$internal$$GET_THEN_ERROR) { + lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$GET_THEN_ERROR.error); + } else if (then === undefined) { + lib$es6$promise$$internal$$fulfill(promise, maybeThenable); + } else if (lib$es6$promise$utils$$isFunction(then)) { + lib$es6$promise$$internal$$handleForeignThenable(promise, maybeThenable, then); + } else { + lib$es6$promise$$internal$$fulfill(promise, maybeThenable); + } + } + } -/** - * Compacts this buffer. - */ -MessageDigest.ByteBuffer.prototype.compact = function() { - this.data = this.data.slice(this.read); - this.read = 0; -}; + function lib$es6$promise$$internal$$resolve(promise, value) { + if (promise === value) { + lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$selfFullfillment()); + } else if (lib$es6$promise$utils$$objectOrFunction(value)) { + lib$es6$promise$$internal$$handleMaybeThenable(promise, value); + } else { + lib$es6$promise$$internal$$fulfill(promise, value); + } + } -/** - * Converts this buffer to a hexadecimal string. - * - * @return a hexadecimal string. - */ -MessageDigest.ByteBuffer.prototype.toHex = function() { - var rval = ''; - for(var i = this.read; i < this.data.length; ++i) { - var b = this.data.charCodeAt(i); - if(b < 16) { - rval += '0'; + function lib$es6$promise$$internal$$publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + lib$es6$promise$$internal$$publish(promise); } - rval += b.toString(16); - } - return rval; -}; -///////////////////////////// DEFINE SHA-1 ALGORITHM ////////////////////////// + function lib$es6$promise$$internal$$fulfill(promise, value) { + if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } -var sha1 = { - // used for word storage - _w: null -}; + promise._result = value; + promise._state = lib$es6$promise$$internal$$FULFILLED; -sha1.Algorithm = function() { - this.name = 'sha1', - this.blockSize = 64; - this.digestLength = 20; - this.messageLengthSize = 8; -}; + if (promise._subscribers.length !== 0) { + lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, promise); + } + } -sha1.Algorithm.prototype.start = function() { - if(!sha1._w) { - sha1._w = new Array(80); - } - return sha1._createState(); -}; + function lib$es6$promise$$internal$$reject(promise, reason) { + if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } + promise._state = lib$es6$promise$$internal$$REJECTED; + promise._result = reason; -sha1.Algorithm.prototype.writeMessageLength = function( - finalBlock, messageLength) { - // message length is in bits and in big-endian order; simply append - finalBlock.putBytes(messageLength.bytes()); -}; + lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publishRejection, promise); + } -sha1.Algorithm.prototype.digest = function(s, input) { - // consume 512 bit (64 byte) chunks - var t, a, b, c, d, e, f, i; - var len = input.length(); - var _w = sha1._w; - while(len >= 64) { - // initialize hash value for this chunk - a = s.h0; - b = s.h1; - c = s.h2; - d = s.h3; - e = s.h4; + function lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection) { + var subscribers = parent._subscribers; + var length = subscribers.length; - // the _w array will be populated with sixteen 32-bit big-endian words - // and then extended into 80 32-bit words according to SHA-1 algorithm - // and for 32-79 using Max Locktyukhin's optimization + parent._onerror = null; - // round 1 - for(i = 0; i < 16; ++i) { - t = input.getInt32(); - _w[i] = t; - f = d ^ (b & (c ^ d)); - t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t; - e = d; - d = c; - c = (b << 30) | (b >>> 2); - b = a; - a = t; - } - for(; i < 20; ++i) { - t = (_w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16]); - t = (t << 1) | (t >>> 31); - _w[i] = t; - f = d ^ (b & (c ^ d)); - t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t; - e = d; - d = c; - c = (b << 30) | (b >>> 2); - b = a; - a = t; - } - // round 2 - for(; i < 32; ++i) { - t = (_w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16]); - t = (t << 1) | (t >>> 31); - _w[i] = t; - f = b ^ c ^ d; - t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t; - e = d; - d = c; - c = (b << 30) | (b >>> 2); - b = a; - a = t; - } - for(; i < 40; ++i) { - t = (_w[i - 6] ^ _w[i - 16] ^ _w[i - 28] ^ _w[i - 32]); - t = (t << 2) | (t >>> 30); - _w[i] = t; - f = b ^ c ^ d; - t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t; - e = d; - d = c; - c = (b << 30) | (b >>> 2); - b = a; - a = t; - } - // round 3 - for(; i < 60; ++i) { - t = (_w[i - 6] ^ _w[i - 16] ^ _w[i - 28] ^ _w[i - 32]); - t = (t << 2) | (t >>> 30); - _w[i] = t; - f = (b & c) | (d & (b ^ c)); - t = ((a << 5) | (a >>> 27)) + f + e + 0x8F1BBCDC + t; - e = d; - d = c; - c = (b << 30) | (b >>> 2); - b = a; - a = t; - } - // round 4 - for(; i < 80; ++i) { - t = (_w[i - 6] ^ _w[i - 16] ^ _w[i - 28] ^ _w[i - 32]); - t = (t << 2) | (t >>> 30); - _w[i] = t; - f = b ^ c ^ d; - t = ((a << 5) | (a >>> 27)) + f + e + 0xCA62C1D6 + t; - e = d; - d = c; - c = (b << 30) | (b >>> 2); - b = a; - a = t; - } - - // update hash state - s.h0 = (s.h0 + a) | 0; - s.h1 = (s.h1 + b) | 0; - s.h2 = (s.h2 + c) | 0; - s.h3 = (s.h3 + d) | 0; - s.h4 = (s.h4 + e) | 0; - - len -= 64; - } - - return s; -}; + subscribers[length] = child; + subscribers[length + lib$es6$promise$$internal$$FULFILLED] = onFulfillment; + subscribers[length + lib$es6$promise$$internal$$REJECTED] = onRejection; -sha1._createState = function() { - var state = { - h0: 0x67452301, - h1: 0xEFCDAB89, - h2: 0x98BADCFE, - h3: 0x10325476, - h4: 0xC3D2E1F0 - }; - state.copy = function() { - var rval = sha1._createState(); - rval.h0 = state.h0; - rval.h1 = state.h1; - rval.h2 = state.h2; - rval.h3 = state.h3; - rval.h4 = state.h4; - return rval; - }; - state.write = function(buffer) { - buffer.putInt32(state.h0); - buffer.putInt32(state.h1); - buffer.putInt32(state.h2); - buffer.putInt32(state.h3); - buffer.putInt32(state.h4); - }; - return state; -}; + if (length === 0 && parent._state) { + lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, parent); + } + } -//////////////////////////// DEFINE SHA-256 ALGORITHM ///////////////////////// + function lib$es6$promise$$internal$$publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; -var sha256 = { - // shared state - _k: null, - _w: null -}; + if (subscribers.length === 0) { return; } -sha256.Algorithm = function() { - this.name = 'sha256', - this.blockSize = 64; - this.digestLength = 32; - this.messageLengthSize = 8; -}; + var child, callback, detail = promise._result; -sha256.Algorithm.prototype.start = function() { - if(!sha256._k) { - sha256._init(); - } - return sha256._createState(); -}; + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; -sha256.Algorithm.prototype.writeMessageLength = function( - finalBlock, messageLength) { - // message length is in bits and in big-endian order; simply append - finalBlock.putBytes(messageLength.bytes()); -}; + if (child) { + lib$es6$promise$$internal$$invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } -sha256.Algorithm.prototype.digest = function(s, input) { - // consume 512 bit (64 byte) chunks - var t1, t2, s0, s1, ch, maj, i, a, b, c, d, e, f, g, h; - var len = input.length(); - var _k = sha256._k; - var _w = sha256._w; - while(len >= 64) { - // the w array will be populated with sixteen 32-bit big-endian words - // and then extended into 64 32-bit words according to SHA-256 - for(i = 0; i < 16; ++i) { - _w[i] = input.getInt32(); - } - for(; i < 64; ++i) { - // XOR word 2 words ago rot right 17, rot right 19, shft right 10 - t1 = _w[i - 2]; - t1 = - ((t1 >>> 17) | (t1 << 15)) ^ - ((t1 >>> 19) | (t1 << 13)) ^ - (t1 >>> 10); - // XOR word 15 words ago rot right 7, rot right 18, shft right 3 - t2 = _w[i - 15]; - t2 = - ((t2 >>> 7) | (t2 << 25)) ^ - ((t2 >>> 18) | (t2 << 14)) ^ - (t2 >>> 3); - // sum(t1, word 7 ago, t2, word 16 ago) modulo 2^32 - _w[i] = (t1 + _w[i - 7] + t2 + _w[i - 16]) | 0; + promise._subscribers.length = 0; } - // initialize hash value for this chunk - a = s.h0; - b = s.h1; - c = s.h2; - d = s.h3; - e = s.h4; - f = s.h5; - g = s.h6; - h = s.h7; + function lib$es6$promise$$internal$$ErrorObject() { + this.error = null; + } - // round function - for(i = 0; i < 64; ++i) { - // Sum1(e) - s1 = - ((e >>> 6) | (e << 26)) ^ - ((e >>> 11) | (e << 21)) ^ - ((e >>> 25) | (e << 7)); - // Ch(e, f, g) (optimized the same way as SHA-1) - ch = g ^ (e & (f ^ g)); - // Sum0(a) - s0 = - ((a >>> 2) | (a << 30)) ^ - ((a >>> 13) | (a << 19)) ^ - ((a >>> 22) | (a << 10)); - // Maj(a, b, c) (optimized the same way as SHA-1) - maj = (a & b) | (c & (a ^ b)); + var lib$es6$promise$$internal$$TRY_CATCH_ERROR = new lib$es6$promise$$internal$$ErrorObject(); - // main algorithm - t1 = h + s1 + ch + _k[i] + _w[i]; - t2 = s0 + maj; - h = g; - g = f; - f = e; - e = (d + t1) | 0; - d = c; - c = b; - b = a; - a = (t1 + t2) | 0; + function lib$es6$promise$$internal$$tryCatch(callback, detail) { + try { + return callback(detail); + } catch(e) { + lib$es6$promise$$internal$$TRY_CATCH_ERROR.error = e; + return lib$es6$promise$$internal$$TRY_CATCH_ERROR; + } } - // update hash state - s.h0 = (s.h0 + a) | 0; - s.h1 = (s.h1 + b) | 0; - s.h2 = (s.h2 + c) | 0; - s.h3 = (s.h3 + d) | 0; - s.h4 = (s.h4 + e) | 0; - s.h5 = (s.h5 + f) | 0; - s.h6 = (s.h6 + g) | 0; - s.h7 = (s.h7 + h) | 0; - len -= 64; - } - - return s; -}; + function lib$es6$promise$$internal$$invokeCallback(settled, promise, callback, detail) { + var hasCallback = lib$es6$promise$utils$$isFunction(callback), + value, error, succeeded, failed; -sha256._createState = function() { - var state = { - h0: 0x6A09E667, - h1: 0xBB67AE85, - h2: 0x3C6EF372, - h3: 0xA54FF53A, - h4: 0x510E527F, - h5: 0x9B05688C, - h6: 0x1F83D9AB, - h7: 0x5BE0CD19 - }; - state.copy = function() { - var rval = sha256._createState(); - rval.h0 = state.h0; - rval.h1 = state.h1; - rval.h2 = state.h2; - rval.h3 = state.h3; - rval.h4 = state.h4; - rval.h5 = state.h5; - rval.h6 = state.h6; - rval.h7 = state.h7; - return rval; - }; - state.write = function(buffer) { - buffer.putInt32(state.h0); - buffer.putInt32(state.h1); - buffer.putInt32(state.h2); - buffer.putInt32(state.h3); - buffer.putInt32(state.h4); - buffer.putInt32(state.h5); - buffer.putInt32(state.h6); - buffer.putInt32(state.h7); - }; - return state; -}; + if (hasCallback) { + value = lib$es6$promise$$internal$$tryCatch(callback, detail); -sha256._init = function() { - // create K table for SHA-256 - sha256._k = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]; + if (value === lib$es6$promise$$internal$$TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value = null; + } else { + succeeded = true; + } - // used for word storage - sha256._w = new Array(64); -}; + if (promise === value) { + lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$cannotReturnOwn()); + return; + } -})(_nodejs); // end definition of NormalizeHash + } else { + value = detail; + succeeded = true; + } -if(!XMLSerializer) { + if (promise._state !== lib$es6$promise$$internal$$PENDING) { + // noop + } else if (hasCallback && succeeded) { + lib$es6$promise$$internal$$resolve(promise, value); + } else if (failed) { + lib$es6$promise$$internal$$reject(promise, error); + } else if (settled === lib$es6$promise$$internal$$FULFILLED) { + lib$es6$promise$$internal$$fulfill(promise, value); + } else if (settled === lib$es6$promise$$internal$$REJECTED) { + lib$es6$promise$$internal$$reject(promise, value); + } + } -var _defineXMLSerializer = function() { - XMLSerializer = _dereq_('xmldom').XMLSerializer; -}; + function lib$es6$promise$$internal$$initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value){ + lib$es6$promise$$internal$$resolve(promise, value); + }, function rejectPromise(reason) { + lib$es6$promise$$internal$$reject(promise, reason); + }); + } catch(e) { + lib$es6$promise$$internal$$reject(promise, e); + } + } -} // end _defineXMLSerializer + function lib$es6$promise$enumerator$$Enumerator(Constructor, input) { + var enumerator = this; -// define URL parser -// parseUri 1.2.2 -// (c) Steven Levithan -// MIT License -// with local jsonld.js modifications -jsonld.url = {}; -jsonld.url.parsers = { - simple: { - // RFC 3986 basic parts - keys: ['href','scheme','authority','path','query','fragment'], - regex: /^(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/ - }, - full: { - keys: ['href','protocol','scheme','authority','auth','user','password','hostname','port','path','directory','file','query','fragment'], - regex: /^(([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?(?:(((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ - } -}; -jsonld.url.parse = function(str, parser) { - var parsed = {}; - var o = jsonld.url.parsers[parser || 'full']; - var m = o.regex.exec(str); - var i = o.keys.length; - while(i--) { - parsed[o.keys[i]] = (m[i] === undefined) ? null : m[i]; - } - parsed.normalizedPath = _removeDotSegments(parsed.path, !!parsed.authority); - return parsed; -}; + enumerator._instanceConstructor = Constructor; + enumerator.promise = new Constructor(lib$es6$promise$$internal$$noop); -/** - * Removes dot segments from a URL path. - * - * @param path the path to remove dot segments from. - * @param hasAuthority true if the URL has an authority, false if not. - */ -function _removeDotSegments(path, hasAuthority) { - var rval = ''; + if (enumerator._validateInput(input)) { + enumerator._input = input; + enumerator.length = input.length; + enumerator._remaining = input.length; - if(path.indexOf('/') === 0) { - rval = '/'; - } + enumerator._init(); - // RFC 3986 5.2.4 (reworked) - var input = path.split('/'); - var output = []; - while(input.length > 0) { - if(input[0] === '.' || (input[0] === '' && input.length > 1)) { - input.shift(); - continue; - } - if(input[0] === '..') { - input.shift(); - if(hasAuthority || - (output.length > 0 && output[output.length - 1] !== '..')) { - output.pop(); + if (enumerator.length === 0) { + lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); + } else { + enumerator.length = enumerator.length || 0; + enumerator._enumerate(); + if (enumerator._remaining === 0) { + lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); + } + } } else { - // leading relative URL '..' - output.push('..'); + lib$es6$promise$$internal$$reject(enumerator.promise, enumerator._validationError()); } - continue; } - output.push(input.shift()); - } - - return rval + output.join('/'); -} -if(_nodejs) { - // use node document loader by default - jsonld.useDocumentLoader('node'); -} else if(typeof XMLHttpRequest !== 'undefined') { - // use xhr document loader by default - jsonld.useDocumentLoader('xhr'); -} + lib$es6$promise$enumerator$$Enumerator.prototype._validateInput = function(input) { + return lib$es6$promise$utils$$isArray(input); + }; -if(_nodejs) { - jsonld.use = function(extension) { - switch(extension) { - // TODO: Deprecated as of 0.4.0. Remove at some point. - case 'request': - // use node JSON-LD request extension - jsonld.request = _dereq_('jsonld-request'); - break; - default: - throw new JsonLdError( - 'Unknown extension.', - 'jsonld.UnknownExtension', {extension: extension}); - } - }; + lib$es6$promise$enumerator$$Enumerator.prototype._validationError = function() { + return new Error('Array Methods must be provided an Array'); + }; - // expose version - var _module = {exports: {}, filename: __dirname}; - _dereq_('pkginfo')(_module, 'version'); - jsonld.version = _module.exports.version; -} + lib$es6$promise$enumerator$$Enumerator.prototype._init = function() { + this._result = new Array(this.length); + }; -// end of jsonld API factory -return jsonld; -}; + var lib$es6$promise$enumerator$$default = lib$es6$promise$enumerator$$Enumerator; -// external APIs: + lib$es6$promise$enumerator$$Enumerator.prototype._enumerate = function() { + var enumerator = this; -// used to generate a new jsonld API instance -var factory = function() { - return wrapper(function() { - return factory(); - }); -}; + var length = enumerator.length; + var promise = enumerator.promise; + var input = enumerator._input; -if(!_nodejs && (typeof define === 'function' && define.amd)) { - // export AMD API - define([], function() { - // now that module is defined, wrap main jsonld API instance - wrapper(factory); - return factory; - }); -} else { - // wrap the main jsonld API instance - wrapper(factory); + for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) { + enumerator._eachEntry(input[i], i); + } + }; - if(typeof _dereq_ === 'function' && - typeof module !== 'undefined' && module.exports) { - // export CommonJS/nodejs API - module.exports = factory; - } + lib$es6$promise$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) { + var enumerator = this; + var c = enumerator._instanceConstructor; - if(_browser) { - // export simple browser API - if(typeof jsonld === 'undefined') { - jsonld = jsonldjs = factory; - } else { - jsonldjs = factory; - } - } -} - -return factory; - -})(); + if (lib$es6$promise$utils$$isMaybeThenable(entry)) { + if (entry.constructor === c && entry._state !== lib$es6$promise$$internal$$PENDING) { + entry._onerror = null; + enumerator._settledAt(entry._state, i, entry._result); + } else { + enumerator._willSettleAt(c.resolve(entry), i); + } + } else { + enumerator._remaining--; + enumerator._result[i] = entry; + } + }; -}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},"/node_modules/jsonld/js") + lib$es6$promise$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) { + var enumerator = this; + var promise = enumerator.promise; -},{"_process":37,"crypto":17,"es6-promise":9,"http":17,"jsonld-request":17,"pkginfo":17,"request":17,"util":17,"xmldom":17}],19:[function(_dereq_,module,exports){ -var pkg = _dereq_('./src/libsbgn'); + if (promise._state === lib$es6$promise$$internal$$PENDING) { + enumerator._remaining--; -module.exports = pkg; + if (state === lib$es6$promise$$internal$$REJECTED) { + lib$es6$promise$$internal$$reject(promise, value); + } else { + enumerator._result[i] = value; + } + } -},{"./src/libsbgn":23}],20:[function(_dereq_,module,exports){ -var N3 = _dereq_('n3'); + if (enumerator._remaining === 0) { + lib$es6$promise$$internal$$fulfill(promise, enumerator._result); + } + }; -var ns = {}; + lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) { + var enumerator = this; -ns.prefixes = { rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", - bqmodel: "http://biomodels.net/model-qualifiers/", - bqbiol: "http://biomodels.net/biology-qualifiers/", - sio: "http://semanticscience.org/resource/", - eisbm: "http://www.eisbm.org/"}; + lib$es6$promise$$internal$$subscribe(promise, undefined, function(value) { + enumerator._settledAt(lib$es6$promise$$internal$$FULFILLED, i, value); + }, function(reason) { + enumerator._settledAt(lib$es6$promise$$internal$$REJECTED, i, reason); + }); + }; + function lib$es6$promise$promise$all$$all(entries) { + return new lib$es6$promise$enumerator$$default(this, entries).promise; + } + var lib$es6$promise$promise$all$$default = lib$es6$promise$promise$all$$all; + function lib$es6$promise$promise$race$$race(entries) { + /*jshint validthis:true */ + var Constructor = this; -// pure shortcut function -ns.expandPrefix = function(prefix) { - return N3.Util.expandPrefixedName(prefix, ns.prefixes) -}; + var promise = new Constructor(lib$es6$promise$$internal$$noop); -// commonly used strings -str_sio223 = "sio:SIO_000223"; -str_sio223exp = ns.expandPrefix(str_sio223); -str_sio116 = "sio:SIO_000116"; -str_sio116exp = ns.expandPrefix(str_sio116); -str_rdfvalue = "rdf:value"; -str_rdfvalueexp = ns.expandPrefix(str_rdfvalue); -str_rdftype = "rdf:type"; -str_rdftypeexp = ns.expandPrefix(str_rdftype); -str_rdfbag = "rdf:Bag"; -str_rdfbagexp = ns.expandPrefix(str_rdfbag); + if (!lib$es6$promise$utils$$isArray(entries)) { + lib$es6$promise$$internal$$reject(promise, new TypeError('You must pass an array to race.')); + return promise; + } -controlledVocabularyList = [ - "bqmodel:is", - "bqmodel:isDerivedFrom", - "bqmodel:isDescribedBy", - "bqmodel:isInstanceOf", - "bqmodel:hasInstance", + var length = entries.length; - "bqbiol:is", - "bqbiol:encodes", - "bqbiol:hasPart", - "bqbiol:hasProperty", - "bqbiol:hasVersion", - "bqbiol:isDescribedBy", - "bqbiol:isEncodedBy", - "bqbiol:isHomologTo", - "bqbiol:isPartOf", - "bqbiol:isPropertyOf", - "bqbiol:isVersionOf", - "bqbiol:occursIn", - "bqbiol:hasTaxon", + function onFulfillment(value) { + lib$es6$promise$$internal$$resolve(promise, value); + } - "sio:SIO_000223" -]; + function onRejection(reason) { + lib$es6$promise$$internal$$reject(promise, reason); + } -ns.isControlledVocabulary = {}; -for(var i=0; i 0; -}; + function lib$es6$promise$promise$$needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); + } -ns.countBagElements = function(graph, subject) { - return graph.countTriples(subject, null, null) - 1; -}; + function lib$es6$promise$promise$$needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); + } -ns.getResourcesOfId = function(graph, id) { - var result = {}; - graph.forEach(function(init_triple){ // iterate over all id relationships - // we want everything that is not a simpel key/value property - if(init_triple.predicate != str_sio223exp) { - var relation = init_triple.predicate; - // initialize relation array if never encountered before - if(!result.hasOwnProperty(relation)) { - result[relation] = []; - } + var lib$es6$promise$promise$$default = lib$es6$promise$promise$$Promise; + /** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise's eventual value or the reason + why the promise cannot be fulfilled. - // if multiple resources specified, or a single element with several attributes, - // blank node is involved, possibly with a bag attribute - if(N3.Util.isBlank(init_triple.object)) { - var resourceContainer = init_triple.object; - graph.forEach(function(triple){ // iterate over the elements of the relationship - // relationship may be a bag, and thus contains undesirable rdf:type bag line - if(triple.object != str_rdfbagexp) { - var resource = triple.object; - result[relation].push(resource); - } - }, resourceContainer, null, null); - } - else { - // simple case, no bag, only 1 resource is linked with 1 attribute - var resource = init_triple.object; - result[relation].push(resource); - } - } - }, id, null, null); - return result; -}; + Terminology + ----------- -/** - * returns the id of a newly created blank node representing the HasProperty predicate - * if one already exists, returns its id - * returns array, potentially several SIO223 present - */ -ns.getRelationship = function (graph, id, relationship) { - if (ns.hasRelationship(graph, id, relationship)) { - var object = graph.getObjects(id, relationship, null)[0]; // careful here - if (!N3.Util.isBlank(object)){ - // object of relationship isn't a bag. Need to turn it into a bag. - var newBag = ns.createBag(graph, id, relationship); - graph.addTriple(id, relationship, newBag); - graph.addTriple(newBag, ns.expandPrefix("rdf:_1"), object); - return [newBag]; - } - else { - return graph.getObjects(id, relationship, null); - } - } - else { - return [ns.createBag(graph, id, relationship)]; - } -}; + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. -ns.createBag = function (graph, id, relationship) { - var newBlank = graph.createBlankNode(); - graph.addTriple(id, ns.expandPrefix(relationship), newBlank); - graph.addTriple(newBlank, str_rdftypeexp, str_rdfbagexp); - return newBlank; -}; + A promise can be in one of three states: pending, fulfilled, or rejected. -/** - * kvobject contains biology qualifier as key and miriam resource as value - */ -ns.addResource = function (graph, id, kvObject) { - for(var relation in kvObject) { - //console.log("relation", relation); - var relationElement = ns.getRelationship(graph, id, relation)[0]; // doesn't matter if more than one - //console.log("after get relation",relationElement, graph.getTriples(id, relation)); - //console.log("after get realtion", graph.getTriples()); - // using elemnt count as index may be dangerous if previous manipulation of - // the elements has happened. Like removing one. - var propIndex = ns.countBagElements(graph, relationElement) + 1; - //console.log("elements in bag:", propIndex); - //console.log("new blank node", graph.getTriples()); - //console.log("Will add", relationElement, ns.expandPrefix("rdf:_"+propIndex), kvObject[relation]); - graph.addTriple(relationElement, ns.expandPrefix("rdf:_"+propIndex), kvObject[relation]); - //console.log("end result", graph.getTriples()); - //console.log("added", relation, kvObject[relation]); - } -}; + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. -module.exports = ns; -},{"n3":25}],21:[function(_dereq_,module,exports){ -/** - * This submodule manages the annotations extension. It adds the ability to save semantic data into - * SBGN-ML in the form of RDF elements. Any SBGN element that can host an extension tag can also - * get RDF annotations. This means that almost every element can get annotated. - * - * The annotations here are intended to be used in two ways: - * - with controlled vocabulary and resources, as suggested by COMBINE, with the help of MIRIAM - * identifiers. - * - as a mean to attach arbitrary data in the form of key-value properties. - * - * # Controlled vocabulary - * - * The formal way of using annotations is to use specific vocabulary with specific identifiers to - * provide additional information that can not be conveyed otherwise through the SBGN format. - * See --link to combine qualifiers-- and --link to identifiers.org and MIRIAM--- - * This was also based on the annotation extension of SBML --link to annotation proposal for SBML-- - * - * - * See {@link Extension} for more general information on extensions in the SBGN-ML format. - * - * You can access the following classes like this: libsbgn.annot.Annotation - * - * @module libsbgn-annotations - * @namespace libsbgn.annot -*/ + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. -var checkParams = _dereq_('./utilities').checkParams; -var $rdf = _dereq_('rdflib'); -var N3 = _dereq_('n3'); -var Util = _dereq_('./annotation-utils'); -var utils = _dereq_('./utilities'); -var ns = {}; + Basic Usage: + ------------ -//ns.xmlns = "http://www.sbml.org/sbml/level3/version1/render/version1"; + ```js + var promise = new Promise(function(resolve, reject) { + // on success + resolve(value); -// ------- ANNOTATION ------- -/** - * Represents the <annotation> element. - * @class - * @param {Object} params - * @param {RdfElement=} params.rdfElement - */ -var Annotation = function (params) { - var params = checkParams(params, ['rdfElement']); - this.rdfElement = params.rdfElement; -}; + // on failure + reject(reason); + }); -/** - * @param {RdfElement} rdfElement - */ -Annotation.prototype.setRdfElement = function(rdfElement) { - this.rdfElement = rdfElement; -}; + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` -Annotation.prototype.buildJsObj = function () { - var annotationJsonObj = {}; + Advanced Usage: + --------------- - // attributes - var attributes = {}; - if(this.id != null) { - attributes.id = this.id; - } - utils.addAttributes(annotationJsonObj, attributes); - return annotationJsonObj; -}; + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. -/** - * @return {string} - */ -Annotation.prototype.toXML = function() { - return utils.buildString({annotation: this.buildJsObj()}) -}; + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + var xhr = new XMLHttpRequest(); -Annotation.fromXML = function (string) { - var annotation; - function fn (err, result) { - annotation = Annotation.fromObj(result); - }; - utils.parseStringKeepPrefix(string, fn); - return annotation; -}; + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); -Annotation.fromObj = function (jsObj) { - if (typeof jsObj.annotation == 'undefined') { - throw new Error("Bad XML provided, expected tagName annotation, got: " + Object.keys(jsObj)[0]); - } + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } - var annotation = new ns.Annotation(); - jsObj = jsObj.annotation; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return annotation; - } + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` - // children - if(jsObj['rdf:RDF']) { - /*var listOfColorDefinitions = ns.ListOfColorDefinitions.fromObj({listOfColorDefinitions: jsObj.listOfColorDefinitions[0]}); - renderInformation.setListOfColorDefinitions(listOfColorDefinitions);*/ + Unlike callbacks, promises are great composable primitives. - var obj = {}; - obj['rdf:RDF'] = jsObj['rdf:RDF'][0]; - var rdf = ns.RdfElement.fromObj(obj); - annotation.setRdfElement(rdf); - } + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON - return annotation; -}; + return values; + }); + ``` -ns.Annotation = Annotation; -// ------- END ANNOTATION ------- + @class Promise + @param {function} resolver + Useful for tooling. + @constructor + */ + function lib$es6$promise$promise$$Promise(resolver) { + this._id = lib$es6$promise$promise$$counter++; + this._state = undefined; + this._result = undefined; + this._subscribers = []; -// ------- STOREOBJECT ------- -var StoreObject = function (params) { - var params = checkParams(params, ['store']); - if (params.store) { - this.store = params.store; - } - else { - var store = N3.Store(); - store.addPrefixes(Util.prefixes); - this.store = store; - } -}; + if (lib$es6$promise$$internal$$noop !== resolver) { + if (!lib$es6$promise$utils$$isFunction(resolver)) { + lib$es6$promise$promise$$needsResolver(); + } -StoreObject.prototype.getCustomPropertiesOfId = function (id) { - return Util.getCustomPropertiesOfId(this.store, id); -}; + if (!(this instanceof lib$es6$promise$promise$$Promise)) { + lib$es6$promise$promise$$needsNew(); + } -StoreObject.prototype.getAllIds = function () { - return Util.getAllIds(this.store); -}; + lib$es6$promise$$internal$$initializePromise(this, resolver); + } + } -StoreObject.prototype.addCustomProperty = function (id, kvObject) { - return Util.addCustomProperty(this.store, id, kvObject); -}; - -StoreObject.prototype.getResourcesOfId = function(id) { - return Util.getResourcesOfId(this.store, id); -}; + lib$es6$promise$promise$$Promise.all = lib$es6$promise$promise$all$$default; + lib$es6$promise$promise$$Promise.race = lib$es6$promise$promise$race$$default; + lib$es6$promise$promise$$Promise.resolve = lib$es6$promise$promise$resolve$$default; + lib$es6$promise$promise$$Promise.reject = lib$es6$promise$promise$reject$$default; + lib$es6$promise$promise$$Promise._setScheduler = lib$es6$promise$asap$$setScheduler; + lib$es6$promise$promise$$Promise._setAsap = lib$es6$promise$asap$$setAsap; + lib$es6$promise$promise$$Promise._asap = lib$es6$promise$asap$$asap; -StoreObject.prototype.addResource = function (id, kvObject) { - return Util.addResource(this.store, id, kvObject); -}; + lib$es6$promise$promise$$Promise.prototype = { + constructor: lib$es6$promise$promise$$Promise, -ns.StoreObject = StoreObject; -// ------- END STOREOBJECT ------- + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. -// ------- GLOBALSTORE ------- -var GlobalRdfStore = function (params) { - ns.StoreObject.call(this, params); -}; -GlobalRdfStore.prototype = Object.create(ns.StoreObject.prototype); -GlobalRdfStore.prototype.constructor = GlobalRdfStore; + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` -GlobalRdfStore.prototype.load = function (annotations) { - for(var i=0; i<rd:RDFf> element. - * @class - */ -var RdfElement = function (params) { - ns.StoreObject.call(this, params); -}; -RdfElement.prototype = Object.create(ns.StoreObject.prototype); -RdfElement.prototype.constructor = RdfElement; + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. -RdfElement.uri = 'http://www.eisbm.org/'; + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` -/** - * @return {string} - */ -RdfElement.prototype.toXML = function() { - /* - Add some functions to the writer object of N3 - Those functions will allow us to serialize triples synchronously. - Without it, we would be forced to use the asynchronous functions. - */ - function addSimpleWrite (writer) { - // replicates the writer._write function but returns a string - writer.simpleWriteTriple = function (subject, predicate, object, graph) { - return this._encodeIriOrBlankNode(subject) + ' ' + - this._encodeIriOrBlankNode(predicate) + ' ' + - this._encodeObject(object) + - (graph ? ' ' + this._encodeIriOrBlankNode(graph) + '.\n' : '.\n') - }; - // allows to provide an array of triples and concatenate their serialized strings - writer.simpleWriteTriples = function (array) { - var stringN3 = ''; - for (var i=0; i[\s\S]*?<(\w+):SIO_000116>([\s\S]*?)<\/\2:SIO_000116>[\s\S]*?([\s\S]*?)<\/rdf:value>[\s\S]*?<\/rdf:li>/g; - var result = string.replace(regexpLi, ''); - return result; - } + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` - function replaceBag(string) { - // regexp will spot a transformed bag and capture its content - var regexpBag = /(([\s\S]*?)[\s\S]*?<\/rdf:Description>)/g; - var result1 = string.replace(regexpBag, '$2'); - var result2 = result1.replace(/ <\/rdf:Bag>/g, ''); - return result2; - } + Simple Example + -------------- - function replaceParseType(string) { - var regexp = / rdf:parseType="Resource"/g; - return string.replace(regexp, ''); - } + Synchronous Example - function replaceSlashInID(string) { - return string.replace(new RegExp(/rdf:about="\//g), 'rdf:about="'); - } - - var result = replaceSlashInID(replaceParseType(replaceLi(replaceBag(serialize)))); - - return result; -}; + ```javascript + var result; -/** - * @param {Element} xml - * @return {RdfElement} - */ -RdfElement.fromString = function (stringXml) { + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` - var rdfElement = new RdfElement(); - var graph = $rdf.graph(); + Errback Example - // rdflib only accepts string as input, not xml elements - try { - $rdf.parse(stringXml, graph, RdfElement.uri, 'application/rdf+xml'); - } catch (err) { - console.log(err); - } - - // convert to turtle to feed to N3 - var turtle = $rdf.serialize($rdf.sym(RdfElement.uri), graph, undefined, 'text/turtle'); + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` - var parser = N3.Parser(); - var store = N3.Store(); - store.addPrefixes(Util.prefixes); - store.addTriples(parser.parse(turtle)); - - rdfElement.store = store; + Promise Example; - return rdfElement; -}; + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` -RdfElement.fromXML = function (string) { - var rdfElement; - function fn (err, result) { - rdfElement = RdfElement.fromObj(result); - }; - utils.parseStringKeepPrefix(string, fn); - return rdfElement; -}; + Advanced Example + -------------- -RdfElement.fromObj = function (jsObj) { - if (typeof jsObj['rdf:RDF'] == 'undefined') { - throw new Error("Bad XML provided, expected tagName rdf:RDF, got: " + Object.keys(jsObj)[0]); - } + Synchronous Example - var rdfElement = new ns.RdfElement(); - jsObj = jsObj['rdf:RDF']; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return rdfElement; - } + ```javascript + var author, books; - var obj = {}; - obj['rdf:RDF'] = jsObj; - rdfElement = ns.RdfElement.fromString(utils.buildString(obj)); + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` - return rdfElement; -}; + Errback Example -RdfElement.prototype.test = function() { - //console.log(this.store); - //console.log(this.store.getTriples("http://local/anID000001", null, null)); - console.log("expand prefix shortcut", Util.expandPrefix("sio:SIO_000116")); - console.log("all properties of id", this.getCustomPropertiesOfId("http://local/anID000001")); - console.log("all ids", this.getAllIds()); -}; + ```js -ns.RdfElement = RdfElement; -// ------- END RDFELEMENT ------- + function foundBooks(books) { + } -ns.rdflib = $rdf; -ns.Util = Util; + function failure(reason) { -module.exports = ns; + } -},{"./annotation-utils":20,"./utilities":24,"n3":25,"rdflib":51}],22:[function(_dereq_,module,exports){ -/** - * This submodule contains the classes to manage the render extension's xml and some utility functions. - * It adds the ability to save the styles and colors used in an SBGN map, as features like background-color, - * border thickness or font properties are not part of the SBGN standard. - * - * It is loosely based on the {@link http://sbml.org/Documents/Specifications/SBML_Level_3/Packages/render|render extension of the SBML format}. - * A subset of this specification has been adapted for SBGN-ML integration. - * - * See {@link Extension} for more general information on extensions in the SBGN-ML format. - * - * You can access the following classes like this: libsbgn.render.ColorDefinition - * - * @module libsbgn-render - * @namespace libsbgn.render -*/ + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` -var utils = _dereq_('./utilities'); -var checkParams = utils.checkParams; -var xml2js = _dereq_('xml2js'); + Promise Example; -var ns = {}; + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` -ns.xmlns = "http://www.sbml.org/sbml/level3/version1/render/version1"; + @method then + @param {Function} onFulfilled + @param {Function} onRejected + Useful for tooling. + @return {Promise} + */ + then: function(onFulfillment, onRejection) { + var parent = this; + var state = parent._state; -// ------- COLORDEFINITION ------- -/** - * Represents the <colorDefinition> element. - * @class - * @param {Object} params - * @param {string=} params.id - * @param {string=} params.value - */ -var ColorDefinition = function(params) { - var params = checkParams(params, ['id', 'value']); - this.id = params.id; - this.value = params.value; -}; + if (state === lib$es6$promise$$internal$$FULFILLED && !onFulfillment || state === lib$es6$promise$$internal$$REJECTED && !onRejection) { + return this; + } -/** - * @return {Object} - xml2js formatted object - */ -ColorDefinition.prototype.buildJsObj = function () { - var colordefObj = {}; + var child = new this.constructor(lib$es6$promise$$internal$$noop); + var result = parent._result; - // attributes - var attributes = {}; - if(this.id != null) { - attributes.id = this.id; - } - if(this.value != null) { - attributes.value = this.value; - } - utils.addAttributes(colordefObj, attributes); - return colordefObj; -}; + if (state) { + var callback = arguments[state - 1]; + lib$es6$promise$asap$$asap(function(){ + lib$es6$promise$$internal$$invokeCallback(state, child, callback, result); + }); + } else { + lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection); + } -/** - * @return {string} - */ -ColorDefinition.prototype.toXML = function () { - return utils.buildString({colorDefinition: this.buildJsObj()}) -}; + return child; + }, -/** - * @param {String} string - * @return {ColorDefinition} - */ -ColorDefinition.fromXML = function (string) { - var colorDefinition; - function fn (err, result) { - colorDefinition = ColorDefinition.fromObj(result); - }; - utils.parseString(string, fn); - return colorDefinition; -}; + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. -/** - * @param {Object} jsObj - xml2js formatted object - * @return {ColorDefinition} - */ -ColorDefinition.fromObj = function (jsObj) { - if (typeof jsObj.colorDefinition == 'undefined') { - throw new Error("Bad XML provided, expected tagName colorDefinition, got: " + Object.keys(jsObj)[0]); - } + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } - var colorDefinition = new ns.ColorDefinition(); - jsObj = jsObj.colorDefinition; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return colorDefinition; - } + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - colorDefinition.id = attributes.id || null; - colorDefinition.value = attributes.value || null; - } - return colorDefinition; -}; + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` -ns.ColorDefinition = ColorDefinition; -// ------- END COLORDEFINITION ------- + @method catch + @param {Function} onRejection + Useful for tooling. + @return {Promise} + */ + 'catch': function(onRejection) { + return this.then(null, onRejection); + } + }; + function lib$es6$promise$polyfill$$polyfill() { + var local; -// ------- LISTOFCOLORDEFINITIONS ------- -/** - * Represents the <listOfColorDefinitions> element. - * @class - */ -var ListOfColorDefinitions = function () { - this.colorDefinitions = []; - this.colorIndex = {}; -}; + if (typeof global !== 'undefined') { + local = global; + } else if (typeof self !== 'undefined') { + local = self; + } else { + try { + local = Function('return this')(); + } catch (e) { + throw new Error('polyfill failed because global object is unavailable in this environment'); + } + } -/** - * @param {ColorDefinition} colorDefinition - */ -ListOfColorDefinitions.prototype.addColorDefinition = function (colorDefinition) { - this.colorDefinitions.push(colorDefinition); - this.colorIndex[colorDefinition.id] = colorDefinition.value; -}; + var P = local.Promise; -/** - * Convenient method to get a color value directly. - * @param {string} id - * @return {string} - */ -ListOfColorDefinitions.prototype.getColorById = function (id) { - return this.colorIndex[id]; -}; + if (P && Object.prototype.toString.call(P.resolve()) === '[object Promise]' && !P.cast) { + return; + } -/** - * Convenient method to get all the color values in the list. - * @return {string[]} - */ -ListOfColorDefinitions.prototype.getAllColors = function () { - return Object.values(this.colorIndex); -}; + local.Promise = lib$es6$promise$promise$$default; + } + var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill; -/** - * @return {Object} - xml2js formatted object - */ -ListOfColorDefinitions.prototype.buildJsObj = function () { - var listOfColorDefinitionsObj = {}; + var lib$es6$promise$umd$$ES6Promise = { + 'Promise': lib$es6$promise$promise$$default, + 'polyfill': lib$es6$promise$polyfill$$default + }; - for(var i=0; i < this.colorDefinitions.length; i++) { - if (i==0) { - listOfColorDefinitionsObj.colorDefinition = []; - } - listOfColorDefinitionsObj.colorDefinition.push(this.colorDefinitions[i].buildJsObj()); - } + /* global define:true module:true window: true */ + if (typeof define === 'function' && define['amd']) { + define(function() { return lib$es6$promise$umd$$ES6Promise; }); + } else if (typeof module !== 'undefined' && module['exports']) { + module['exports'] = lib$es6$promise$umd$$ES6Promise; + } else if (typeof this !== 'undefined') { + this['ES6Promise'] = lib$es6$promise$umd$$ES6Promise; + } - return listOfColorDefinitionsObj; -}; + lib$es6$promise$polyfill$$default(); +}).call(this); -/** - * @return {string} - */ -ListOfColorDefinitions.prototype.toXML = function () { - return utils.buildString({listOfColorDefinitions: this.buildJsObj()}) -}; +}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{"_process":12}],54:[function(_dereq_,module,exports){ +// Ignore module for browserify (see package.json) +},{}],55:[function(_dereq_,module,exports){ +(function (process,global,__dirname){ /** - * @param {String} string - * @return {ListOfColorDefinitions} + * A JavaScript implementation of the JSON-LD API. + * + * @author Dave Longley + * + * @license BSD 3-Clause License + * Copyright (c) 2011-2015 Digital Bazaar, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the Digital Bazaar, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -ListOfColorDefinitions.fromXML = function (string) { - var listOfColorDefinitions; - function fn (err, result) { - listOfColorDefinitions = ListOfColorDefinitions.fromObj(result); - }; - utils.parseString(string, fn); - return listOfColorDefinitions; -}; +(function() { + +// determine if in-browser or using node.js +var _nodejs = ( + typeof process !== 'undefined' && process.versions && process.versions.node); +var _browser = !_nodejs && + (typeof window !== 'undefined' || typeof self !== 'undefined'); +if(_browser) { + if(typeof global === 'undefined') { + if(typeof window !== 'undefined') { + global = window; + } else if(typeof self !== 'undefined') { + global = self; + } else if(typeof $ !== 'undefined') { + global = $; + } + } +} + +// attaches jsonld API to the given object +var wrapper = function(jsonld) { + +/* Core API */ /** - * @param {Object} jsObj - xml2js formatted object - * @return {ListOfColorDefinitions} + * Performs JSON-LD compaction. + * + * @param input the JSON-LD input to compact. + * @param ctx the context to compact with. + * @param [options] options to use: + * [base] the base IRI to use. + * [compactArrays] true to compact arrays to single values when + * appropriate, false not to (default: true). + * [graph] true to always output a top-level graph (default: false). + * [expandContext] a context to expand with. + * [skipExpansion] true to assume the input is expanded and skip + * expansion, false not to, defaults to false. + * [documentLoader(url, callback(err, remoteDoc))] the document loader. + * @param callback(err, compacted, ctx) called once the operation completes. */ -ListOfColorDefinitions.fromObj = function (jsObj) { - if (typeof jsObj.listOfColorDefinitions == 'undefined') { - throw new Error("Bad XML provided, expected tagName listOfColorDefinitions, got: " + Object.keys(jsObj)[0]); - } +jsonld.compact = function(input, ctx, options, callback) { + if(arguments.length < 2) { + return jsonld.nextTick(function() { + callback(new TypeError('Could not compact, too few arguments.')); + }); + } - var listOfColorDefinitions = new ns.ListOfColorDefinitions(); - jsObj = jsObj.listOfColorDefinitions; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return listOfColorDefinitions; - } + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; - // children - if(jsObj.colorDefinition) { - var colorDefinitions = jsObj.colorDefinition; - for (var i=0; i < colorDefinitions.length; i++) { - var colorDefinition = ns.ColorDefinition.fromObj({colorDefinition: colorDefinitions[i]}); - listOfColorDefinitions.addColorDefinition(colorDefinition); - } - } + if(ctx === null) { + return jsonld.nextTick(function() { + callback(new JsonLdError( + 'The compaction context must not be null.', + 'jsonld.CompactError', {code: 'invalid local context'})); + }); + } - return listOfColorDefinitions; -}; + // nothing to compact + if(input === null) { + return jsonld.nextTick(function() { + callback(null, null); + }); + } -ns.ListOfColorDefinitions = ListOfColorDefinitions; -// ------- END LISTOFCOLORDEFINITIONS ------- + // set default options + if(!('base' in options)) { + options.base = (typeof input === 'string') ? input : ''; + } + if(!('compactArrays' in options)) { + options.compactArrays = true; + } + if(!('graph' in options)) { + options.graph = false; + } + if(!('skipExpansion' in options)) { + options.skipExpansion = false; + } + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } + if(!('link' in options)) { + options.link = false; + } + if(options.link) { + // force skip expansion when linking, "link" is not part of the public + // API, it should only be called from framing + options.skipExpansion = true; + } -// ------- RENDERGROUP ------- -/** - * Represents the <g> element. - * @class - * @param {Object} params - * @param {string=} params.id - * @param {string=} params.fontSize - * @param {string=} params.fontFamily - * @param {string=} params.fontWeight - * @param {string=} params.fontStyle - * @param {string=} params.textAnchor - * @param {string=} params.vtextAnchor - * @param {string=} params.fill The element's background color - * @param {string=} params.stroke Border color for glyphs, line color for arcs. - * @param {string=} params.strokeWidth - */ -var RenderGroup = function (params) { - // each of those are optional, so test if it is defined is mandatory - var params = checkParams(params, ['fontSize', 'fontFamily', 'fontWeight', - 'fontStyle', 'textAnchor', 'vtextAnchor', 'fill', 'id', 'stroke', 'strokeWidth']); - // specific to renderGroup - this.fontSize = params.fontSize; - this.fontFamily = params.fontFamily; - this.fontWeight = params.fontWeight; - this.fontStyle = params.fontStyle; - this.textAnchor = params.textAnchor; // probably useless - this.vtextAnchor = params.vtextAnchor; // probably useless - // from GraphicalPrimitive2D - this.fill = params.fill; // fill color - // from GraphicalPrimitive1D - this.id = params.id; - this.stroke = params.stroke; // stroke color - this.strokeWidth = params.strokeWidth; -}; + var expand = function(input, options, callback) { + if(options.skipExpansion) { + return jsonld.nextTick(function() { + callback(null, input); + }); + } + jsonld.expand(input, options, callback); + }; -/** - * @return {Object} - xml2js formatted object - */ -RenderGroup.prototype.buildJsObj = function () { - var renderGroupObj = {}; + // expand input then do compaction + expand(input, options, function(err, expanded) { + if(err) { + return callback(new JsonLdError( + 'Could not expand input before compaction.', + 'jsonld.CompactError', {cause: err})); + } - // attributes - var attributes = {}; - if(this.id != null) { - attributes.id = this.id; - } - if(this.fontSize != null) { - attributes.fontSize = this.fontSize; - } - if(this.fontFamily != null) { - attributes.fontFamily = this.fontFamily; - } - if(this.fontWeight != null) { - attributes.fontWeight = this.fontWeight; - } - if(this.fontStyle != null) { - attributes.fontStyle = this.fontStyle; - } - if(this.textAnchor != null) { - attributes.textAnchor = this.textAnchor; - } - if(this.vtextAnchor != null) { - attributes.vtextAnchor = this.vtextAnchor; - } - if(this.stroke != null) { - attributes.stroke = this.stroke; - } - if(this.strokeWidth != null) { - attributes.strokeWidth = this.strokeWidth; - } - if(this.fill != null) { - attributes.fill = this.fill; - } - utils.addAttributes(renderGroupObj, attributes); - return renderGroupObj; -}; + // process context + var activeCtx = _getInitialContext(options); + jsonld.processContext(activeCtx, ctx, options, function(err, activeCtx) { + if(err) { + return callback(new JsonLdError( + 'Could not process context before compaction.', + 'jsonld.CompactError', {cause: err})); + } -/** - * @return {string} - */ -RenderGroup.prototype.toXML = function () { - return utils.buildString({g: this.buildJsObj()}) -}; + var compacted; + try { + // do compaction + compacted = new Processor().compact(activeCtx, null, expanded, options); + } catch(ex) { + return callback(ex); + } -/** - * @param {String} string - * @return {RenderGroup} - */ -RenderGroup.fromXML = function (string) { - var g; - function fn (err, result) { - g = RenderGroup.fromObj(result); - }; - utils.parseString(string, fn); - return g; -}; + cleanup(null, compacted, activeCtx, options); + }); + }); -/** - * @param {Object} jsObj - xml2js formatted object - * @return {RenderGroup} - */ -RenderGroup.fromObj = function (jsObj) { - if (typeof jsObj.g == 'undefined') { - throw new Error("Bad XML provided, expected tagName g, got: " + Object.keys(jsObj)[0]); - } + // performs clean up after compaction + function cleanup(err, compacted, activeCtx, options) { + if(err) { + return callback(err); + } - var g = new ns.RenderGroup(); - jsObj = jsObj.g; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return g; - } + if(options.compactArrays && !options.graph && _isArray(compacted)) { + if(compacted.length === 1) { + // simplify to a single item + compacted = compacted[0]; + } else if(compacted.length === 0) { + // simplify to an empty object + compacted = {}; + } + } else if(options.graph && _isObject(compacted)) { + // always use array if graph option is on + compacted = [compacted]; + } - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - g.id = attributes.id || null; - g.fontSize = attributes.fontSize || null; - g.fontFamily = attributes.fontFamily || null; - g.fontWeight = attributes.fontWeight || null; - g.fontStyle = attributes.fontStyle || null; - g.textAnchor = attributes.textAnchor || null; - g.vtextAnchor = attributes.vtextAnchor || null; - g.stroke = attributes.stroke || null; - g.strokeWidth = attributes.strokeWidth || null; - g.fill = attributes.fill || null; - } - return g; -}; + // follow @context key + if(_isObject(ctx) && '@context' in ctx) { + ctx = ctx['@context']; + } -ns.RenderGroup = RenderGroup; -// ------- END RENDERGROUP ------- + // build output context + ctx = _clone(ctx); + if(!_isArray(ctx)) { + ctx = [ctx]; + } + // remove empty contexts + var tmp = ctx; + ctx = []; + for(var i = 0; i < tmp.length; ++i) { + if(!_isObject(tmp[i]) || Object.keys(tmp[i]).length > 0) { + ctx.push(tmp[i]); + } + } -// ------- STYLE ------- -/** - * Represents the <style> element. - * @class - * @param {Object} params - * @param {string=} params.id - * @param {string=} params.name - * @param {string=} params.idList - * @param {RenderGroup=} params.renderGroup - */ -var Style = function(params) { - var params = checkParams(params, ['id', 'name', 'idList', 'renderGroup']); - this.id = params.id; - this.name = params.name; - this.idList = params.idList; // TODO add utility functions to manage this (should be array) - this.renderGroup = params.renderGroup; -}; + // remove array if only one context + var hasContext = (ctx.length > 0); + if(ctx.length === 1) { + ctx = ctx[0]; + } -/** - * @param {RenderGroup} renderGroup - */ -Style.prototype.setRenderGroup = function (renderGroup) { - this.renderGroup = renderGroup; + // add context and/or @graph + if(_isArray(compacted)) { + // use '@graph' keyword + var kwgraph = _compactIri(activeCtx, '@graph'); + var graph = compacted; + compacted = {}; + if(hasContext) { + compacted['@context'] = ctx; + } + compacted[kwgraph] = graph; + } else if(_isObject(compacted) && hasContext) { + // reorder keys so @context is first + var graph = compacted; + compacted = {'@context': ctx}; + for(var key in graph) { + compacted[key] = graph[key]; + } + } + + callback(null, compacted, activeCtx); + } }; /** - * @return {string[]} + * Performs JSON-LD expansion. + * + * @param input the JSON-LD input to expand. + * @param [options] the options to use: + * [base] the base IRI to use. + * [expandContext] a context to expand with. + * [keepFreeFloatingNodes] true to keep free-floating nodes, + * false not to, defaults to false. + * [documentLoader(url, callback(err, remoteDoc))] the document loader. + * @param callback(err, expanded) called once the operation completes. */ -Style.prototype.getIdListAsArray = function () { - return this.idList.split(' '); -} +jsonld.expand = function(input, options, callback) { + if(arguments.length < 1) { + return jsonld.nextTick(function() { + callback(new TypeError('Could not expand, too few arguments.')); + }); + } -/** - * @param {string[]} idArray - */ -Style.prototype.setIdListFromArray = function (idArray) { - this.idList = idArray.join(' '); -} + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; -/** - * Convenience function returning a map of ids to their respective RenderGroup object. - * The style properties can then be directly accessed. Example: map[id].stroke - * @return {Object.} - */ -Style.prototype.getStyleMap = function () { - var index = {}; - var ids = this.getIdListAsArray(); - for(var i=0; i < ids.length; i++) { - var id = ids[i]; - index[id] = this.renderGroup; - } - return index; -}; -/** - * @return {Object} - xml2js formatted object - */ -Style.prototype.buildJsObj = function () { - var styleObj = {}; - - // attributes - var attributes = {}; - if(this.id != null) { - attributes.id = this.id; - } - if(this.name != null) { - attributes.name = this.name; - } - if(this.idList != null) { - attributes.idList = this.idList; - } - utils.addAttributes(styleObj, attributes); - - // children - if(this.renderGroup != null) { - styleObj.g = this.renderGroup.buildJsObj(); - } - return styleObj; -}; + // set default options + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } + if(!('keepFreeFloatingNodes' in options)) { + options.keepFreeFloatingNodes = false; + } -/** - * @return {string} - */ -Style.prototype.toXML = function () { - return utils.buildString({style: this.buildJsObj()}) -}; + jsonld.nextTick(function() { + // if input is a string, attempt to dereference remote document + if(typeof input === 'string') { + var done = function(err, remoteDoc) { + if(err) { + return callback(err); + } + try { + if(!remoteDoc.document) { + throw new JsonLdError( + 'No remote document found at the given URL.', + 'jsonld.NullRemoteDocument'); + } + if(typeof remoteDoc.document === 'string') { + remoteDoc.document = JSON.parse(remoteDoc.document); + } + } catch(ex) { + return callback(new JsonLdError( + 'Could not retrieve a JSON-LD document from the URL. URL ' + + 'dereferencing not implemented.', 'jsonld.LoadDocumentError', { + code: 'loading document failed', + cause: ex, + remoteDoc: remoteDoc + })); + } + expand(remoteDoc); + }; + var promise = options.documentLoader(input, done); + if(promise && 'then' in promise) { + promise.then(done.bind(null, null), done); + } + return; + } + // nothing to load + expand({contextUrl: null, documentUrl: null, document: input}); + }); -/** - * @param {String} string - * @return {Style} - */ -Style.fromXML = function (string) { - var style; - function fn (err, result) { - style = Style.fromObj(result); + function expand(remoteDoc) { + // set default base + if(!('base' in options)) { + options.base = remoteDoc.documentUrl || ''; + } + // build meta-object and retrieve all @context URLs + var input = { + document: _clone(remoteDoc.document), + remoteContext: {'@context': remoteDoc.contextUrl} }; - utils.parseString(string, fn); - return style; -}; - -/** - * @param {Object} jsObj - xml2js formatted object - * @return {Style} - */ -Style.fromObj = function (jsObj) { - if (typeof jsObj.style == 'undefined') { - throw new Error("Bad XML provided, expected tagName style, got: " + Object.keys(jsObj)[0]); - } + if('expandContext' in options) { + var expandContext = _clone(options.expandContext); + if(typeof expandContext === 'object' && '@context' in expandContext) { + input.expandContext = expandContext; + } else { + input.expandContext = {'@context': expandContext}; + } + } + _retrieveContextUrls(input, options, function(err, input) { + if(err) { + return callback(err); + } - var style = new ns.Style(); - jsObj = jsObj.style; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return style; - } + var expanded; + try { + var processor = new Processor(); + var activeCtx = _getInitialContext(options); + var document = input.document; + var remoteContext = input.remoteContext['@context']; - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - style.id = attributes.id || null; - style.name = attributes.name || null; - style.idList = attributes.idList || null; - } + // process optional expandContext + if(input.expandContext) { + activeCtx = processor.processContext( + activeCtx, input.expandContext['@context'], options); + } - // children - if(jsObj.g) { - var g = ns.RenderGroup.fromObj({g: jsObj.g[0]}); - style.setRenderGroup(g); - } + // process remote context from HTTP Link Header + if(remoteContext) { + activeCtx = processor.processContext( + activeCtx, remoteContext, options); + } - return style; -}; + // expand document + expanded = processor.expand( + activeCtx, null, document, options, false); -ns.Style = Style; -// ------- END STYLE ------- + // optimize away @graph with no other properties + if(_isObject(expanded) && ('@graph' in expanded) && + Object.keys(expanded).length === 1) { + expanded = expanded['@graph']; + } else if(expanded === null) { + expanded = []; + } -// ------- LISTOFSTYLES ------- -/** - * Represents the <listOfStyles> element. - * @class - */ -var ListOfStyles = function() { - this.styles = []; + // normalize to an array + if(!_isArray(expanded)) { + expanded = [expanded]; + } + } catch(ex) { + return callback(ex); + } + callback(null, expanded); + }); + } }; /** - * @param {Style} style + * Performs JSON-LD flattening. + * + * @param input the JSON-LD to flatten. + * @param ctx the context to use to compact the flattened output, or null. + * @param [options] the options to use: + * [base] the base IRI to use. + * [expandContext] a context to expand with. + * [documentLoader(url, callback(err, remoteDoc))] the document loader. + * @param callback(err, flattened) called once the operation completes. */ -ListOfStyles.prototype.addStyle = function (style) { - this.styles.push(style); -}; +jsonld.flatten = function(input, ctx, options, callback) { + if(arguments.length < 1) { + return jsonld.nextTick(function() { + callback(new TypeError('Could not flatten, too few arguments.')); + }); + } -/** - * Convenience function returning a map of ids to their respective RenderGroup object, - * for all the styles. - * The style properties can then be directly accessed. Example: map[id].stroke - * @return {Object.} - */ -ListOfStyles.prototype.getStyleMap = function () { - var index = {}; - for(var i=0; i < this.styles.length; i++) { - var style = this.styles[i]; - var subIndex = style.getStyleMap(); - for(var id in subIndex) { - index[id] = subIndex[id]; - } - } - return index; -} + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } else if(typeof ctx === 'function') { + callback = ctx; + ctx = null; + options = {}; + } + options = options || {}; -/** - * @return {Object} - xml2js formatted object - */ -ListOfStyles.prototype.buildJsObj = function () { - var listOfStylesObj = {}; + // set default options + if(!('base' in options)) { + options.base = (typeof input === 'string') ? input : ''; + } + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } - for(var i=0; i < this.styles.length; i++) { - if (i==0) { - listOfStylesObj.style = []; - } - listOfStylesObj.style.push(this.styles[i].buildJsObj()); - } + // expand input + jsonld.expand(input, options, function(err, _input) { + if(err) { + return callback(new JsonLdError( + 'Could not expand input before flattening.', + 'jsonld.FlattenError', {cause: err})); + } - return listOfStylesObj; -}; + var flattened; + try { + // do flattening + flattened = new Processor().flatten(_input); + } catch(ex) { + return callback(ex); + } -/** - * @return {string} - */ -ListOfStyles.prototype.toXML = function () { - return utils.buildString({listOfStyles: this.buildJsObj()}) -}; + if(ctx === null) { + return callback(null, flattened); + } -/** - * @param {String} string - * @return {ListOfStyles} - */ -ListOfStyles.fromXML = function (string) { - var listOfStyles; - function fn (err, result) { - listOfStyles = ListOfStyles.fromObj(result); - }; - utils.parseString(string, fn); - return listOfStyles; + // compact result (force @graph option to true, skip expansion) + options.graph = true; + options.skipExpansion = true; + jsonld.compact(flattened, ctx, options, function(err, compacted) { + if(err) { + return callback(new JsonLdError( + 'Could not compact flattened output.', + 'jsonld.FlattenError', {cause: err})); + } + callback(null, compacted); + }); + }); }; /** - * @param {Object} jsObj - xml2js formatted object - * @return {ListOfStyles} + * Performs JSON-LD framing. + * + * @param input the JSON-LD input to frame. + * @param frame the JSON-LD frame to use. + * @param [options] the framing options. + * [base] the base IRI to use. + * [expandContext] a context to expand with. + * [embed] default @embed flag: '@last', '@always', '@never', '@link' + * (default: '@last'). + * [explicit] default @explicit flag (default: false). + * [requireAll] default @requireAll flag (default: true). + * [omitDefault] default @omitDefault flag (default: false). + * [documentLoader(url, callback(err, remoteDoc))] the document loader. + * @param callback(err, framed) called once the operation completes. */ -ListOfStyles.fromObj = function (jsObj) { - if (typeof jsObj.listOfStyles == 'undefined') { - throw new Error("Bad XML provided, expected tagName listOfStyles, got: " + Object.keys(jsObj)[0]); - } +jsonld.frame = function(input, frame, options, callback) { + if(arguments.length < 2) { + return jsonld.nextTick(function() { + callback(new TypeError('Could not frame, too few arguments.')); + }); + } - var listOfStyles = new ns.ListOfStyles(); - jsObj = jsObj.listOfStyles; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return listOfStyles; - } + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; - // children - if(jsObj.style) { - var styles = jsObj.style; - for (var i=0; i < styles.length; i++) { - var style = ns.Style.fromObj({style: styles[i]}); - listOfStyles.addStyle(style); - } - } + // set default options + if(!('base' in options)) { + options.base = (typeof input === 'string') ? input : ''; + } + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } + if(!('embed' in options)) { + options.embed = '@last'; + } + options.explicit = options.explicit || false; + if(!('requireAll' in options)) { + options.requireAll = true; + } + options.omitDefault = options.omitDefault || false; - return listOfStyles; -}; + jsonld.nextTick(function() { + // if frame is a string, attempt to dereference remote document + if(typeof frame === 'string') { + var done = function(err, remoteDoc) { + if(err) { + return callback(err); + } + try { + if(!remoteDoc.document) { + throw new JsonLdError( + 'No remote document found at the given URL.', + 'jsonld.NullRemoteDocument'); + } + if(typeof remoteDoc.document === 'string') { + remoteDoc.document = JSON.parse(remoteDoc.document); + } + } catch(ex) { + return callback(new JsonLdError( + 'Could not retrieve a JSON-LD document from the URL. URL ' + + 'dereferencing not implemented.', 'jsonld.LoadDocumentError', { + code: 'loading document failed', + cause: ex, + remoteDoc: remoteDoc + })); + } + doFrame(remoteDoc); + }; + var promise = options.documentLoader(frame, done); + if(promise && 'then' in promise) { + promise.then(done.bind(null, null), done); + } + return; + } + // nothing to load + doFrame({contextUrl: null, documentUrl: null, document: frame}); + }); -ns.ListOfStyles = ListOfStyles; -// ------- END LISTOFSTYLES ------- + function doFrame(remoteFrame) { + // preserve frame context and add any Link header context + var frame = remoteFrame.document; + var ctx; + if(frame) { + ctx = frame['@context']; + if(remoteFrame.contextUrl) { + if(!ctx) { + ctx = remoteFrame.contextUrl; + } else if(_isArray(ctx)) { + ctx.push(remoteFrame.contextUrl); + } else { + ctx = [ctx, remoteFrame.contextUrl]; + } + frame['@context'] = ctx; + } else { + ctx = ctx || {}; + } + } else { + ctx = {}; + } -// ------- RENDERINFORMATION ------- -/** - * Represents the <renderInformation> element. - * @class - * @param {Object} params - * @param {string=} params.id - * @param {string=} params.name - * @param {string=} params.programName - * @param {string=} params.programVersion - * @param {string=} params.backgroundColor - * @param {ListOfColorDefinitions=} params.listOfColorDefinitions - * @param {ListOfStyles=} params.listOfStyles - */ -var RenderInformation = function (params) { - var params = checkParams(params, ['id', 'name', 'programName', - 'programVersion', 'backgroundColor', 'listOfColorDefinitions', 'listOfStyles']); - this.id = params.id; // required, rest is optional - this.name = params.name; - this.programName = params.programName; - this.programVersion = params.programVersion; - this.backgroundColor = params.backgroundColor; - this.listOfColorDefinitions = params.listOfColorDefinitions; - this.listOfStyles = params.listOfStyles; + // expand input + jsonld.expand(input, options, function(err, expanded) { + if(err) { + return callback(new JsonLdError( + 'Could not expand input before framing.', + 'jsonld.FrameError', {cause: err})); + } + + // expand frame + var opts = _clone(options); + opts.isFrame = true; + opts.keepFreeFloatingNodes = true; + jsonld.expand(frame, opts, function(err, expandedFrame) { + if(err) { + return callback(new JsonLdError( + 'Could not expand frame before framing.', + 'jsonld.FrameError', {cause: err})); + } + + var framed; + try { + // do framing + framed = new Processor().frame(expanded, expandedFrame, opts); + } catch(ex) { + return callback(ex); + } + + // compact result (force @graph option to true, skip expansion, + // check for linked embeds) + opts.graph = true; + opts.skipExpansion = true; + opts.link = {}; + jsonld.compact(framed, ctx, opts, function(err, compacted, ctx) { + if(err) { + return callback(new JsonLdError( + 'Could not compact framed output.', + 'jsonld.FrameError', {cause: err})); + } + // get graph alias + var graph = _compactIri(ctx, '@graph'); + // remove @preserve from results + opts.link = {}; + compacted[graph] = _removePreserve(ctx, compacted[graph], opts); + callback(null, compacted); + }); + }); + }); + } }; /** - * @param {ListOfColorDefinitions} listOfColorDefinitions + * **Experimental** + * + * Links a JSON-LD document's nodes in memory. + * + * @param input the JSON-LD document to link. + * @param ctx the JSON-LD context to apply. + * @param [options] the options to use: + * [base] the base IRI to use. + * [expandContext] a context to expand with. + * [documentLoader(url, callback(err, remoteDoc))] the document loader. + * @param callback(err, linked) called once the operation completes. */ -RenderInformation.prototype.setListOfColorDefinitions = function(listOfColorDefinitions) { - this.listOfColorDefinitions = listOfColorDefinitions; +jsonld.link = function(input, ctx, options, callback) { + // API matches running frame with a wildcard frame and embed: '@link' + // get arguments + var frame = {}; + if(ctx) { + frame['@context'] = ctx; + } + frame['@embed'] = '@link'; + jsonld.frame(input, frame, options, callback); }; /** - * @param {ListOfStyles} listOfStyles - */ -RenderInformation.prototype.setListOfStyles = function(listOfStyles) { - this.listOfStyles = listOfStyles; -}; - -/** - * @return {Object} - xml2js formatted object - */ -RenderInformation.prototype.buildJsObj = function () { - var renderInformationObj = {}; - - // attributes - var attributes = {}; - attributes.xmlns = ns.xmlns; - if(this.id != null) { - attributes.id = this.id; - } - if(this.name != null) { - attributes.name = this.name; - } - if(this.programName != null) { - attributes.programName = this.programName; - } - if(this.programVersion != null) { - attributes.programVersion = this.programVersion; - } - if(this.backgroundColor != null) { - attributes.backgroundColor = this.backgroundColor; - } - utils.addAttributes(renderInformationObj, attributes); - - // children - if(this.listOfColorDefinitions != null) { - renderInformationObj.listOfColorDefinitions = this.listOfColorDefinitions.buildJsObj(); - } - if(this.listOfStyles != null) { - renderInformationObj.listOfStyles = this.listOfStyles.buildJsObj(); - } - return renderInformationObj; -}; - -/** - * @return {string} - */ -RenderInformation.prototype.toXML = function() { - return utils.buildString({renderInformation: this.buildJsObj()}) -}; - -/** - * @param {String} string - * @return {RenderInformation} - */ -RenderInformation.fromXML = function (string) { - var renderInformation; - function fn (err, result) { - renderInformation = RenderInformation.fromObj(result); - }; - utils.parseString(string, fn); - return renderInformation; -}; - -/** - * @param {Object} jsObj - xml2js formatted object - * @return {RenderInformation} + * **Deprecated** + * + * Performs JSON-LD objectification. + * + * @param input the JSON-LD document to objectify. + * @param ctx the JSON-LD context to apply. + * @param [options] the options to use: + * [base] the base IRI to use. + * [expandContext] a context to expand with. + * [documentLoader(url, callback(err, remoteDoc))] the document loader. + * @param callback(err, linked) called once the operation completes. */ -RenderInformation.fromObj = function (jsObj) { - if (typeof jsObj.renderInformation == 'undefined') { - throw new Error("Bad XML provided, expected tagName renderInformation, got: " + Object.keys(jsObj)[0]); - } - - var renderInformation = new ns.RenderInformation(); - jsObj = jsObj.renderInformation; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return renderInformation; - } +jsonld.objectify = function(input, ctx, options, callback) { + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - renderInformation.id = attributes.id || null; - renderInformation.name = attributes.name || null; - renderInformation.programName = attributes.programName || null; - renderInformation.programVersion = attributes.programVersion || null; - renderInformation.backgroundColor = attributes.backgroundColor || null; - } + // set default options + if(!('base' in options)) { + options.base = (typeof input === 'string') ? input : ''; + } + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } - // children - if(jsObj.listOfColorDefinitions) { - var listOfColorDefinitions = ns.ListOfColorDefinitions.fromObj({listOfColorDefinitions: jsObj.listOfColorDefinitions[0]}); - renderInformation.setListOfColorDefinitions(listOfColorDefinitions); - } - if(jsObj.listOfStyles) { - var listOfStyles = ns.ListOfStyles.fromObj({listOfStyles: jsObj.listOfStyles[0]}); - renderInformation.setListOfStyles(listOfStyles); - } + // expand input + jsonld.expand(input, options, function(err, _input) { + if(err) { + return callback(new JsonLdError( + 'Could not expand input before linking.', + 'jsonld.LinkError', {cause: err})); + } - return renderInformation; -}; + var flattened; + try { + // flatten the graph + flattened = new Processor().flatten(_input); + } catch(ex) { + return callback(ex); + } -ns.RenderInformation = RenderInformation; -// ------- END RENDERINFORMATION ------- + // compact result (force @graph option to true, skip expansion) + options.graph = true; + options.skipExpansion = true; + jsonld.compact(flattened, ctx, options, function(err, compacted, ctx) { + if(err) { + return callback(new JsonLdError( + 'Could not compact flattened output before linking.', + 'jsonld.LinkError', {cause: err})); + } + // get graph alias + var graph = _compactIri(ctx, '@graph'); + var top = compacted[graph][0]; -module.exports = ns; -},{"./utilities":24,"xml2js":118}],23:[function(_dereq_,module,exports){ -/** - * The API contains two other submodules: {@link libsbgn.render} and {@link libsbgn.annot} - * @module libsbgn - * @namespace libsbgn -*/ + var recurse = function(subject) { + // can't replace just a string + if(!_isObject(subject) && !_isArray(subject)) { + return; + } -var renderExt = _dereq_('./libsbgn-render'); -var annotExt = _dereq_('./libsbgn-annotations'); -var xml2js = _dereq_('xml2js'); -var utils = _dereq_('./utilities'); -var checkParams = utils.checkParams; + // bottom out recursion on re-visit + if(_isObject(subject)) { + if(recurse.visited[subject['@id']]) { + return; + } + recurse.visited[subject['@id']] = true; + } -var ns = {}; // namespace that encapsulates all exportable features + // each array element *or* object key + for(var k in subject) { + var obj = subject[k]; + var isid = (jsonld.getContextValue(ctx, k, '@type') === '@id'); -ns.xmlns = "http://sbgn.org/libsbgn/0.3"; + // can't replace a non-object or non-array unless it's an @id + if(!_isArray(obj) && !_isObject(obj) && !isid) { + continue; + } -// ------- SBGNBase ------- -/** - * Parent class for several sbgn elements. Used to provide extension and notes element. - * End users don't need to interact with it. It can be safely ignored. - * @class - * @param {Object} params - * @param {Extension=} params.extension - * @param {Notes=} params.notes - */ -var SBGNBase = function (params) { - var params = checkParams(params, ['extension', 'notes']); - this.extension = params.extension; - this.notes = params.notes; -}; + if(_isString(obj) && isid) { + subject[k] = obj = top[obj]; + recurse(obj); + } else if(_isArray(obj)) { + for(var i = 0; i < obj.length; ++i) { + if(_isString(obj[i]) && isid) { + obj[i] = top[obj[i]]; + } else if(_isObject(obj[i]) && '@id' in obj[i]) { + obj[i] = top[obj[i]['@id']]; + } + recurse(obj[i]); + } + } else if(_isObject(obj)) { + var sid = obj['@id']; + subject[k] = obj = top[sid]; + recurse(obj); + } + } + }; + recurse.visited = {}; + recurse(top); -/** - * Allows inheriting objects to get an extension element. - * @param {Extension} extension - */ -SBGNBase.prototype.setExtension = function (extension) { - this.extension = extension; + compacted.of_type = {}; + for(var s in top) { + if(!('@type' in top[s])) { + continue; + } + var types = top[s]['@type']; + if(!_isArray(types)) { + types = [types]; + } + for(var t = 0; t < types.length; ++t) { + if(!(types[t] in compacted.of_type)) { + compacted.of_type[types[t]] = []; + } + compacted.of_type[types[t]].push(top[s]); + } + } + callback(null, compacted); + }); + }); }; /** - * Allows inheriting objects to get a notes element. - * @param {Notes} notes + * Performs RDF dataset normalization on the given input. The input is JSON-LD + * unless the 'inputFormat' option is used. The output is an RDF dataset + * unless the 'format' option is used. + * + * @param input the input to normalize as JSON-LD or as a format specified by + * the 'inputFormat' option. + * @param [options] the options to use: + * [algorithm] the normalization algorithm to use, `URDNA2015` or + * `URGNA2012` (default: `URGNA2012`). + * [base] the base IRI to use. + * [expandContext] a context to expand with. + * [inputFormat] the format if input is not JSON-LD: + * 'application/nquads' for N-Quads. + * [format] the format if output is a string: + * 'application/nquads' for N-Quads. + * [documentLoader(url, callback(err, remoteDoc))] the document loader. + * @param callback(err, normalized) called once the operation completes. */ -SBGNBase.prototype.setNotes = function (notes) { - this.notes = notes; -}; +jsonld.normalize = function(input, options, callback) { + if(arguments.length < 1) { + return jsonld.nextTick(function() { + callback(new TypeError('Could not normalize, too few arguments.')); + }); + } -/** - * Add the appropriate properties to jsObj. - * @param {Object} jsObj - xml2js formatted object - */ -SBGNBase.prototype.baseToJsObj = function (jsObj) { - if(this.extension != null) { - jsObj.extension = this.extension.buildJsObj(); - } - if(this.notes != null) { - jsObj.notes = this.notes.buildJsObj(); - } -}; + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; -/** - * Get the appropriate properties from jsObj. - * @param {Object} jsObj - xml2js formatted object - */ -SBGNBase.prototype.baseFromObj = function (jsObj) { - if (jsObj.extension) { - var extension = ns.Extension.fromObj({extension: jsObj.extension[0]}); - this.setExtension(extension); - } - if (jsObj.notes) { - var notes = ns.Notes.fromObj({notes: jsObj.notes[0]}); - this.setNotes(notes); - } -}; -ns.SBGNBase = SBGNBase; -// ------- END SBGNBase ------- + // set default options + if(!('algorithm' in options)) { + options.algorithm = 'URGNA2012'; + } + if(!('base' in options)) { + options.base = (typeof input === 'string') ? input : ''; + } + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } -// ------- SBGN ------- -/** - * Represents the <sbgn> element. - * @class - * @extends SBGNBase - * @param {Object} params - * @param {string=} params.xmlns - * @param {Map[]=} params.maps - */ -var Sbgn = function (params) { - ns.SBGNBase.call(this, params); - var params = checkParams(params, ['xmlns', 'maps']); - this.xmlns = params.xmlns; - this.maps = params.maps || []; + if('inputFormat' in options) { + if(options.inputFormat !== 'application/nquads') { + return callback(new JsonLdError( + 'Unknown normalization input format.', + 'jsonld.NormalizeError')); + } + var parsedInput = _parseNQuads(input); + // do normalization + new Processor().normalize(parsedInput, options, callback); + } else { + // convert to RDF dataset then do normalization + var opts = _clone(options); + delete opts.format; + opts.produceGeneralizedRdf = false; + jsonld.toRDF(input, opts, function(err, dataset) { + if(err) { + return callback(new JsonLdError( + 'Could not convert input to RDF dataset before normalization.', + 'jsonld.NormalizeError', {cause: err})); + } + // do normalization + new Processor().normalize(dataset, options, callback); + }); + } }; -Sbgn.prototype = Object.create(ns.SBGNBase.prototype); -Sbgn.prototype.constructor = Sbgn; - /** - * @param {Map} map + * Converts an RDF dataset to JSON-LD. + * + * @param dataset a serialized string of RDF in a format specified by the + * format option or an RDF dataset to convert. + * @param [options] the options to use: + * [format] the format if dataset param must first be parsed: + * 'application/nquads' for N-Quads (default). + * [rdfParser] a custom RDF-parser to use to parse the dataset. + * [useRdfType] true to use rdf:type, false to use @type + * (default: false). + * [useNativeTypes] true to convert XSD types into native types + * (boolean, integer, double), false not to (default: false). + * @param callback(err, output) called once the operation completes. */ -Sbgn.prototype.addMap = function (map) { - this.maps.push(map); -}; +jsonld.fromRDF = function(dataset, options, callback) { + if(arguments.length < 1) { + return jsonld.nextTick(function() { + callback(new TypeError('Could not convert from RDF, too few arguments.')); + }); + } -/** - * @return {Object} - xml2js formatted object - */ -Sbgn.prototype.buildJsObj = function () { - var sbgnObj = {}; + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; - // attributes - var attributes = {}; - if(this.xmlns != null) { - attributes.xmlns = this.xmlns; - } - utils.addAttributes(sbgnObj, attributes); + // set default options + if(!('useRdfType' in options)) { + options.useRdfType = false; + } + if(!('useNativeTypes' in options)) { + options.useNativeTypes = false; + } - // children - this.baseToJsObj(sbgnObj); - for(var i=0; i < this.maps.length; i++) { - if (i==0) { - sbgnObj.map = []; - } - sbgnObj.map.push(this.maps[i].buildJsObj()); - } - return sbgnObj; -}; + if(!('format' in options) && _isString(dataset)) { + // set default format to nquads + if(!('format' in options)) { + options.format = 'application/nquads'; + } + } -/** - * @return {string} - */ -Sbgn.prototype.toXML = function () { - return utils.buildString({sbgn: this.buildJsObj()}); -}; + jsonld.nextTick(function() { + // handle special format + var rdfParser; + if(options.format) { + // check supported formats + rdfParser = options.rdfParser || _rdfParsers[options.format]; + if(!rdfParser) { + return callback(new JsonLdError( + 'Unknown input format.', + 'jsonld.UnknownFormat', {format: options.format})); + } + } else { + // no-op parser, assume dataset already parsed + rdfParser = function() { + return dataset; + }; + } -/** - * @param {String} string - * @return {Sbgn} - */ -Sbgn.fromXML = function (string) { - var sbgn; - function fn (err, result) { - sbgn = Sbgn.fromObj(result); + var callbackCalled = false; + try { + // rdf parser may be async or sync, always pass callback + dataset = rdfParser(dataset, function(err, dataset) { + callbackCalled = true; + if(err) { + return callback(err); + } + fromRDF(dataset, options, callback); + }); + } catch(e) { + if(!callbackCalled) { + return callback(e); + } + throw e; + } + // handle synchronous or promise-based parser + if(dataset) { + // if dataset is actually a promise + if('then' in dataset) { + return dataset.then(function(dataset) { + fromRDF(dataset, options, callback); + }, callback); + } + // parser is synchronous + fromRDF(dataset, options, callback); } - utils.parseString(string, fn); - return sbgn; + function fromRDF(dataset, options, callback) { + // convert from RDF + new Processor().fromRDF(dataset, options, callback); + } + }); }; /** - * @param {Object} jsObj - xml2js formatted object - * @return {Sbgn} + * Outputs the RDF dataset found in the given JSON-LD object. + * + * @param input the JSON-LD input. + * @param [options] the options to use: + * [base] the base IRI to use. + * [expandContext] a context to expand with. + * [format] the format to use to output a string: + * 'application/nquads' for N-Quads. + * [produceGeneralizedRdf] true to output generalized RDF, false + * to produce only standard RDF (default: false). + * [documentLoader(url, callback(err, remoteDoc))] the document loader. + * @param callback(err, dataset) called once the operation completes. */ -Sbgn.fromObj = function (jsObj) { - if (typeof jsObj.sbgn == 'undefined') { - throw new Error("Bad XML provided, expected tagName sbgn, got: " + Object.keys(jsObj)[0]); - } +jsonld.toRDF = function(input, options, callback) { + if(arguments.length < 1) { + return jsonld.nextTick(function() { + callback(new TypeError('Could not convert to RDF, too few arguments.')); + }); + } - var sbgn = new ns.Sbgn(); - jsObj = jsObj.sbgn; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return sbgn; - } + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; - if(jsObj.$) { // we have some atributes - var attributes = jsObj.$; - sbgn.xmlns = attributes.xmlns || null; - - // getting attribute with 'xmlns' doesn't work if some namespace is defined like 'xmlns:sbgn' - // so if there is some attribute there, and we didn't find the xmlns directly, we need to into it - if(!sbgn.xmlns && Object.keys(attributes).length > 0) { - // sbgn is not supposed to have any other attribute than an xmlns, so we assume the first attr is the xmlns - var key = Object.keys(attributes)[0]; - if(key.startsWith('xmlns')) { - sbgn.xmlns = attributes[key]; - sbgn.namespacePrefix = key.replace('xmlns:', ''); - } - else { - throw new Error("Couldn't find xmlns definition in sbgn element"); - } - } - } + // set default options + if(!('base' in options)) { + options.base = (typeof input === 'string') ? input : ''; + } + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } - if(jsObj.map) { - var maps = jsObj.map; - for (var i=0; i < maps.length; i++) { - var map = ns.Map.fromObj({map: maps[i]}); - sbgn.addMap(map); - } - } + // expand input + jsonld.expand(input, options, function(err, expanded) { + if(err) { + return callback(new JsonLdError( + 'Could not expand input before serialization to RDF.', + 'jsonld.RdfError', {cause: err})); + } - sbgn.baseFromObj(jsObj); // call to parent class - return sbgn; + var dataset; + try { + // output RDF dataset + dataset = Processor.prototype.toRDF(expanded, options); + if(options.format) { + if(options.format === 'application/nquads') { + return callback(null, _toNQuads(dataset)); + } + throw new JsonLdError( + 'Unknown output format.', + 'jsonld.UnknownFormat', {format: options.format}); + } + } catch(ex) { + return callback(ex); + } + callback(null, dataset); + }); }; -ns.Sbgn = Sbgn; -// ------- END SBGN ------- -// ------- MAP ------- /** - * Represents the <map> element. - * @class - * @extends SBGNBase - * @param {Object} params - * @param {string=} params.id - * @param {string=} params.language - * @param {string=} params.version - * @param {Glyph[]=} params.glyphs - * @param {Arc[]=} params.arcs - * @param {Bbox=} params.bbox - * @param {Arcgroup[]=} params.arcgroups + * **Experimental** + * + * Recursively flattens the nodes in the given JSON-LD input into a map of + * node ID => node. + * + * @param input the JSON-LD input. + * @param [options] the options to use: + * [base] the base IRI to use. + * [expandContext] a context to expand with. + * [issuer] a jsonld.IdentifierIssuer to use to label blank nodes. + * [namer] (deprecated) + * [documentLoader(url, callback(err, remoteDoc))] the document loader. + * @param callback(err, nodeMap) called once the operation completes. */ -var Map = function (params) { - ns.SBGNBase.call(this, params); - var params = checkParams(params, ['id', 'language', 'version', 'glyphs', 'arcs', 'bbox', 'arcgroups']); - this.id = params.id; - this.language = params.language; - this.version = params.version; - this.bbox = params.bbox; - this.glyphs = params.glyphs || []; - this.arcs = params.arcs || []; - this.arcgroups = params.arcgroups || []; -}; +jsonld.createNodeMap = function(input, options, callback) { + if(arguments.length < 1) { + return jsonld.nextTick(function() { + callback(new TypeError('Could not create node map, too few arguments.')); + }); + } -Map.prototype = Object.create(ns.SBGNBase.prototype); -Map.prototype.constructor = Map; + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; -/** - * @param {Glyph} glyph - */ -Map.prototype.addGlyph = function (glyph) { - this.glyphs.push(glyph); -}; + // set default options + if(!('base' in options)) { + options.base = (typeof input === 'string') ? input : ''; + } + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } -/** - * @param {Arc} arc - */ -Map.prototype.addArc = function (arc) { - this.arcs.push(arc); -}; + // expand input + jsonld.expand(input, options, function(err, _input) { + if(err) { + return callback(new JsonLdError( + 'Could not expand input before creating node map.', + 'jsonld.CreateNodeMapError', {cause: err})); + } -/** - * @param {Bbox} bbox - */ -Map.prototype.setBbox = function (bbox) { - this.bbox = bbox; -}; + var nodeMap; + try { + nodeMap = new Processor().createNodeMap(_input, options); + } catch(ex) { + return callback(ex); + } -/** - * @param {Arcgroup} arc - */ -Map.prototype.addArcgroup = function (arcgroup) { - this.arcgroups.push(arcgroup); + callback(null, nodeMap); + }); }; /** - * @param {string} class_ - * @return {Gyph[]} + * **Experimental** + * + * Merges two or more JSON-LD documents into a single flattened document. + * + * @param docs the JSON-LD documents to merge together. + * @param ctx the context to use to compact the merged result, or null. + * @param [options] the options to use: + * [base] the base IRI to use. + * [expandContext] a context to expand with. + * [issuer] a jsonld.IdentifierIssuer to use to label blank nodes. + * [namer] (deprecated). + * [mergeNodes] true to merge properties for nodes with the same ID, + * false to ignore new properties for nodes with the same ID once + * the ID has been defined; note that this may not prevent merging + * new properties where a node is in the `object` position + * (default: true). + * [documentLoader(url, callback(err, remoteDoc))] the document loader. + * @param callback(err, merged) called once the operation completes. */ -Map.prototype.getGlyphsByClass = function (class_) { - var resultGlyphs = []; - for(var i=0; i < this.glyphs.length; i++) { - var glyph = this.glyphs[i]; - if(glyph.class_ == class_) { - resultGlyphs.push(glyph); - } - } - return resultGlyphs; -}; +jsonld.merge = function(docs, ctx, options, callback) { + if(arguments.length < 1) { + return jsonld.nextTick(function() { + callback(new TypeError('Could not merge, too few arguments.')); + }); + } + if(!_isArray(docs)) { + return jsonld.nextTick(function() { + callback(new TypeError('Could not merge, "docs" must be an array.')); + }); + } -/** - * @return {Object} - xml2js formatted object - */ -Map.prototype.buildJsObj = function () { - var mapObj = {}; + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } else if(typeof ctx === 'function') { + callback = ctx; + ctx = null; + options = {}; + } + options = options || {}; - // attributes - var attributes = {}; - if(this.id != null) { - attributes.id = this.id; - } - if(this.language != null) { - attributes.language = this.language; - } - if(this.version != null) { - attributes.version = this.version; - } - utils.addAttributes(mapObj, attributes); + // expand all documents + var expanded = []; + var error = null; + var count = docs.length; + for(var i = 0; i < docs.length; ++i) { + var opts = {}; + for(var key in options) { + opts[key] = options[key]; + } + jsonld.expand(docs[i], opts, expandComplete); + } - // children - this.baseToJsObj(mapObj); - if(this.bbox != null) { - mapObj.bbox = this.bbox.buildJsObj(); - } - for(var i=0; i < this.glyphs.length; i++) { - if (i==0) { - mapObj.glyph = []; - } - mapObj.glyph.push(this.glyphs[i].buildJsObj()); - } - for(var i=0; i < this.arcs.length; i++) { - if (i==0) { - mapObj.arc = []; - } - mapObj.arc.push(this.arcs[i].buildJsObj()); - } - for(var i=0; i < this.arcgroups.length; i++) { - if (i==0) { - mapObj.arcgroup = []; - } - mapObj.arcgroup.push(this.arcgroups[i].buildJsObj()); - } - return mapObj; -}; + function expandComplete(err, _input) { + if(error) { + return; + } + if(err) { + error = err; + return callback(new JsonLdError( + 'Could not expand input before flattening.', + 'jsonld.FlattenError', {cause: err})); + } + expanded.push(_input); + if(--count === 0) { + merge(expanded); + } + } -/** - * @return {string} - */ -Map.prototype.toXML = function () { - return utils.buildString({map: this.buildJsObj()}); -}; + function merge(expanded) { + var mergeNodes = true; + if('mergeNodes' in options) { + mergeNodes = options.mergeNodes; + } -/** - * @param {String} string - * @return {Map} - */ -Map.fromXML = function (string) { - var map; - function fn (err, result) { - map = Map.fromObj(result); - }; - utils.parseString(string, fn); - return map; -}; + var issuer = options.namer || options.issuer || new IdentifierIssuer('_:b'); + var graphs = {'@default': {}}; -/** - * @param {Object} jsObj - xml2js formatted object - * @return {Map} - */ -Map.fromObj = function (jsObj) { - if (typeof jsObj.map == 'undefined') { - throw new Error("Bad XML provided, expected tagName map, got: " + Object.keys(jsObj)[0]); - } + var defaultGraph; + try { + for(var i = 0; i < expanded.length; ++i) { + // uniquely relabel blank nodes + var doc = expanded[i]; + doc = jsonld.relabelBlankNodes(doc, { + issuer: new IdentifierIssuer('_:b' + i + '-') + }); - var map = new ns.Map(); - jsObj = jsObj.map; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return map; - } + // add nodes to the shared node map graphs if merging nodes, to a + // separate graph set if not + var _graphs = (mergeNodes || i === 0) ? graphs : {'@default': {}}; + _createNodeMap(doc, _graphs, '@default', issuer); - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - map.id = attributes.id || null; - map.language = attributes.language || null; - map.version = attributes.version || null; - } + if(_graphs !== graphs) { + // merge document graphs but don't merge existing nodes + for(var graphName in _graphs) { + var _nodeMap = _graphs[graphName]; + if(!(graphName in graphs)) { + graphs[graphName] = _nodeMap; + continue; + } + var nodeMap = graphs[graphName]; + for(var key in _nodeMap) { + if(!(key in nodeMap)) { + nodeMap[key] = _nodeMap[key]; + } + } + } + } + } - if(jsObj.bbox) { - var bbox = ns.Bbox.fromObj({bbox: jsObj.bbox[0]}); - map.setBbox(bbox); - } - if(jsObj.glyph) { - var glyphs = jsObj.glyph; - for (var i=0; i < glyphs.length; i++) { - var glyph = ns.Glyph.fromObj({glyph: glyphs[i]}); - map.addGlyph(glyph); - } - } - if(jsObj.arc) { - var arcs = jsObj.arc; - for (var i=0; i < arcs.length; i++) { - var arc = ns.Arc.fromObj({arc: arcs[i]}); - map.addArc(arc); - } - } - if(jsObj.arcgroup) { - var arcgroups = jsObj.arcgroup; - for (var i=0; i < arcgroups.length; i++) { - var arcgroup = ns.Arcgroup.fromObj({arcgroup: arcgroups[i]}); - map.addArcgroup(arcgroup); - } - } + // add all non-default graphs to default graph + defaultGraph = _mergeNodeMaps(graphs); + } catch(ex) { + return callback(ex); + } - map.baseFromObj(jsObj); - return map; -}; + // produce flattened output + var flattened = []; + var keys = Object.keys(defaultGraph).sort(); + for(var ki = 0; ki < keys.length; ++ki) { + var node = defaultGraph[keys[ki]]; + // only add full subjects to top-level + if(!_isSubjectReference(node)) { + flattened.push(node); + } + } -ns.Map = Map; -// ------- END MAP ------- + if(ctx === null) { + return callback(null, flattened); + } + + // compact result (force @graph option to true, skip expansion) + options.graph = true; + options.skipExpansion = true; + jsonld.compact(flattened, ctx, options, function(err, compacted) { + if(err) { + return callback(new JsonLdError( + 'Could not compact merged output.', + 'jsonld.MergeError', {cause: err})); + } + callback(null, compacted); + }); + } +}; -// ------- EXTENSION ------- /** - * Represents the <extension> element. - * @class + * Relabels all blank nodes in the given JSON-LD input. + * + * @param input the JSON-LD input. + * @param [options] the options to use: + * [issuer] a jsonld.IdentifierIssuer to use to label blank nodes. + * [namer] (deprecated). */ -var Extension = function () { - // consider first order children, add them with their tagname as property of this object - // store string if no supported parsing (unrecognized extensions) - // else store instance of the extension - this.list = {}; +jsonld.relabelBlankNodes = function(input, options) { + options = options || {}; + var issuer = options.namer || options.issuer || new IdentifierIssuer('_:b'); + return _labelBlankNodes(issuer, input); }; /** - * @param {String|render.RenderInformation|annot.Annotation} extension + * Prepends a base IRI to the given relative IRI. + * + * @param base the base IRI. + * @param iri the relative IRI. + * + * @return the absolute IRI. */ -Extension.prototype.add = function (extension) { - if (extension instanceof renderExt.RenderInformation) { - this.list['renderInformation'] = extension; - } - else if (extension instanceof annotExt.Annotation) { - this.list['annotation'] = extension; - } - else if(typeof extension == "string") { - var parsedAsObj; - function fn (err, result) { - parsedAsObj = result; - }; - utils.parseString(extension, fn); - var name = Object.keys(parsedAsObj)[0]; - if(name == "renderInformation") { - var renderInformation = renderExt.RenderInformation.fromXML(extension); - this.list['renderInformation'] = renderInformation; - } - else if(name == "annotation") { - var annotation = annotExt.Annotation.fromXML(extension); - this.list['annotation'] = renderInformation; - } - else { - this.list[name] = extension; - } - } +jsonld.prependBase = function(base, iri) { + return _prependBase(base, iri); }; /** - * @param {string} extensionName - * @return {boolean} + * The default document loader for external documents. If the environment + * is node.js, a callback-continuation-style document loader is used; otherwise, + * a promises-style document loader is used. + * + * @param url the URL to load. + * @param callback(err, remoteDoc) called once the operation completes, + * if using a non-promises API. + * + * @return a promise, if using a promises API. */ -Extension.prototype.has = function (extensionName) { - return this.list.hasOwnProperty(extensionName); +jsonld.documentLoader = function(url, callback) { + var err = new JsonLdError( + 'Could not retrieve a JSON-LD document from the URL. URL ' + + 'dereferencing not implemented.', 'jsonld.LoadDocumentError', + {code: 'loading document failed'}); + if(_nodejs) { + return callback(err, {contextUrl: null, documentUrl: url, document: null}); + } + return jsonld.promisify(function(callback) { + callback(err); + }); }; /** - * @param {string} extensionName - * @return {String|render.RenderInformation|annot.Annotation} + * Deprecated default document loader. Use or override jsonld.documentLoader + * instead. */ -Extension.prototype.get = function (extensionName) { - if (this.has(extensionName)) { - return this.list[extensionName]; - } - else { - return null; - } +jsonld.loadDocument = function(url, callback) { + var promise = jsonld.documentLoader(url, callback); + if(promise && 'then' in promise) { + promise.then(callback.bind(null, null), callback); + } }; +/* Promises API */ + /** - * @return {Object} - xml2js formatted object + * Creates a new promises API object. + * + * @param [options] the options to use: + * [api] an object to attach the API to. + * [version] 'json-ld-1.0' to output a standard JSON-LD 1.0 promises + * API, 'jsonld.js' to output the same with augmented proprietary + * methods (default: 'jsonld.js') + * + * @return the promises API object. */ -Extension.prototype.buildJsObj = function () { - var extensionObj = {}; +jsonld.promises = function(options) { + options = options || {}; + var slice = Array.prototype.slice; + var promisify = jsonld.promisify; - for (var extInstance in this.list) { - if (extInstance == "renderInformation") { - extensionObj.renderInformation = this.get(extInstance).buildJsObj(); - } - else if (extInstance == "annotation") { - extensionObj.annotation = this.get(extInstance).buildJsObj(); - } - else { - // unsupported extensions are stored as is, as xml string - // we need to parse it to build the js object - var unsupportedExtObj; - function fn (err, result) { - unsupportedExtObj = result; - }; - utils.parseString(this.get(extInstance), fn); - extensionObj[extInstance] = unsupportedExtObj[extInstance]; - } - } - return extensionObj; + // handle 'api' option as version, set defaults + var api = options.api || {}; + var version = options.version || 'jsonld.js'; + if(typeof options.api === 'string') { + if(!options.version) { + version = options.api; + } + api = {}; + } + + // The Web IDL test harness will check the number of parameters defined in + // the functions below. The number of parameters must exactly match the + // required (non-optional) parameters of the JsonLdProcessor interface as + // defined here: + // https://www.w3.org/TR/json-ld-api/#the-jsonldprocessor-interface + + api.expand = function(input) { + if(arguments.length < 1) { + throw new TypeError('Could not expand, too few arguments.'); + } + return promisify.apply(null, [jsonld.expand].concat(slice.call(arguments))); + }; + api.compact = function(input, ctx) { + if(arguments.length < 2) { + throw new TypeError('Could not compact, too few arguments.'); + } + var compact = function(input, ctx, options, callback) { + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; + // ensure only one value is returned in callback + jsonld.compact(input, ctx, options, function(err, compacted) { + callback(err, compacted); + }); + }; + return promisify.apply(null, [compact].concat(slice.call(arguments))); + }; + api.flatten = function(input) { + if(arguments.length < 1) { + throw new TypeError('Could not flatten, too few arguments.'); + } + return promisify.apply( + null, [jsonld.flatten].concat(slice.call(arguments))); + }; + api.frame = function(input, frame) { + if(arguments.length < 2) { + throw new TypeError('Could not frame, too few arguments.'); + } + return promisify.apply(null, [jsonld.frame].concat(slice.call(arguments))); + }; + api.fromRDF = function(dataset) { + if(arguments.length < 1) { + throw new TypeError('Could not convert from RDF, too few arguments.'); + } + return promisify.apply( + null, [jsonld.fromRDF].concat(slice.call(arguments))); + }; + api.toRDF = function(input) { + if(arguments.length < 1) { + throw new TypeError('Could not convert to RDF, too few arguments.'); + } + return promisify.apply(null, [jsonld.toRDF].concat(slice.call(arguments))); + }; + api.normalize = function(input) { + if(arguments.length < 1) { + throw new TypeError('Could not normalize, too few arguments.'); + } + return promisify.apply( + null, [jsonld.normalize].concat(slice.call(arguments))); + }; + + if(version === 'jsonld.js') { + api.link = function(input, ctx) { + if(arguments.length < 2) { + throw new TypeError('Could not link, too few arguments.'); + } + return promisify.apply( + null, [jsonld.link].concat(slice.call(arguments))); + }; + api.objectify = function(input) { + return promisify.apply( + null, [jsonld.objectify].concat(slice.call(arguments))); + }; + api.createNodeMap = function(input) { + return promisify.apply( + null, [jsonld.createNodeMap].concat(slice.call(arguments))); + }; + api.merge = function(input) { + return promisify.apply( + null, [jsonld.merge].concat(slice.call(arguments))); + }; + } + + try { + jsonld.Promise = global.Promise || _dereq_('es6-promise').Promise; + } catch(e) { + var f = function() { + throw new Error('Unable to find a Promise implementation.'); + }; + for(var method in api) { + api[method] = f; + } + } + + return api; }; /** - * @return {string} + * Converts a node.js async op into a promise w/boxed resolved value(s). + * + * @param op the operation to convert. + * + * @return the promise. */ -Extension.prototype.toXML = function () { - return utils.buildString({extension: this.buildJsObj()}) +jsonld.promisify = function(op) { + if(!jsonld.Promise) { + try { + jsonld.Promise = global.Promise || _dereq_('es6-promise').Promise; + } catch(e) { + throw new Error('Unable to find a Promise implementation.'); + } + } + var args = Array.prototype.slice.call(arguments, 1); + return new jsonld.Promise(function(resolve, reject) { + op.apply(null, args.concat(function(err, value) { + if(!err) { + resolve(value); + } else { + reject(err); + } + })); + }); }; -/** - * @param {String} string - * @return {Extension} - */ -Extension.fromXML = function (string) { - var extension; - function fn (err, result) { - extension = Extension.fromObj(result); - }; - utils.parseString(string, fn); - return extension; +// extend jsonld.promises w/jsonld.js methods +jsonld.promises({api: jsonld.promises}); + +/* WebIDL API */ + +function JsonLdProcessor() {} +JsonLdProcessor.prototype = jsonld.promises({version: 'json-ld-1.0'}); +JsonLdProcessor.prototype.toString = function() { + if(this instanceof JsonLdProcessor) { + return '[object JsonLdProcessor]'; + } + return '[object JsonLdProcessorPrototype]'; }; +jsonld.JsonLdProcessor = JsonLdProcessor; -/** - * @param {Object} jsObj - xml2js formatted object - * @return {Extension} - */ -Extension.fromObj = function (jsObj) { - if (typeof jsObj.extension == 'undefined') { - throw new Error("Bad XML provided, expected tagName extension, got: " + Object.keys(jsObj)[0]); - } +// IE8 has Object.defineProperty but it only +// works on DOM nodes -- so feature detection +// requires try/catch :-( +var canDefineProperty = !!Object.defineProperty; +if(canDefineProperty) { + try { + Object.defineProperty({}, 'x', {}); + } catch(e) { + canDefineProperty = false; + } +} - var extension = new Extension(); - jsObj = jsObj.extension; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return extension; - } +if(canDefineProperty) { + Object.defineProperty(JsonLdProcessor, 'prototype', { + writable: false, + enumerable: false + }); + Object.defineProperty(JsonLdProcessor.prototype, 'constructor', { + writable: true, + enumerable: false, + configurable: true, + value: JsonLdProcessor + }); +} - //var children = Object.keys(jsObj); - for (var extName in jsObj) { - //var extName = Object.keys(jsObj[i])[0]; - var extJsObj = jsObj[extName]; +// setup browser global JsonLdProcessor +if(_browser && typeof global.JsonLdProcessor === 'undefined') { + if(canDefineProperty) { + Object.defineProperty(global, 'JsonLdProcessor', { + writable: true, + enumerable: false, + configurable: true, + value: JsonLdProcessor + }); + } else { + global.JsonLdProcessor = JsonLdProcessor; + } +} - //extension.add(extInstance); - if (extName == 'renderInformation') { - var renderInformation = renderExt.RenderInformation.fromObj({renderInformation: extJsObj[0]}); - extension.add(renderInformation); - } - else if (extName == 'annotation') { - var annotation = annotExt.Annotation.fromObj({annotation: extJsObj[0]}); - extension.add(annotation); - } - else { // unsupported extension, we still store the data as is - var unsupportedExt = {}; - unsupportedExt[extName] = extJsObj[0]; // make extension serialisable - var stringExt = utils.buildString(unsupportedExt); // serialise to string - extension.add(stringExt); // save it - } - } +/* Utility API */ - return extension; -}; +// define setImmediate and nextTick +//// nextTick implementation with browser-compatible fallback //// +// from https://github.com/caolan/async/blob/master/lib/async.js -ns.Extension = Extension; -// ------- END EXTENSION ------- +// capture the global reference to guard against fakeTimer mocks +var _setImmediate = typeof setImmediate === 'function' && setImmediate; -// ------- NOTES ------- -/** - * Represents the <notes> element. - * Its single content attribute stores xhtml elements as string. - * @class - */ -var Notes = function () { - this.content = ""; +var _delay = _setImmediate ? function(fn) { + // not a direct alias (for IE10 compatibility) + _setImmediate(fn); +} : function(fn) { + setTimeout(fn, 0); }; +if(typeof process === 'object' && typeof process.nextTick === 'function') { + jsonld.nextTick = process.nextTick; +} else { + jsonld.nextTick = _delay; +} +jsonld.setImmediate = _setImmediate ? _delay : jsonld.nextTick; + /** - * Overwrite the content. - * @param {String} string + * Parses a link header. The results will be key'd by the value of "rel". + * + * Link: ; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json" + * + * Parses as: { + * 'http://www.w3.org/ns/json-ld#context': { + * target: http://json-ld.org/contexts/person.jsonld, + * type: 'application/ld+json' + * } + * } + * + * If there is more than one "rel" with the same IRI, then entries in the + * resulting map for that "rel" will be arrays. + * + * @param header the link header to parse. */ -Notes.prototype.setContent = function (string) { - this.content = string; +jsonld.parseLinkHeader = function(header) { + var rval = {}; + // split on unbracketed/unquoted commas + var entries = header.match(/(?:<[^>]*?>|"[^"]*?"|[^,])+/g); + var rLinkHeader = /\s*<([^>]*?)>\s*(?:;\s*(.*))?/; + for(var i = 0; i < entries.length; ++i) { + var match = entries[i].match(rLinkHeader); + if(!match) { + continue; + } + var result = {target: match[1]}; + var params = match[2]; + var rParams = /(.*?)=(?:(?:"([^"]*?)")|([^"]*?))\s*(?:(?:;\s*)|$)/g; + while(match = rParams.exec(params)) { + result[match[1]] = (match[2] === undefined) ? match[3] : match[2]; + } + var rel = result['rel'] || ''; + if(_isArray(rval[rel])) { + rval[rel].push(result); + } else if(rel in rval) { + rval[rel] = [rval[rel], result]; + } else { + rval[rel] = result; + } + } + return rval; }; /** - * @param {String} string + * Creates a simple queue for requesting documents. */ -Notes.prototype.appendContent = function (string) { - this.content += string; +jsonld.RequestQueue = function() { + this._requests = {}; +}; +jsonld.RequestQueue.prototype.wrapLoader = function(loader) { + this._loader = loader; + this._usePromise = (loader.length === 1); + return this.add.bind(this); }; +jsonld.RequestQueue.prototype.add = function(url, callback) { + var self = this; -/** - * @return {Object} - xml2js formatted object - */ -Notes.prototype.buildJsObj = function () { + // callback must be given if not using promises + if(!callback && !self._usePromise) { + throw new Error('callback must be specified.'); + } - var parsedContent; - utils.parseString(this.content, function (err, result) { - parsedContent = result; + // Promise-based API + if(self._usePromise) { + return new jsonld.Promise(function(resolve, reject) { + var load = self._requests[url]; + if(!load) { + // load URL then remove from queue + load = self._requests[url] = self._loader(url) + .then(function(remoteDoc) { + delete self._requests[url]; + return remoteDoc; + }).catch(function(err) { + delete self._requests[url]; + throw err; + }); + } + // resolve/reject promise once URL has been loaded + load.then(function(remoteDoc) { + resolve(remoteDoc); + }).catch(function(err) { + reject(err); + }); }); + } - return parsedContent; + // callback-based API + if(url in self._requests) { + self._requests[url].push(callback); + } else { + self._requests[url] = [callback]; + self._loader(url, function(err, remoteDoc) { + var callbacks = self._requests[url]; + delete self._requests[url]; + for(var i = 0; i < callbacks.length; ++i) { + callbacks[i](err, remoteDoc); + } + }); + } }; /** - * @return {string} + * Creates a simple document cache that retains documents for a short + * period of time. + * + * FIXME: Implement simple HTTP caching instead. + * + * @param size the maximum size of the cache. */ -Notes.prototype.toXML = function () { - return utils.buildString({notes: this.buildJsObj()}) +jsonld.DocumentCache = function(size) { + this.order = []; + this.cache = {}; + this.size = size || 50; + this.expires = 30 * 1000; +}; +jsonld.DocumentCache.prototype.get = function(url) { + if(url in this.cache) { + var entry = this.cache[url]; + if(entry.expires >= +new Date()) { + return entry.ctx; + } + delete this.cache[url]; + this.order.splice(this.order.indexOf(url), 1); + } + return null; +}; +jsonld.DocumentCache.prototype.set = function(url, ctx) { + if(this.order.length === this.size) { + delete this.cache[this.order.shift()]; + } + this.order.push(url); + this.cache[url] = {ctx: ctx, expires: (+new Date() + this.expires)}; }; /** - * @param {String} string - * @return {Notes} + * Creates an active context cache. + * + * @param size the maximum size of the cache. */ -Notes.fromXML = function (string) { - var notes; - function fn (err, result) { - notes = Notes.fromObj(result); - }; - utils.parseString(string, fn); - return notes; +jsonld.ActiveContextCache = function(size) { + this.order = []; + this.cache = {}; + this.size = size || 100; +}; +jsonld.ActiveContextCache.prototype.get = function(activeCtx, localCtx) { + var key1 = JSON.stringify(activeCtx); + var key2 = JSON.stringify(localCtx); + var level1 = this.cache[key1]; + if(level1 && key2 in level1) { + return level1[key2]; + } + return null; +}; +jsonld.ActiveContextCache.prototype.set = function( + activeCtx, localCtx, result) { + if(this.order.length === this.size) { + var entry = this.order.shift(); + delete this.cache[entry.activeCtx][entry.localCtx]; + } + var key1 = JSON.stringify(activeCtx); + var key2 = JSON.stringify(localCtx); + this.order.push({activeCtx: key1, localCtx: key2}); + if(!(key1 in this.cache)) { + this.cache[key1] = {}; + } + this.cache[key1][key2] = _clone(result); }; /** - * @param {Object} jsObj - xml2js formatted object - * @return {Notes} + * Default JSON-LD cache. */ -Notes.fromObj = function (jsObj) { - if (typeof jsObj.notes == 'undefined') { - throw new Error("Bad XML provided, expected tagName notes, got: " + Object.keys(jsObj)[0]); - } - - var notes = new Notes(); - jsObj = jsObj.notes; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return notes; - } - - var stringExt = utils.buildString({notes: jsObj}); // serialise to string - // xml2js does weird things when you just want to serialize the content - // need to include the root to get it properly, and then remove it in the result string. - stringExt = stringExt.replace('', ''); - stringExt = stringExt.replace('', ''); - notes.content = stringExt; // save it - - return notes; +jsonld.cache = { + activeCtx: new jsonld.ActiveContextCache() }; -ns.Notes = Notes; -// ------- END NOTES ------- - -// ------- GLYPH ------- /** - * Represents the <glyph> element. - * @class Glyph - * @extends SBGNBase - * @param {Object} params - * @param {string=} params.id - * @param {string=} params.class_ - * @param {string=} params.compartmentRef - * @param {string|number=} params.compartmentOrder - * @param {string=} params.mapRef - * @param {string=} params.tagRef - * @param {string=} params.orientation - * @param {Label=} params.label - * @param {Bbox=} params.bbox - * @param {StateType=} params.state - * @param {CloneType=} params.clone - * @param {Callout=} params.callout - * @param {EntityType=} params.entity - * @param {Glyph[]=} params.glyphMembers - * @param {Port[]=} params.ports + * Document loaders. */ -var Glyph = function (params) { - ns.SBGNBase.call(this, params); - var params = checkParams(params, ['id', 'class_', 'compartmentRef', 'compartmentOrder', 'mapRef', - 'tagRef', 'orientation', 'label', 'bbox', 'glyphMembers', 'ports', 'state', 'clone', 'entity', 'callout']); - this.id = params.id; - this.class_ = params.class_; - this.compartmentRef = params.compartmentRef; - this.compartmentOrder = parseFloat(params.compartmentOrder); - this.mapRef = params.mapRef; - this.tagRef = params.tagRef; - this.orientation = params.orientation; - - // children - this.label = params.label; - this.state = params.state; - this.clone = params.clone; - this.callout = params.callout; - this.entity = params.entity; - this.bbox = params.bbox; - this.glyphMembers = params.glyphMembers || []; // case of complex, can have arbitrary list of nested glyphs - this.ports = params.ports || []; -}; - -Glyph.prototype = Object.create(ns.SBGNBase.prototype); -Glyph.prototype.constructor = Glyph; +jsonld.documentLoaders = {}; /** - * @param {Label} label + * Creates a built-in jquery document loader. + * + * @param $ the jquery instance to use. + * @param options the options to use: + * secure: require all URLs to use HTTPS. + * usePromise: true to use a promises API, false for a + * callback-continuation-style API; defaults to true if Promise + * is globally defined, false if not. + * + * @return the jquery document loader. */ -Glyph.prototype.setLabel = function (label) { - this.label = label; -}; +jsonld.documentLoaders.jquery = function($, options) { + options = options || {}; + var queue = new jsonld.RequestQueue(); -/** - * @param {StateType} state - */ -Glyph.prototype.setState = function (state) { - this.state = state; + // use option or, by default, use Promise when its defined + var usePromise = ('usePromise' in options ? + options.usePromise : (typeof Promise !== 'undefined')); + if(usePromise) { + return queue.wrapLoader(function(url) { + return jsonld.promisify(loader, url); + }); + } + return queue.wrapLoader(loader); + + function loader(url, callback) { + if(url.indexOf('http:') !== 0 && url.indexOf('https:') !== 0) { + return callback(new JsonLdError( + 'URL could not be dereferenced; only "http" and "https" URLs are ' + + 'supported.', + 'jsonld.InvalidUrl', {code: 'loading document failed', url: url}), + {contextUrl: null, documentUrl: url, document: null}); + } + if(options.secure && url.indexOf('https') !== 0) { + return callback(new JsonLdError( + 'URL could not be dereferenced; secure mode is enabled and ' + + 'the URL\'s scheme is not "https".', + 'jsonld.InvalidUrl', {code: 'loading document failed', url: url}), + {contextUrl: null, documentUrl: url, document: null}); + } + $.ajax({ + url: url, + accepts: { + json: 'application/ld+json, application/json' + }, + // ensure Accept header is very specific for JSON-LD/JSON + headers: { + 'Accept': 'application/ld+json, application/json' + }, + dataType: 'json', + crossDomain: true, + success: function(data, textStatus, jqXHR) { + var doc = {contextUrl: null, documentUrl: url, document: data}; + + // handle Link Header + var contentType = jqXHR.getResponseHeader('Content-Type'); + var linkHeader = jqXHR.getResponseHeader('Link'); + if(linkHeader && contentType !== 'application/ld+json') { + // only 1 related link header permitted + linkHeader = jsonld.parseLinkHeader(linkHeader)[LINK_HEADER_REL]; + if(_isArray(linkHeader)) { + return callback(new JsonLdError( + 'URL could not be dereferenced, it has more than one ' + + 'associated HTTP Link Header.', + 'jsonld.InvalidUrl', + {code: 'multiple context link headers', url: url}), doc); + } + if(linkHeader) { + doc.contextUrl = linkHeader.target; + } + } + + callback(null, doc); + }, + error: function(jqXHR, textStatus, err) { + callback(new JsonLdError( + 'URL could not be dereferenced, an error occurred.', + 'jsonld.LoadDocumentError', + {code: 'loading document failed', url: url, cause: err}), + {contextUrl: null, documentUrl: url, document: null}); + } + }); + } }; /** - * @param {Bbox} bbox + * Creates a built-in node document loader. + * + * @param options the options to use: + * secure: require all URLs to use HTTPS. + * strictSSL: true to require SSL certificates to be valid, + * false not to (default: true). + * maxRedirects: the maximum number of redirects to permit, none by + * default. + * request: the object which will make the request, default is + * provided by `https://www.npmjs.com/package/request`. + * headers: an array of headers which will be passed as request + * headers for the requested document. Accept is not allowed. + * usePromise: true to use a promises API, false for a + * callback-continuation-style API; false by default. + * + * @return the node document loader. */ -Glyph.prototype.setBbox = function (bbox) { - this.bbox = bbox; +jsonld.documentLoaders.node = function(options) { + options = options || {}; + var strictSSL = ('strictSSL' in options) ? options.strictSSL : true; + var maxRedirects = ('maxRedirects' in options) ? options.maxRedirects : -1; + var request = ('request' in options) ? options.request : _dereq_('request'); + var acceptHeader = 'application/ld+json, application/json'; + var http = _dereq_('http'); + // TODO: disable cache until HTTP caching implemented + //var cache = new jsonld.DocumentCache(); + + var queue = new jsonld.RequestQueue(); + if(options.usePromise) { + return queue.wrapLoader(function(url) { + return jsonld.promisify(loadDocument, url, []); + }); + } + var headers = options.headers || {}; + if('Accept' in headers || 'accept' in headers) { + throw new RangeError( + 'Accept header may not be specified as an option; only "' + + acceptHeader + '" is supported.'); + } + return queue.wrapLoader(function(url, callback) { + loadDocument(url, [], callback); + }); + + function loadDocument(url, redirects, callback) { + if(url.indexOf('http:') !== 0 && url.indexOf('https:') !== 0) { + return callback(new JsonLdError( + 'URL could not be dereferenced; only "http" and "https" URLs are ' + + 'supported.', + 'jsonld.InvalidUrl', {code: 'loading document failed', url: url}), + {contextUrl: null, documentUrl: url, document: null}); + } + if(options.secure && url.indexOf('https') !== 0) { + return callback(new JsonLdError( + 'URL could not be dereferenced; secure mode is enabled and ' + + 'the URL\'s scheme is not "https".', + 'jsonld.InvalidUrl', {code: 'loading document failed', url: url}), + {contextUrl: null, documentUrl: url, document: null}); + } + // TODO: disable cache until HTTP caching implemented + var doc = null;//cache.get(url); + if(doc !== null) { + return callback(null, doc); + } + var headers = {'Accept': acceptHeader}; + for(var k in options.headers) { headers[k] = options.headers[k]; } + request({ + url: url, + headers: headers, + strictSSL: strictSSL, + followRedirect: false + }, handleResponse); + + function handleResponse(err, res, body) { + doc = {contextUrl: null, documentUrl: url, document: body || null}; + + // handle error + if(err) { + return callback(new JsonLdError( + 'URL could not be dereferenced, an error occurred.', + 'jsonld.LoadDocumentError', + {code: 'loading document failed', url: url, cause: err}), doc); + } + var statusText = http.STATUS_CODES[res.statusCode]; + if(res.statusCode >= 400) { + return callback(new JsonLdError( + 'URL could not be dereferenced: ' + statusText, + 'jsonld.InvalidUrl', { + code: 'loading document failed', + url: url, + httpStatusCode: res.statusCode + }), doc); + } + + // handle Link Header + if(res.headers.link && + res.headers['content-type'] !== 'application/ld+json') { + // only 1 related link header permitted + var linkHeader = jsonld.parseLinkHeader( + res.headers.link)[LINK_HEADER_REL]; + if(_isArray(linkHeader)) { + return callback(new JsonLdError( + 'URL could not be dereferenced, it has more than one associated ' + + 'HTTP Link Header.', + 'jsonld.InvalidUrl', + {code: 'multiple context link headers', url: url}), doc); + } + if(linkHeader) { + doc.contextUrl = linkHeader.target; + } + } + + // handle redirect + if(res.statusCode >= 300 && res.statusCode < 400 && + res.headers.location) { + if(redirects.length === maxRedirects) { + return callback(new JsonLdError( + 'URL could not be dereferenced; there were too many redirects.', + 'jsonld.TooManyRedirects', { + code: 'loading document failed', + url: url, + httpStatusCode: res.statusCode, + redirects: redirects + }), doc); + } + if(redirects.indexOf(url) !== -1) { + return callback(new JsonLdError( + 'URL could not be dereferenced; infinite redirection was detected.', + 'jsonld.InfiniteRedirectDetected', { + code: 'recursive context inclusion', + url: url, + httpStatusCode: res.statusCode, + redirects: redirects + }), doc); + } + redirects.push(url); + return loadDocument(res.headers.location, redirects, callback); + } + // cache for each redirected URL + redirects.push(url); + // TODO: disable cache until HTTP caching implemented + /*for(var i = 0; i < redirects.length; ++i) { + cache.set( + redirects[i], + {contextUrl: null, documentUrl: redirects[i], document: body}); + }*/ + callback(err, doc); + } + } }; /** - * @param {CloneType} clone + * Creates a built-in XMLHttpRequest document loader. + * + * @param options the options to use: + * secure: require all URLs to use HTTPS. + * usePromise: true to use a promises API, false for a + * callback-continuation-style API; defaults to true if Promise + * is globally defined, false if not. + * [xhr]: the XMLHttpRequest API to use. + * + * @return the XMLHttpRequest document loader. */ -Glyph.prototype.setClone = function (clone) { - this.clone = clone; +jsonld.documentLoaders.xhr = function(options) { + options = options || {}; + var rlink = /(^|(\r\n))link:/i; + var queue = new jsonld.RequestQueue(); + + // use option or, by default, use Promise when its defined + var usePromise = ('usePromise' in options ? + options.usePromise : (typeof Promise !== 'undefined')); + if(usePromise) { + return queue.wrapLoader(function(url) { + return jsonld.promisify(loader, url); + }); + } + return queue.wrapLoader(loader); + + function loader(url, callback) { + if(url.indexOf('http:') !== 0 && url.indexOf('https:') !== 0) { + return callback(new JsonLdError( + 'URL could not be dereferenced; only "http" and "https" URLs are ' + + 'supported.', + 'jsonld.InvalidUrl', {code: 'loading document failed', url: url}), + {contextUrl: null, documentUrl: url, document: null}); + } + if(options.secure && url.indexOf('https') !== 0) { + return callback(new JsonLdError( + 'URL could not be dereferenced; secure mode is enabled and ' + + 'the URL\'s scheme is not "https".', + 'jsonld.InvalidUrl', {code: 'loading document failed', url: url}), + {contextUrl: null, documentUrl: url, document: null}); + } + var xhr = options.xhr || XMLHttpRequest; + var req = new xhr(); + req.onload = function() { + if(req.status >= 400) { + return callback(new JsonLdError( + 'URL could not be dereferenced: ' + req.statusText, + 'jsonld.LoadDocumentError', { + code: 'loading document failed', + url: url, + httpStatusCode: req.status + }), {contextUrl: null, documentUrl: url, document: null}); + } + + var doc = {contextUrl: null, documentUrl: url, document: req.response}; + + // handle Link Header (avoid unsafe header warning by existence testing) + var contentType = req.getResponseHeader('Content-Type'); + var linkHeader; + if(rlink.test(req.getAllResponseHeaders())) { + linkHeader = req.getResponseHeader('Link'); + } + if(linkHeader && contentType !== 'application/ld+json') { + // only 1 related link header permitted + linkHeader = jsonld.parseLinkHeader(linkHeader)[LINK_HEADER_REL]; + if(_isArray(linkHeader)) { + return callback(new JsonLdError( + 'URL could not be dereferenced, it has more than one ' + + 'associated HTTP Link Header.', + 'jsonld.InvalidUrl', + {code: 'multiple context link headers', url: url}), doc); + } + if(linkHeader) { + doc.contextUrl = linkHeader.target; + } + } + + callback(null, doc); + }; + req.onerror = function() { + callback(new JsonLdError( + 'URL could not be dereferenced, an error occurred.', + 'jsonld.LoadDocumentError', + {code: 'loading document failed', url: url}), + {contextUrl: null, documentUrl: url, document: null}); + }; + req.open('GET', url, true); + req.setRequestHeader('Accept', 'application/ld+json, application/json'); + req.send(); + } }; /** - * @param {Callout} callout + * Assigns the default document loader for external document URLs to a built-in + * default. Supported types currently include: 'jquery' and 'node'. + * + * To use the jquery document loader, the first parameter must be a reference + * to the main jquery object. + * + * @param type the type to set. + * @param [params] the parameters required to use the document loader. */ -Glyph.prototype.setCallout = function (callout) { - this.callout = callout; +jsonld.useDocumentLoader = function(type) { + if(!(type in jsonld.documentLoaders)) { + throw new JsonLdError( + 'Unknown document loader type: "' + type + '"', + 'jsonld.UnknownDocumentLoader', + {type: type}); + } + + // set document loader + jsonld.documentLoader = jsonld.documentLoaders[type].apply( + jsonld, Array.prototype.slice.call(arguments, 1)); }; /** - * @param {EntityType} entity + * Processes a local context, resolving any URLs as necessary, and returns a + * new active context in its callback. + * + * @param activeCtx the current active context. + * @param localCtx the local context to process. + * @param [options] the options to use: + * [documentLoader(url, callback(err, remoteDoc))] the document loader. + * @param callback(err, ctx) called once the operation completes. */ -Glyph.prototype.setEntity = function (entity) { - this.entity = entity; +jsonld.processContext = function(activeCtx, localCtx) { + // get arguments + var options = {}; + var callbackArg = 2; + if(arguments.length > 3) { + options = arguments[2] || {}; + callbackArg += 1; + } + var callback = arguments[callbackArg]; + + // set default options + if(!('base' in options)) { + options.base = ''; + } + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } + + // return initial context early for null context + if(localCtx === null) { + return callback(null, _getInitialContext(options)); + } + + // retrieve URLs in localCtx + localCtx = _clone(localCtx); + if(!(_isObject(localCtx) && '@context' in localCtx)) { + localCtx = {'@context': localCtx}; + } + _retrieveContextUrls(localCtx, options, function(err, ctx) { + if(err) { + return callback(err); + } + try { + // process context + ctx = new Processor().processContext(activeCtx, ctx, options); + } catch(ex) { + return callback(ex); + } + callback(null, ctx); + }); }; /** - * @param {Glyph} glyphMember + * Returns true if the given subject has the given property. + * + * @param subject the subject to check. + * @param property the property to look for. + * + * @return true if the subject has the given property, false if not. */ -Glyph.prototype.addGlyphMember = function (glyphMember) { - this.glyphMembers.push(glyphMember); +jsonld.hasProperty = function(subject, property) { + var rval = false; + if(property in subject) { + var value = subject[property]; + rval = (!_isArray(value) || value.length > 0); + } + return rval; }; /** - * @param {Port} port + * Determines if the given value is a property of the given subject. + * + * @param subject the subject to check. + * @param property the property to check. + * @param value the value to check. + * + * @return true if the value exists, false if not. */ -Glyph.prototype.addPort = function (port) { - this.ports.push(port); +jsonld.hasValue = function(subject, property, value) { + var rval = false; + if(jsonld.hasProperty(subject, property)) { + var val = subject[property]; + var isList = _isList(val); + if(_isArray(val) || isList) { + if(isList) { + val = val['@list']; + } + for(var i = 0; i < val.length; ++i) { + if(jsonld.compareValues(value, val[i])) { + rval = true; + break; + } + } + } else if(!_isArray(value)) { + // avoid matching the set of values with an array value parameter + rval = jsonld.compareValues(value, val); + } + } + return rval; }; /** - * @return {Object} - xml2js formatted object + * Adds a value to a subject. If the value is an array, all values in the + * array will be added. + * + * @param subject the subject to add the value to. + * @param property the property that relates the value to the subject. + * @param value the value to add. + * @param [options] the options to use: + * [propertyIsArray] true if the property is always an array, false + * if not (default: false). + * [allowDuplicate] true to allow duplicates, false not to (uses a + * simple shallow comparison of subject ID or value) (default: true). */ -Glyph.prototype.buildJsObj = function () { - var glyphObj = {}; +jsonld.addValue = function(subject, property, value, options) { + options = options || {}; + if(!('propertyIsArray' in options)) { + options.propertyIsArray = false; + } + if(!('allowDuplicate' in options)) { + options.allowDuplicate = true; + } - // attributes - var attributes = {}; - if(this.id != null) { - attributes.id = this.id; - } - if(this.class_ != null) { - attributes.class = this.class_; - } - if(this.compartmentRef != null) { - attributes.compartmentRef = this.compartmentRef; - } - if(!isNaN(this.compartmentOrder)) { - attributes.compartmentOrder = this.compartmentOrder; - } - if(this.mapRef != null) { - attributes.mapRef = this.mapRef; - } - if(this.tagRef != null) { - attributes.tagRef = this.tagRef; - } - if(this.orientation != null) { - attributes.orientation = this.orientation; - } - utils.addAttributes(glyphObj, attributes); + if(_isArray(value)) { + if(value.length === 0 && options.propertyIsArray && + !(property in subject)) { + subject[property] = []; + } + for(var i = 0; i < value.length; ++i) { + jsonld.addValue(subject, property, value[i], options); + } + } else if(property in subject) { + // check if subject already has value if duplicates not allowed + var hasValue = (!options.allowDuplicate && + jsonld.hasValue(subject, property, value)); - // children - this.baseToJsObj(glyphObj); - if(this.label != null) { - glyphObj.label = this.label.buildJsObj(); - } - if(this.state != null) { - glyphObj.state = this.state.buildJsObj(); - } - if(this.clone != null) { - glyphObj.clone = this.clone.buildJsObj(); - } - if(this.callout != null) { - glyphObj.callout = this.callout.buildJsObj(); - } - if(this.entity != null) { - glyphObj.entity = this.entity.buildJsObj(); - } - if(this.bbox != null) { - glyphObj.bbox = this.bbox.buildJsObj(); - } - for(var i=0; i < this.glyphMembers.length; i++) { - if (i==0) { - glyphObj.glyph = []; - } - glyphObj.glyph.push(this.glyphMembers[i].buildJsObj()); - } - for(var i=0; i < this.ports.length; i++) { - if (i==0) { - glyphObj.port = []; - } - glyphObj.port.push(this.ports[i].buildJsObj()); - } - return glyphObj; -}; + // make property an array if value not present or always an array + if(!_isArray(subject[property]) && + (!hasValue || options.propertyIsArray)) { + subject[property] = [subject[property]]; + } -/** - * @return {string} - */ -Glyph.prototype.toXML = function () { - return utils.buildString({glyph: this.buildJsObj()}) + // add new value + if(!hasValue) { + subject[property].push(value); + } + } else { + // add new value as set or single value + subject[property] = options.propertyIsArray ? [value] : value; + } }; /** - * @param {String} string - * @return {Glyph} + * Gets all of the values for a subject's property as an array. + * + * @param subject the subject. + * @param property the property. + * + * @return all of the values for a subject's property as an array. */ -Glyph.fromXML = function (string) { - var glyph; - function fn (err, result) { - glyph = Glyph.fromObj(result); - }; - utils.parseString(string, fn); - return glyph; +jsonld.getValues = function(subject, property) { + var rval = subject[property] || []; + if(!_isArray(rval)) { + rval = [rval]; + } + return rval; }; /** - * @param {Object} jsObj - xml2js formatted object - * @return {Glyph} + * Removes a property from a subject. + * + * @param subject the subject. + * @param property the property. */ -Glyph.fromObj = function (jsObj) { - if (typeof jsObj.glyph == 'undefined') { - throw new Error("Bad XML provided, expected tagName glyph, got: " + Object.keys(jsObj)[0]); - } - - var glyph = new ns.Glyph(); - jsObj = jsObj.glyph; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return glyph; - } - - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - glyph.id = attributes.id || null; - glyph.class_ = attributes.class || null; - glyph.compartmentRef = attributes.compartmentRef || null; - glyph.compartmentOrder = parseFloat(attributes.compartmentOrder); - glyph.mapRef = attributes.mapRef || null; - glyph.tagRef = attributes.tagRef || null; - glyph.orientation = attributes.orientation || null; - } - - // children - if(jsObj.label) { - var label = ns.Label.fromObj({label: jsObj.label[0]}); - glyph.setLabel(label); - } - if(jsObj.state) { - var state = ns.StateType.fromObj({state: jsObj.state[0]}); - glyph.setState(state); - } - if(jsObj.clone) { - var clone = ns.CloneType.fromObj({clone: jsObj.clone[0]}); - glyph.setClone(clone); - } - if(jsObj.callout) { - var callout = ns.Callout.fromObj({callout: jsObj.callout[0]}); - glyph.setCallout(callout); - } - if(jsObj.entity) { - var entity = ns.EntityType.fromObj({entity: jsObj.entity[0]}); - glyph.setEntity(entity); - } - if(jsObj.bbox) { - var bbox = ns.Bbox.fromObj({bbox: jsObj.bbox[0]}); - glyph.setBbox(bbox); - } - - if(jsObj.glyph) { - var glyphs = jsObj.glyph; - for (var i=0; i < glyphs.length; i++) { - var glyphMember = ns.Glyph.fromObj({glyph: glyphs[i]}); - glyph.addGlyphMember(glyphMember); - } - } - if(jsObj.port) { - var ports = jsObj.port; - for (var i=0; i < ports.length; i++) { - var port = ns.Port.fromObj({port: ports[i]}); - glyph.addPort(port); - } - } - - glyph.baseFromObj(jsObj); - return glyph; +jsonld.removeProperty = function(subject, property) { + delete subject[property]; }; -ns.Glyph = Glyph; -// ------- END GLYPH ------- - -// ------- LABEL ------- /** - * Represents the <label> element. - * @class Label - * @extends SBGNBase - * @param {Object} params - * @param {string=} params.text - * @param {Bbox=} params.bbox + * Removes a value from a subject. + * + * @param subject the subject. + * @param property the property that relates the value to the subject. + * @param value the value to remove. + * @param [options] the options to use: + * [propertyIsArray] true if the property is always an array, false + * if not (default: false). */ -var Label = function (params) { - ns.SBGNBase.call(this, params); - var params = checkParams(params, ['text', 'bbox']); - this.text = params.text; - this.bbox = params.bbox; -}; +jsonld.removeValue = function(subject, property, value, options) { + options = options || {}; + if(!('propertyIsArray' in options)) { + options.propertyIsArray = false; + } -Label.prototype = Object.create(ns.SBGNBase.prototype); -Label.prototype.constructor = ns.Label; + // filter out value + var values = jsonld.getValues(subject, property).filter(function(e) { + return !jsonld.compareValues(e, value); + }); -/** - * @param {Bbox} bbox - */ -Label.prototype.setBbox = function (bbox) { - this.bbox = bbox; + if(values.length === 0) { + jsonld.removeProperty(subject, property); + } else if(values.length === 1 && !options.propertyIsArray) { + subject[property] = values[0]; + } else { + subject[property] = values; + } }; /** - * @return {Object} - xml2js formatted object + * Compares two JSON-LD values for equality. Two JSON-LD values will be + * considered equal if: + * + * 1. They are both primitives of the same type and value. + * 2. They are both @values with the same @value, @type, @language, + * and @index, OR + * 3. They both have @ids they are the same. + * + * @param v1 the first value. + * @param v2 the second value. + * + * @return true if v1 and v2 are considered equal, false if not. */ -Label.prototype.buildJsObj = function () { - var labelObj = {}; - - // attributes - var attributes = {}; - if(this.text != null) { - attributes.text = this.text; - } - else { // text is a required attribute - attributes.text = ""; - } - // ensure encoding of line breaks is always respected - //attributes.text = attributes.text.replace('\n', '\n'); //' '); - utils.addAttributes(labelObj, attributes); +jsonld.compareValues = function(v1, v2) { + // 1. equal primitives + if(v1 === v2) { + return true; + } - this.baseToJsObj(labelObj); - if(this.bbox != null) { - labelObj.bbox = this.bbox.buildJsObj(); - } - return labelObj; -}; + // 2. equal @values + if(_isValue(v1) && _isValue(v2) && + v1['@value'] === v2['@value'] && + v1['@type'] === v2['@type'] && + v1['@language'] === v2['@language'] && + v1['@index'] === v2['@index']) { + return true; + } -/** - * @return {string} - */ -Label.prototype.toXML = function () { - return utils.buildString({label: this.buildJsObj()}) -}; + // 3. equal @ids + if(_isObject(v1) && ('@id' in v1) && _isObject(v2) && ('@id' in v2)) { + return v1['@id'] === v2['@id']; + } -/** - * @param {String} string - * @return {Label} - */ -Label.fromXML = function (string) { - var label; - function fn (err, result) { - label = Label.fromObj(result); - }; - utils.parseString(string, fn); - return label; + return false; }; /** - * @param {Object} jsObj - xml2js formatted object - * @return {Label} + * Gets the value for the given active context key and type, null if none is + * set. + * + * @param ctx the active context. + * @param key the context key. + * @param [type] the type of value to get (eg: '@id', '@type'), if not + * specified gets the entire entry for a key, null if not found. + * + * @return the value. */ -Label.fromObj = function (jsObj) { - if (typeof jsObj.label == 'undefined') { - throw new Error("Bad XML provided, expected tagName label, got: " + Object.keys(jsObj)[0]); - } +jsonld.getContextValue = function(ctx, key, type) { + var rval = null; - var label = new ns.Label(); - jsObj = jsObj.label; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return label; - } + // return null for invalid key + if(key === null) { + return rval; + } - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - label.text = attributes.text || null; - } + // get default language + if(type === '@language' && (type in ctx)) { + rval = ctx[type]; + } - if(jsObj.bbox) { - var bbox = ns.Bbox.fromObj({bbox: jsObj.bbox[0]}); - label.setBbox(bbox); - } - label.baseFromObj(jsObj); - return label; -}; + // get specific entry information + if(ctx.mappings[key]) { + var entry = ctx.mappings[key]; -ns.Label = Label; -// ------- END LABEL ------- + if(_isUndefined(type)) { + // return whole entry + rval = entry; + } else if(type in entry) { + // return entry value for type + rval = entry[type]; + } + } -// ------- BBOX ------- -/** - * Represents the <bbox> element. - * @class Bbox - * @extends SBGNBase - * @param {Object} params - * @param {string|number=} params.x - * @param {string|number=} params.y - * @param {string|number=} params.w - * @param {string|number=} params.h - */ -var Bbox = function (params) { - ns.SBGNBase.call(this, params); - var params = checkParams(params, ['x', 'y', 'w', 'h']); - this.x = parseFloat(params.x); - this.y = parseFloat(params.y); - this.w = parseFloat(params.w); - this.h = parseFloat(params.h); + return rval; }; -Bbox.prototype = Object.create(ns.SBGNBase.prototype); -Bbox.prototype.constructor = ns.Bbox; +/** Registered RDF dataset parsers hashed by content-type. */ +var _rdfParsers = {}; /** - * @return {Object} - xml2js formatted object + * Registers an RDF dataset parser by content-type, for use with + * jsonld.fromRDF. An RDF dataset parser will always be given two parameters, + * a string of input and a callback. An RDF dataset parser can be synchronous + * or asynchronous. + * + * If the parser function returns undefined or null then it will be assumed to + * be asynchronous w/a continuation-passing style and the callback parameter + * given to the parser MUST be invoked. + * + * If it returns a Promise, then it will be assumed to be asynchronous, but the + * callback parameter MUST NOT be invoked. It should instead be ignored. + * + * If it returns an RDF dataset, it will be assumed to be synchronous and the + * callback parameter MUST NOT be invoked. It should instead be ignored. + * + * @param contentType the content-type for the parser. + * @param parser(input, callback(err, dataset)) the parser function (takes a + * string as a parameter and either returns null/undefined and uses + * the given callback, returns a Promise, or returns an RDF dataset). */ -Bbox.prototype.buildJsObj = function () { - var bboxObj = {}; - - // attributes - var attributes = {}; - if(!isNaN(this.x)) { - attributes.x = this.x; - } - if(!isNaN(this.y)) { - attributes.y = this.y; - } - if(!isNaN(this.w)) { - attributes.w = this.w; - } - if(!isNaN(this.h)) { - attributes.h = this.h; - } - utils.addAttributes(bboxObj, attributes); - this.baseToJsObj(bboxObj); - return bboxObj; +jsonld.registerRDFParser = function(contentType, parser) { + _rdfParsers[contentType] = parser; }; /** - * @return {string} + * Unregisters an RDF dataset parser by content-type. + * + * @param contentType the content-type for the parser. */ -Bbox.prototype.toXML = function () { - return utils.buildString({bbox: this.buildJsObj()}) +jsonld.unregisterRDFParser = function(contentType) { + delete _rdfParsers[contentType]; }; -/** - * @param {String} string - * @return {Bbox} - */ -Bbox.fromXML = function (string) { - var bbox; - function fn (err, result) { - bbox = Bbox.fromObj(result); +if(_nodejs) { + // needed for serialization of XML literals + if(typeof XMLSerializer === 'undefined') { + var XMLSerializer = null; + } + if(typeof Node === 'undefined') { + var Node = { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE:12 }; - utils.parseString(string, fn); - return bbox; -}; - -/** - * @param {Object} jsObj - xml2js formatted object - * @return {Bbox} - */ -Bbox.fromObj = function (jsObj) { - if (typeof jsObj.bbox == 'undefined') { - throw new Error("Bad XML provided, expected tagName bbox, got: " + Object.keys(jsObj)[0]); - } + } +} - var bbox = new ns.Bbox(); - jsObj = jsObj.bbox; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return bbox; - } +// constants +var XSD_BOOLEAN = 'http://www.w3.org/2001/XMLSchema#boolean'; +var XSD_DOUBLE = 'http://www.w3.org/2001/XMLSchema#double'; +var XSD_INTEGER = 'http://www.w3.org/2001/XMLSchema#integer'; +var XSD_STRING = 'http://www.w3.org/2001/XMLSchema#string'; - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - bbox.x = parseFloat(attributes.x); - bbox.y = parseFloat(attributes.y); - bbox.w = parseFloat(attributes.w); - bbox.h = parseFloat(attributes.h); - } - bbox.baseFromObj(jsObj); - return bbox; -}; +var RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; +var RDF_LIST = RDF + 'List'; +var RDF_FIRST = RDF + 'first'; +var RDF_REST = RDF + 'rest'; +var RDF_NIL = RDF + 'nil'; +var RDF_TYPE = RDF + 'type'; +var RDF_PLAIN_LITERAL = RDF + 'PlainLiteral'; +var RDF_XML_LITERAL = RDF + 'XMLLiteral'; +var RDF_OBJECT = RDF + 'object'; +var RDF_LANGSTRING = RDF + 'langString'; -ns.Bbox = Bbox; -// ------- END BBOX ------- +var LINK_HEADER_REL = 'http://www.w3.org/ns/json-ld#context'; +var MAX_CONTEXT_URLS = 10; -// ------- STATE ------- /** - * Represents the <state> element. - * @class StateType - * @param {Object} params - * @param {string=} params.value - * @param {string=} params.variable + * A JSON-LD Error. + * + * @param msg the error message. + * @param type the error type. + * @param details the error details. */ -var StateType = function (params) { - var params = checkParams(params, ['value', 'variable']); - this.value = params.value; - this.variable = params.variable; +var JsonLdError = function(msg, type, details) { + if(_nodejs) { + Error.call(this); + Error.captureStackTrace(this, this.constructor); + } else if(typeof Error !== 'undefined') { + this.stack = (new Error()).stack; + } + this.name = type || 'jsonld.Error'; + this.message = msg || 'An unspecified JSON-LD error occurred.'; + this.details = details || {}; }; +if(_nodejs) { + _dereq_('util').inherits(JsonLdError, Error); +} else if(typeof Error !== 'undefined') { + JsonLdError.prototype = new Error(); +} /** - * @return {Object} - xml2js formatted object + * Constructs a new JSON-LD Processor. */ -StateType.prototype.buildJsObj = function () { - var stateObj = {}; - - // attributes - var attributes = {}; - if(this.value != null) { - attributes.value = this.value; - } - if(this.variable != null) { - attributes.variable = this.variable; - } - utils.addAttributes(stateObj, attributes); - return stateObj; -}; +var Processor = function() {}; /** - * @return {string} + * Recursively compacts an element using the given active context. All values + * must be in expanded form before this method is called. + * + * @param activeCtx the active context to use. + * @param activeProperty the compacted property associated with the element + * to compact, null for none. + * @param element the element to compact. + * @param options the compaction options. + * + * @return the compacted value. */ -StateType.prototype.toXML = function () { - return utils.buildString({state: this.buildJsObj()}) -}; +Processor.prototype.compact = function( + activeCtx, activeProperty, element, options) { + // recursively compact array + if(_isArray(element)) { + var rval = []; + for(var i = 0; i < element.length; ++i) { + // compact, dropping any null values + var compacted = this.compact( + activeCtx, activeProperty, element[i], options); + if(compacted !== null) { + rval.push(compacted); + } + } + if(options.compactArrays && rval.length === 1) { + // use single element if no container is specified + var container = jsonld.getContextValue( + activeCtx, activeProperty, '@container'); + if(container === null) { + rval = rval[0]; + } + } + return rval; + } -/** - * @param {String} string - * @return {StateType} - */ -StateType.fromXML = function (string) { - var state; - function fn (err, result) { - state = StateType.fromObj(result); - }; - utils.parseString(string, fn); - return state; -}; + // recursively compact object + if(_isObject(element)) { + if(options.link && '@id' in element && element['@id'] in options.link) { + // check for a linked element to reuse + var linked = options.link[element['@id']]; + for(var i = 0; i < linked.length; ++i) { + if(linked[i].expanded === element) { + return linked[i].compacted; + } + } + } -/** - * @param {Object} jsObj - xml2js formatted object - * @return {StateType} - */ -StateType.fromObj = function (jsObj) { - if (typeof jsObj.state == 'undefined') { - throw new Error("Bad XML provided, expected tagName state, got: " + Object.keys(jsObj)[0]); - } + // do value compaction on @values and subject references + if(_isValue(element) || _isSubjectReference(element)) { + var rval = _compactValue(activeCtx, activeProperty, element); + if(options.link && _isSubjectReference(element)) { + // store linked element + if(!(element['@id'] in options.link)) { + options.link[element['@id']] = []; + } + options.link[element['@id']].push({expanded: element, compacted: rval}); + } + return rval; + } - var state = new ns.StateType(); - jsObj = jsObj.state; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return state; - } + // FIXME: avoid misuse of active property as an expanded property? + var insideReverse = (activeProperty === '@reverse'); - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - state.value = attributes.value || null; - state.variable = attributes.variable || null; - } - return state; -}; + var rval = {}; -ns.StateType = StateType; -// ------- END STATE ------- + if(options.link && '@id' in element) { + // store linked element + if(!(element['@id'] in options.link)) { + options.link[element['@id']] = []; + } + options.link[element['@id']].push({expanded: element, compacted: rval}); + } -// ------- CLONE ------- -/** - * Represents the <clone> element. - * @class CloneType - * @param {Object} params - * @param {string=} params.label - */ -var CloneType = function (params) { - var params = checkParams(params, ['label']); - this.label = params.label; -}; + // process element keys in order + var keys = Object.keys(element).sort(); + for(var ki = 0; ki < keys.length; ++ki) { + var expandedProperty = keys[ki]; + var expandedValue = element[expandedProperty]; -/** - * @param {Label} label - */ -CloneType.prototype.setLabel = function (label) { - this.label = label; -}; + // compact @id and @type(s) + if(expandedProperty === '@id' || expandedProperty === '@type') { + var compactedValue; -/** - * @return {Object} - xml2js formatted object - */ -CloneType.prototype.buildJsObj = function () { - var cloneObj = {}; + // compact single @id + if(_isString(expandedValue)) { + compactedValue = _compactIri( + activeCtx, expandedValue, null, + {vocab: (expandedProperty === '@type')}); + } else { + // expanded value must be a @type array + compactedValue = []; + for(var vi = 0; vi < expandedValue.length; ++vi) { + compactedValue.push(_compactIri( + activeCtx, expandedValue[vi], null, {vocab: true})); + } + } - // children - if(this.label != null) { - cloneObj.label = this.label.buildJsObj(); - } - return cloneObj; -}; + // use keyword alias and add value + var alias = _compactIri(activeCtx, expandedProperty); + var isArray = (_isArray(compactedValue) && expandedValue.length === 0); + jsonld.addValue( + rval, alias, compactedValue, {propertyIsArray: isArray}); + continue; + } -/** - * @return {string} - */ -CloneType.prototype.toXML = function () { - return utils.buildString({clone: this.buildJsObj()}) -}; + // handle @reverse + if(expandedProperty === '@reverse') { + // recursively compact expanded value + var compactedValue = this.compact( + activeCtx, '@reverse', expandedValue, options); -/** - * @param {String} string - * @return {CloneType} - */ -CloneType.fromXML = function (string) { - var clone; - function fn (err, result) { - clone = CloneType.fromObj(result); - }; - utils.parseString(string, fn); - return clone; -}; + // handle double-reversed properties + for(var compactedProperty in compactedValue) { + if(activeCtx.mappings[compactedProperty] && + activeCtx.mappings[compactedProperty].reverse) { + var value = compactedValue[compactedProperty]; + var container = jsonld.getContextValue( + activeCtx, compactedProperty, '@container'); + var useArray = (container === '@set' || !options.compactArrays); + jsonld.addValue( + rval, compactedProperty, value, {propertyIsArray: useArray}); + delete compactedValue[compactedProperty]; + } + } -/** - * @param {Object} jsObj - xml2js formatted object - * @return {CloneType} - */ -CloneType.fromObj = function (jsObj) { - if (typeof jsObj.clone == 'undefined') { - throw new Error("Bad XML provided, expected tagName clone, got: " + Object.keys(jsObj)[0]); - } + if(Object.keys(compactedValue).length > 0) { + // use keyword alias and add value + var alias = _compactIri(activeCtx, expandedProperty); + jsonld.addValue(rval, alias, compactedValue); + } - var clone = new ns.CloneType(); - jsObj = jsObj.clone; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return clone; - } + continue; + } - // children - if(jsObj.label) { - var label = ns.Label.fromObj({label: jsObj.label[0]}); - clone.setLabel(label); - } - return clone; -}; + // handle @index property + if(expandedProperty === '@index') { + // drop @index if inside an @index container + var container = jsonld.getContextValue( + activeCtx, activeProperty, '@container'); + if(container === '@index') { + continue; + } -ns.CloneType = CloneType; -// ------- END CLONE ------- + // use keyword alias and add value + var alias = _compactIri(activeCtx, expandedProperty); + jsonld.addValue(rval, alias, expandedValue); + continue; + } -// ------- ENTITYTYPE ------- -/** - * Represents the <entity> element. - * @class EntityType - * @param {Object} params - * @param {string=} params.name - */ -var EntityType = function (params) { - var params = checkParams(params, ['name']); - this.name = params.name; -}; + // skip array processing for keywords that aren't @graph or @list + if(expandedProperty !== '@graph' && expandedProperty !== '@list' && + _isKeyword(expandedProperty)) { + // use keyword alias and add value as is + var alias = _compactIri(activeCtx, expandedProperty); + jsonld.addValue(rval, alias, expandedValue); + continue; + } -/** - * @return {Object} - xml2js formatted object - */ -EntityType.prototype.buildJsObj = function () { - var entityObj = {}; + // Note: expanded value must be an array due to expansion algorithm. - // attributes - var attributes = {}; - if(this.name != null) { - attributes.name = this.name; - } - utils.addAttributes(entityObj, attributes); - return entityObj; -}; + // preserve empty arrays + if(expandedValue.length === 0) { + var itemActiveProperty = _compactIri( + activeCtx, expandedProperty, expandedValue, {vocab: true}, + insideReverse); + jsonld.addValue( + rval, itemActiveProperty, expandedValue, {propertyIsArray: true}); + } -/** - * @return {string} - */ -EntityType.prototype.toXML = function () { - return utils.buildString({entity: this.buildJsObj()}) -}; + // recusively process array values + for(var vi = 0; vi < expandedValue.length; ++vi) { + var expandedItem = expandedValue[vi]; -/** - * @param {String} string - * @return {EntityType} - */ -EntityType.fromXML = function (string) { - var entity; - function fn (err, result) { - entity = EntityType.fromObj(result); - }; - utils.parseString(string, fn); - return entity; -}; + // compact property and get container type + var itemActiveProperty = _compactIri( + activeCtx, expandedProperty, expandedItem, {vocab: true}, + insideReverse); + var container = jsonld.getContextValue( + activeCtx, itemActiveProperty, '@container'); -/** - * @param {Object} jsObj - xml2js formatted object - * @return {EntityType} - */ -EntityType.fromObj = function (jsObj) { - if (typeof jsObj.entity == 'undefined') { - throw new Error("Bad XML provided, expected tagName entity, got: " + Object.keys(jsObj)[0]); - } + // get @list value if appropriate + var isList = _isList(expandedItem); + var list = null; + if(isList) { + list = expandedItem['@list']; + } - var entity = new ns.EntityType(); - jsObj = jsObj.entity; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return entity; - } + // recursively compact expanded item + var compactedItem = this.compact( + activeCtx, itemActiveProperty, isList ? list : expandedItem, options); - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - entity.name = attributes.name || null; - } - return entity; -}; + // handle @list + if(isList) { + // ensure @list value is an array + if(!_isArray(compactedItem)) { + compactedItem = [compactedItem]; + } -ns.EntityType = EntityType; -// ------- END ENTITYTYPE ------- + if(container !== '@list') { + // wrap using @list alias + var wrapper = {}; + wrapper[_compactIri(activeCtx, '@list')] = compactedItem; + compactedItem = wrapper; -// ------- PORT ------- -/** - * Represents the <port> element. - * @class Port - * @param {Object} params - * @param {string=} params.id - * @param {string|number=} params.x - * @param {string|number=} params.y - */ -var Port = function (params) { - ns.SBGNBase.call(this, params); - var params = checkParams(params, ['id', 'x', 'y']); - this.id = params.id; - this.x = parseFloat(params.x); - this.y = parseFloat(params.y); -}; + // include @index from expanded @list, if any + if('@index' in expandedItem) { + compactedItem[_compactIri(activeCtx, '@index')] = + expandedItem['@index']; + } + } else if(itemActiveProperty in rval) { + // can't use @list container for more than 1 list + throw new JsonLdError( + 'JSON-LD compact error; property has a "@list" @container ' + + 'rule but there is more than a single @list that matches ' + + 'the compacted term in the document. Compaction might mix ' + + 'unwanted items into the list.', + 'jsonld.SyntaxError', {code: 'compaction to list of lists'}); + } + } -Port.prototype = Object.create(ns.SBGNBase.prototype); -Port.prototype.constructor = ns.Port; + // handle language and index maps + if(container === '@language' || container === '@index') { + // get or create the map object + var mapObject; + if(itemActiveProperty in rval) { + mapObject = rval[itemActiveProperty]; + } else { + rval[itemActiveProperty] = mapObject = {}; + } -/** - * @return {Object} - xml2js formatted object - */ -Port.prototype.buildJsObj = function () { - var portObj = {}; + // if container is a language map, simplify compacted value to + // a simple string + if(container === '@language' && _isValue(compactedItem)) { + compactedItem = compactedItem['@value']; + } - // attributes - var attributes = {}; - if(this.id != null) { - attributes.id = this.id; - } - if(!isNaN(this.x)) { - attributes.x = this.x; - } - if(!isNaN(this.y)) { - attributes.y = this.y; - } - utils.addAttributes(portObj, attributes); - this.baseToJsObj(portObj); - return portObj; -}; + // add compact value to map object using key from expanded value + // based on the container type + jsonld.addValue(mapObject, expandedItem[container], compactedItem); + } else { + // use an array if: compactArrays flag is false, + // @container is @set or @list , value is an empty + // array, or key is @graph + var isArray = (!options.compactArrays || container === '@set' || + container === '@list' || + (_isArray(compactedItem) && compactedItem.length === 0) || + expandedProperty === '@list' || expandedProperty === '@graph'); -/** - * @return {string} - */ -Port.prototype.toXML = function () { - return utils.buildString({port: this.buildJsObj()}) -}; + // add compact value + jsonld.addValue( + rval, itemActiveProperty, compactedItem, + {propertyIsArray: isArray}); + } + } + } -/** - * @param {String} string - * @return {Port} - */ -Port.fromXML = function (string) { - var port; - function fn (err, result) { - port = Port.fromObj(result); - }; - utils.parseString(string, fn); - return port; + return rval; + } + + // only primitives remain which are already compact + return element; }; /** - * @param {Object} jsObj - xml2js formatted object - * @return {Port} + * Recursively expands an element using the given context. Any context in + * the element will be removed. All context URLs must have been retrieved + * before calling this method. + * + * @param activeCtx the context to use. + * @param activeProperty the property for the element, null for none. + * @param element the element to expand. + * @param options the expansion options. + * @param insideList true if the element is a list, false if not. + * + * @return the expanded value. */ -Port.fromObj = function (jsObj) { - if (typeof jsObj.port == 'undefined') { - throw new Error("Bad XML provided, expected tagName port, got: " + Object.keys(jsObj)[0]); - } +Processor.prototype.expand = function( + activeCtx, activeProperty, element, options, insideList) { + var self = this; - var port = new ns.Port(); - jsObj = jsObj.port; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return port; - } + // nothing to expand + if(element === null || element === undefined) { + return null; + } - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - port.x = parseFloat(attributes.x); - port.y = parseFloat(attributes.y); - port.id = attributes.id || null; - } - port.baseFromObj(jsObj); - return port; -}; + if(!_isArray(element) && !_isObject(element)) { + // drop free-floating scalars that are not in lists + if(!insideList && (activeProperty === null || + _expandIri(activeCtx, activeProperty, {vocab: true}) === '@graph')) { + return null; + } -ns.Port = Port; -// ------- END PORT ------- - -// ------- ARC ------- -/** - * Represents the <arc> element. - * @class Arc - * @param {Object} params - * @param {string=} params.id - * @param {string=} params.class_ - * @param {string=} params.source - * @param {string=} params.target - * @param {StartType=} params.start - * @param {EndType=} params.end - * @param {NextType=} params.nexts - * @param {Glyph[]=} params.glyphs The arc's cardinality. Possibility to have more than one glyph is left open. - */ -var Arc = function (params) { - ns.SBGNBase.call(this, params); - var params = checkParams(params, ['id', 'class_', 'source', 'target', 'start', 'end', 'nexts', 'glyphs']); - this.id = params.id; - this.class_ = params.class_; - this.source = params.source; - this.target = params.target; - - this.start = params.start; - this.end = params.end; - this.nexts = params.nexts || []; - this.glyphs = params.glyphs || []; -}; + // expand element according to value expansion rules + return _expandValue(activeCtx, activeProperty, element); + } -Arc.prototype = Object.create(ns.SBGNBase.prototype); -Arc.prototype.constructor = ns.Arc; + // recursively expand array + if(_isArray(element)) { + var rval = []; + var container = jsonld.getContextValue( + activeCtx, activeProperty, '@container'); + insideList = insideList || container === '@list'; + for(var i = 0; i < element.length; ++i) { + // expand element + var e = self.expand(activeCtx, activeProperty, element[i], options); + if(insideList && (_isArray(e) || _isList(e))) { + // lists of lists are illegal + throw new JsonLdError( + 'Invalid JSON-LD syntax; lists of lists are not permitted.', + 'jsonld.SyntaxError', {code: 'list of lists'}); + } + // drop null values + if(e !== null) { + if(_isArray(e)) { + rval = rval.concat(e); + } else { + rval.push(e); + } + } + } + return rval; + } -/** - * @param {StartType} start - */ -Arc.prototype.setStart = function (start) { - this.start = start; -}; + // recursively expand object: -/** - * @param {EndType} end - */ -Arc.prototype.setEnd = function (end) { - this.end = end; -}; + // if element has a context, process it + if('@context' in element) { + activeCtx = self.processContext(activeCtx, element['@context'], options); + } -/** - * @param {NextType} next - */ -Arc.prototype.addNext = function (next) { - this.nexts.push(next); -}; + // expand the active property + var expandedActiveProperty = _expandIri( + activeCtx, activeProperty, {vocab: true}); -/** - * @param {Glyph} glyph - */ -Arc.prototype.addGlyph = function (glyph) { - this.glyphs.push(glyph); -}; + var rval = {}; + var keys = Object.keys(element).sort(); + for(var ki = 0; ki < keys.length; ++ki) { + var key = keys[ki]; + var value = element[key]; + var expandedValue; -/** - * @return {Object} - xml2js formatted object - */ -Arc.prototype.buildJsObj = function () { - var arcObj = {}; + // skip @context + if(key === '@context') { + continue; + } - // attributes - var attributes = {}; - if(this.id != null) { - attributes.id = this.id; - } - if(this.class_ != null) { - attributes.class = this.class_; - } - if(this.source != null) { - attributes.source = this.source; - } - if(this.target != null) { - attributes.target = this.target; - } - utils.addAttributes(arcObj, attributes); + // expand property + var expandedProperty = _expandIri(activeCtx, key, {vocab: true}); - // children - this.baseToJsObj(arcObj); - for(var i=0; i < this.glyphs.length; i++) { - if (i==0) { - arcObj.glyph = []; - } - arcObj.glyph.push(this.glyphs[i].buildJsObj()); - } - if(this.start != null) { - arcObj.start = this.start.buildJsObj(); - } - if(this.state != null) { - arcObj.state = this.state.buildJsObj(); - } - for(var i=0; i < this.nexts.length; i++) { - if (i==0) { - arcObj.next = []; - } - arcObj.next.push(this.nexts[i].buildJsObj()); - } - if(this.end != null) { - arcObj.end = this.end.buildJsObj(); - } - return arcObj; -}; + // drop non-absolute IRI keys that aren't keywords + if(expandedProperty === null || + !(_isAbsoluteIri(expandedProperty) || _isKeyword(expandedProperty))) { + continue; + } -/** - * @return {string} - */ -Arc.prototype.toXML = function () { - return utils.buildString({arc: this.buildJsObj()}) -}; + if(_isKeyword(expandedProperty)) { + if(expandedActiveProperty === '@reverse') { + throw new JsonLdError( + 'Invalid JSON-LD syntax; a keyword cannot be used as a @reverse ' + + 'property.', 'jsonld.SyntaxError', + {code: 'invalid reverse property map', value: value}); + } + if(expandedProperty in rval) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; colliding keywords detected.', + 'jsonld.SyntaxError', + {code: 'colliding keywords', keyword: expandedProperty}); + } + } -/** - * @param {String} string - * @return {Arc} - */ -Arc.fromXML = function (string) { - var arc; - function fn (err, result) { - arc = Arc.fromObj(result); - }; - utils.parseString(string, fn); - return arc; -}; + // syntax error if @id is not a string + if(expandedProperty === '@id' && !_isString(value)) { + if(!options.isFrame) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; "@id" value must a string.', + 'jsonld.SyntaxError', {code: 'invalid @id value', value: value}); + } + if(!_isObject(value)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; "@id" value must be a string or an ' + + 'object.', 'jsonld.SyntaxError', + {code: 'invalid @id value', value: value}); + } + } -/** - * @param {Object} jsObj - xml2js formatted object - * @return {Arc} - */ -Arc.fromObj = function (jsObj) { - if (typeof jsObj.arc == 'undefined') { - throw new Error("Bad XML provided, expected tagName arc, got: " + Object.keys(jsObj)[0]); - } + if(expandedProperty === '@type') { + _validateTypeValue(value); + } - var arc = new ns.Arc(); - jsObj = jsObj.arc; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return arc; - } + // @graph must be an array or an object + if(expandedProperty === '@graph' && + !(_isObject(value) || _isArray(value))) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; "@graph" value must not be an ' + + 'object or an array.', + 'jsonld.SyntaxError', {code: 'invalid @graph value', value: value}); + } - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - arc.id = attributes.id || null; - arc.class_ = attributes.class || null; - arc.source = attributes.source || null; - arc.target = attributes.target || null; - } + // @value must not be an object or an array + if(expandedProperty === '@value' && + (_isObject(value) || _isArray(value))) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; "@value" value must not be an ' + + 'object or an array.', + 'jsonld.SyntaxError', + {code: 'invalid value object value', value: value}); + } - // children - if(jsObj.start) { - var start = ns.StartType.fromObj({start: jsObj.start[0]}); - arc.setStart(start); - } - if(jsObj.next) { - var nexts = jsObj.next; - for (var i=0; i < nexts.length; i++) { - var next = ns.NextType.fromObj({next: nexts[i]}); - arc.addNext(next); - } - } - if(jsObj.end) { - var end = ns.EndType.fromObj({end: jsObj.end[0]}); - arc.setEnd(end); - } - if(jsObj.glyph) { - var glyphs = jsObj.glyph; - for (var i=0; i < glyphs.length; i++) { - var glyph = ns.Glyph.fromObj({glyph: glyphs[i]}); - arc.addGlyph(glyph); - } - } + // @language must be a string + if(expandedProperty === '@language') { + if(value === null) { + // drop null @language values, they expand as if they didn't exist + continue; + } + if(!_isString(value)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; "@language" value must be a string.', + 'jsonld.SyntaxError', + {code: 'invalid language-tagged string', value: value}); + } + // ensure language value is lowercase + value = value.toLowerCase(); + } - arc.baseFromObj(jsObj); - return arc; -}; + // @index must be a string + if(expandedProperty === '@index') { + if(!_isString(value)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; "@index" value must be a string.', + 'jsonld.SyntaxError', + {code: 'invalid @index value', value: value}); + } + } -ns.Arc = Arc; -// ------- END ARC ------- + // @reverse must be an object + if(expandedProperty === '@reverse') { + if(!_isObject(value)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; "@reverse" value must be an object.', + 'jsonld.SyntaxError', {code: 'invalid @reverse value', value: value}); + } -// ------- STARTTYPE ------- -/** - * Represents the <start> element. - * @class StartType - * @param {Object} params - * @param {string|number=} params.x - * @param {string|number=} params.y - */ -var StartType = function (params) { - var params = checkParams(params, ['x', 'y']); - this.x = parseFloat(params.x); - this.y = parseFloat(params.y); -}; + expandedValue = self.expand(activeCtx, '@reverse', value, options); -/** - * @return {Object} - xml2js formatted object - */ -StartType.prototype.buildJsObj = function () { - var startObj = {}; + // properties double-reversed + if('@reverse' in expandedValue) { + for(var property in expandedValue['@reverse']) { + jsonld.addValue( + rval, property, expandedValue['@reverse'][property], + {propertyIsArray: true}); + } + } - // attributes - var attributes = {}; - if(!isNaN(this.x)) { - attributes.x = this.x; - } - if(!isNaN(this.y)) { - attributes.y = this.y; - } - utils.addAttributes(startObj, attributes); - return startObj; -}; + // FIXME: can this be merged with code below to simplify? + // merge in all reversed properties + var reverseMap = rval['@reverse'] || null; + for(var property in expandedValue) { + if(property === '@reverse') { + continue; + } + if(reverseMap === null) { + reverseMap = rval['@reverse'] = {}; + } + jsonld.addValue(reverseMap, property, [], {propertyIsArray: true}); + var items = expandedValue[property]; + for(var ii = 0; ii < items.length; ++ii) { + var item = items[ii]; + if(_isValue(item) || _isList(item)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; "@reverse" value must not be a ' + + '@value or an @list.', 'jsonld.SyntaxError', + {code: 'invalid reverse property value', value: expandedValue}); + } + jsonld.addValue( + reverseMap, property, item, {propertyIsArray: true}); + } + } -/** - * @return {string} - */ -StartType.prototype.toXML = function () { - return utils.buildString({start: this.buildJsObj()}) -}; + continue; + } -/** - * @param {String} string - * @return {StartType} - */ -StartType.fromXML = function (string) { - var start; - function fn (err, result) { - start = StartType.fromObj(result); - }; - utils.parseString(string, fn); - return start; -}; + var container = jsonld.getContextValue(activeCtx, key, '@container'); -/** - * @param {Object} jsObj - xml2js formatted object - * @return {StartType} - */ -StartType.fromObj = function (jsObj) { - if (typeof jsObj.start == 'undefined') { - throw new Error("Bad XML provided, expected tagName start, got: " + Object.keys(jsObj)[0]); - } + if(container === '@language' && _isObject(value)) { + // handle language map container (skip if value is not an object) + expandedValue = _expandLanguageMap(value); + } else if(container === '@index' && _isObject(value)) { + // handle index container (skip if value is not an object) + expandedValue = (function _expandIndexMap(activeProperty) { + var rval = []; + var keys = Object.keys(value).sort(); + for(var ki = 0; ki < keys.length; ++ki) { + var key = keys[ki]; + var val = value[key]; + if(!_isArray(val)) { + val = [val]; + } + val = self.expand(activeCtx, activeProperty, val, options, false); + for(var vi = 0; vi < val.length; ++vi) { + var item = val[vi]; + if(!('@index' in item)) { + item['@index'] = key; + } + rval.push(item); + } + } + return rval; + })(key); + } else { + // recurse into @list or @set + var isList = (expandedProperty === '@list'); + if(isList || expandedProperty === '@set') { + var nextActiveProperty = activeProperty; + if(isList && expandedActiveProperty === '@graph') { + nextActiveProperty = null; + } + expandedValue = self.expand( + activeCtx, nextActiveProperty, value, options, isList); + if(isList && _isList(expandedValue)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; lists of lists are not permitted.', + 'jsonld.SyntaxError', {code: 'list of lists'}); + } + } else { + // recursively expand value with key as new active property + expandedValue = self.expand(activeCtx, key, value, options, false); + } + } - var start = new ns.StartType(); - jsObj = jsObj.start; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return start; - } + // drop null values if property is not @value + if(expandedValue === null && expandedProperty !== '@value') { + continue; + } - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - start.x = parseFloat(attributes.x); - start.y = parseFloat(attributes.y); - } - return start; -}; + // convert expanded value to @list if container specifies it + if(expandedProperty !== '@list' && !_isList(expandedValue) && + container === '@list') { + // ensure expanded value is an array + expandedValue = (_isArray(expandedValue) ? + expandedValue : [expandedValue]); + expandedValue = {'@list': expandedValue}; + } -ns.StartType = StartType; -// ------- END STARTTYPE ------- + // FIXME: can this be merged with code above to simplify? + // merge in reverse properties + if(activeCtx.mappings[key] && activeCtx.mappings[key].reverse) { + var reverseMap = rval['@reverse'] = rval['@reverse'] || {}; + if(!_isArray(expandedValue)) { + expandedValue = [expandedValue]; + } + for(var ii = 0; ii < expandedValue.length; ++ii) { + var item = expandedValue[ii]; + if(_isValue(item) || _isList(item)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; "@reverse" value must not be a ' + + '@value or an @list.', 'jsonld.SyntaxError', + {code: 'invalid reverse property value', value: expandedValue}); + } + jsonld.addValue( + reverseMap, expandedProperty, item, {propertyIsArray: true}); + } + continue; + } -// ------- ENDTYPE ------- -/** - * Represents the <end> element. - * @class EndType - * @param {Object} params - * @param {string|number=} params.x - * @param {string|number=} params.y - */ -var EndType = function (params) { - var params = checkParams(params, ['x', 'y']); - this.x = parseFloat(params.x); - this.y = parseFloat(params.y); -}; + // add value for property + // use an array except for certain keywords + var useArray = + ['@index', '@id', '@type', '@value', '@language'].indexOf( + expandedProperty) === -1; + jsonld.addValue( + rval, expandedProperty, expandedValue, {propertyIsArray: useArray}); + } -/** - * @return {Object} - xml2js formatted object - */ -EndType.prototype.buildJsObj = function () { - var endObj = {}; + // get property count on expanded output + keys = Object.keys(rval); + var count = keys.length; - // attributes - var attributes = {}; - if(!isNaN(this.x)) { - attributes.x = this.x; - } - if(!isNaN(this.y)) { - attributes.y = this.y; - } - utils.addAttributes(endObj, attributes); - return endObj; -}; + if('@value' in rval) { + // @value must only have @language or @type + if('@type' in rval && '@language' in rval) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; an element containing "@value" may not ' + + 'contain both "@type" and "@language".', + 'jsonld.SyntaxError', {code: 'invalid value object', element: rval}); + } + var validCount = count - 1; + if('@type' in rval) { + validCount -= 1; + } + if('@index' in rval) { + validCount -= 1; + } + if('@language' in rval) { + validCount -= 1; + } + if(validCount !== 0) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; an element containing "@value" may only ' + + 'have an "@index" property and at most one other property ' + + 'which can be "@type" or "@language".', + 'jsonld.SyntaxError', {code: 'invalid value object', element: rval}); + } + // drop null @values + if(rval['@value'] === null) { + rval = null; + } else if('@language' in rval && !_isString(rval['@value'])) { + // if @language is present, @value must be a string + throw new JsonLdError( + 'Invalid JSON-LD syntax; only strings may be language-tagged.', + 'jsonld.SyntaxError', + {code: 'invalid language-tagged value', element: rval}); + } else if('@type' in rval && (!_isAbsoluteIri(rval['@type']) || + rval['@type'].indexOf('_:') === 0)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; an element containing "@value" and "@type" ' + + 'must have an absolute IRI for the value of "@type".', + 'jsonld.SyntaxError', {code: 'invalid typed value', element: rval}); + } + } else if('@type' in rval && !_isArray(rval['@type'])) { + // convert @type to an array + rval['@type'] = [rval['@type']]; + } else if('@set' in rval || '@list' in rval) { + // handle @set and @list + if(count > 1 && !(count === 2 && '@index' in rval)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; if an element has the property "@set" ' + + 'or "@list", then it can have at most one other property that is ' + + '"@index".', 'jsonld.SyntaxError', + {code: 'invalid set or list object', element: rval}); + } + // optimize away @set + if('@set' in rval) { + rval = rval['@set']; + keys = Object.keys(rval); + count = keys.length; + } + } else if(count === 1 && '@language' in rval) { + // drop objects with only @language + rval = null; + } -/** - * @return {string} - */ -EndType.prototype.toXML = function () { - return utils.buildString({end: this.buildJsObj()}) -}; + // drop certain top-level objects that do not occur in lists + if(_isObject(rval) && + !options.keepFreeFloatingNodes && !insideList && + (activeProperty === null || expandedActiveProperty === '@graph')) { + // drop empty object, top-level @value/@list, or object with only @id + if(count === 0 || '@value' in rval || '@list' in rval || + (count === 1 && '@id' in rval)) { + rval = null; + } + } -/** - * @param {String} string - * @return {EndType} - */ -EndType.fromXML = function (string) { - var end; - function fn (err, result) { - end = EndType.fromObj(result); - }; - utils.parseString(string, fn); - return end; + return rval; }; /** - * @param {Object} jsObj - xml2js formatted object - * @return {EndType} + * Creates a JSON-LD node map (node ID => node). + * + * @param input the expanded JSON-LD to create a node map of. + * @param [options] the options to use: + * [issuer] a jsonld.IdentifierIssuer to use to label blank nodes. + * [namer] (deprecated). + * + * @return the node map. */ -EndType.fromObj = function (jsObj) { - if (typeof jsObj.end == 'undefined') { - throw new Error("Bad XML provided, expected tagName end, got: " + Object.keys(jsObj)[0]); - } +Processor.prototype.createNodeMap = function(input, options) { + options = options || {}; - var end = new ns.EndType(); - jsObj = jsObj.end; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return end; - } + // produce a map of all subjects and name each bnode + var issuer = options.namer || options.issuer || new IdentifierIssuer('_:b'); + var graphs = {'@default': {}}; + _createNodeMap(input, graphs, '@default', issuer); - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - end.x = parseFloat(attributes.x); - end.y = parseFloat(attributes.y); - } - return end; + // add all non-default graphs to default graph + return _mergeNodeMaps(graphs); }; -ns.EndType = EndType; -// ------- END ENDTYPE ------- - -// ------- NEXTTYPE ------- /** - * Represents the <next> element. - * @class NextType - * @param {Object} params - * @param {string|number=} params.x - * @param {string|number=} params.y + * Performs JSON-LD flattening. + * + * @param input the expanded JSON-LD to flatten. + * + * @return the flattened output. */ -var NextType = function (params) { - var params = checkParams(params, ['x', 'y']); - this.x = parseFloat(params.x); - this.y = parseFloat(params.y); +Processor.prototype.flatten = function(input) { + var defaultGraph = this.createNodeMap(input); + + // produce flattened output + var flattened = []; + var keys = Object.keys(defaultGraph).sort(); + for(var ki = 0; ki < keys.length; ++ki) { + var node = defaultGraph[keys[ki]]; + // only add full subjects to top-level + if(!_isSubjectReference(node)) { + flattened.push(node); + } + } + return flattened; }; /** - * @return {Object} - xml2js formatted object + * Performs JSON-LD framing. + * + * @param input the expanded JSON-LD to frame. + * @param frame the expanded JSON-LD frame to use. + * @param options the framing options. + * + * @return the framed output. */ -NextType.prototype.buildJsObj = function () { - var nextObj = {}; +Processor.prototype.frame = function(input, frame, options) { + // create framing state + var state = { + options: options, + graphs: {'@default': {}, '@merged': {}}, + subjectStack: [], + link: {} + }; - // attributes - var attributes = {}; - if(!isNaN(this.x)) { - attributes.x = this.x; - } - if(!isNaN(this.y)) { - attributes.y = this.y; - } - utils.addAttributes(nextObj, attributes); - return nextObj; -}; + // produce a map of all graphs and name each bnode + // FIXME: currently uses subjects from @merged graph only + var issuer = new IdentifierIssuer('_:b'); + _createNodeMap(input, state.graphs, '@merged', issuer); + state.subjects = state.graphs['@merged']; -/** - * @return {string} - */ -NextType.prototype.toXML = function () { - return utils.buildString({next: this.buildJsObj()}) + // frame the subjects + var framed = []; + _frame(state, Object.keys(state.subjects).sort(), frame, framed, null); + return framed; }; /** - * @param {String} string - * @return {NextType} + * Performs normalization on the given RDF dataset. + * + * @param dataset the RDF dataset to normalize. + * @param options the normalization options. + * @param callback(err, normalized) called once the operation completes. */ -NextType.fromXML = function (string) { - var next; - function fn (err, result) { - next = NextType.fromObj(result); - }; - utils.parseString(string, fn); - return next; +Processor.prototype.normalize = function(dataset, options, callback) { + if(options.algorithm === 'URDNA2015') { + return new URDNA2015(options).main(dataset, callback); + } + if(options.algorithm === 'URGNA2012') { + return new URGNA2012(options).main(dataset, callback); + } + callback(new Error( + 'Invalid RDF Dataset Normalization algorithm: ' + options.algorithm)); }; /** - * @param {Object} jsObj - xml2js formatted object - * @return {NextType} + * Converts an RDF dataset to JSON-LD. + * + * @param dataset the RDF dataset. + * @param options the RDF serialization options. + * @param callback(err, output) called once the operation completes. */ -NextType.fromObj = function (jsObj) { - if (typeof jsObj.next == 'undefined') { - throw new Error("Bad XML provided, expected tagName next, got: " + Object.keys(jsObj)[0]); - } - - var next = new ns.NextType(); - jsObj = jsObj.next; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return next; - } - - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - next.x = parseFloat(attributes.x); - next.y = parseFloat(attributes.y); - } - return next; -}; +Processor.prototype.fromRDF = function(dataset, options, callback) { + var defaultGraph = {}; + var graphMap = {'@default': defaultGraph}; + var referencedOnce = {}; -ns.NextType = NextType; -// ------- END NEXTTYPE ------- + for(var name in dataset) { + var graph = dataset[name]; + if(!(name in graphMap)) { + graphMap[name] = {}; + } + if(name !== '@default' && !(name in defaultGraph)) { + defaultGraph[name] = {'@id': name}; + } + var nodeMap = graphMap[name]; + for(var ti = 0; ti < graph.length; ++ti) { + var triple = graph[ti]; -// ------- POINT ------- -/** - * Represents the <point> element. - * @class Point - * @param {Object} params - * @param {string|number=} params.x - * @param {string|number=} params.y - */ -var Point = function (params) { - ns.SBGNBase.call(this, params); - var params = checkParams(params, ['x', 'y']); - this.x = parseFloat(params.x); - this.y = parseFloat(params.y); -}; -Point.prototype = Object.create(ns.SBGNBase.prototype); -Point.prototype.constructor = Point; + // get subject, predicate, object + var s = triple.subject.value; + var p = triple.predicate.value; + var o = triple.object; -/** - * @return {Object} - xml2js formatted object - */ -Point.prototype.buildJsObj = function () { - var pointJsObj = {}; + if(!(s in nodeMap)) { + nodeMap[s] = {'@id': s}; + } + var node = nodeMap[s]; - // attributes - var attributes = {}; - if(!isNaN(this.x)) { - attributes.x = this.x; - } - if(!isNaN(this.y)) { - attributes.y = this.y; - } - utils.addAttributes(pointJsObj, attributes); - this.baseToJsObj(pointJsObj); - return pointJsObj; -}; + var objectIsId = (o.type === 'IRI' || o.type === 'blank node'); + if(objectIsId && !(o.value in nodeMap)) { + nodeMap[o.value] = {'@id': o.value}; + } -/** - * @return {string} - */ -Point.prototype.toXML = function () { - return utils.buildString({point: this.buildJsObj()}) -}; + if(p === RDF_TYPE && !options.useRdfType && objectIsId) { + jsonld.addValue(node, '@type', o.value, {propertyIsArray: true}); + continue; + } -/** - * @param {String} string - * @return {Point} - */ -Point.fromXML = function (string) { - var point; - function fn (err, result) { - point = Point.fromObj(result); - }; - utils.parseString(string, fn); - return point; -}; + var value = _RDFToObject(o, options.useNativeTypes); + jsonld.addValue(node, p, value, {propertyIsArray: true}); -/** - * @param {Object} jsObj - xml2js formatted object - * @return {Point} - */ -Point.fromObj = function (jsObj) { - if (typeof jsObj.point == 'undefined') { - throw new Error("Bad XML provided, expected tagName point, got: " + Object.keys(jsObj)[0]); - } + // object may be an RDF list/partial list node but we can't know easily + // until all triples are read + if(objectIsId) { + if(o.value === RDF_NIL) { + // track rdf:nil uniquely per graph + var object = nodeMap[o.value]; + if(!('usages' in object)) { + object.usages = []; + } + object.usages.push({ + node: node, + property: p, + value: value + }); + } else if(o.value in referencedOnce) { + // object referenced more than once + referencedOnce[o.value] = false; + } else { + // keep track of single reference + referencedOnce[o.value] = { + node: node, + property: p, + value: value + }; + } + } + } + } - var point = new ns.Point(); - jsObj = jsObj.point; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return point; - } + // convert linked lists to @list arrays + for(var name in graphMap) { + var graphObject = graphMap[name]; - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - point.x = parseFloat(attributes.x); - point.y = parseFloat(attributes.y); - } - point.baseFromObj(jsObj); - return point; -}; + // no @lists to be converted, continue + if(!(RDF_NIL in graphObject)) { + continue; + } -ns.Point = Point; -// ------- END POINT ------- + // iterate backwards through each RDF list + var nil = graphObject[RDF_NIL]; + for(var i = 0; i < nil.usages.length; ++i) { + var usage = nil.usages[i]; + var node = usage.node; + var property = usage.property; + var head = usage.value; + var list = []; + var listNodes = []; -// ------- CALLOUT ------- -/** - * Represents the <callout> element. - * @class Callout - * @param {Object} params - * @param {string=} params.target - * @param {Point=} params.point - */ -var Callout = function (params) { - var params = checkParams(params, ['target', 'point']); - this.target = params.target; - this.point = params.point; -}; + // ensure node is a well-formed list node; it must: + // 1. Be referenced only once. + // 2. Have an array for rdf:first that has 1 item. + // 3. Have an array for rdf:rest that has 1 item. + // 4. Have no keys other than: @id, rdf:first, rdf:rest, and, + // optionally, @type where the value is rdf:List. + var nodeKeyCount = Object.keys(node).length; + while(property === RDF_REST && + _isObject(referencedOnce[node['@id']]) && + _isArray(node[RDF_FIRST]) && node[RDF_FIRST].length === 1 && + _isArray(node[RDF_REST]) && node[RDF_REST].length === 1 && + (nodeKeyCount === 3 || (nodeKeyCount === 4 && _isArray(node['@type']) && + node['@type'].length === 1 && node['@type'][0] === RDF_LIST))) { + list.push(node[RDF_FIRST][0]); + listNodes.push(node['@id']); -/** - * @param {Point} point - */ -Callout.prototype.setPoint = function(point) { - this.point = point; -}; + // get next node, moving backwards through list + usage = referencedOnce[node['@id']]; + node = usage.node; + property = usage.property; + head = usage.value; + nodeKeyCount = Object.keys(node).length; -/** - * @return {Object} - xml2js formatted object - */ -Callout.prototype.buildJsObj = function () { - var calloutObj = {}; + // if node is not a blank node, then list head found + if(node['@id'].indexOf('_:') !== 0) { + break; + } + } - // attributes - var attributes = {}; - if(this.target != null) { - attributes.target = this.target; - } - utils.addAttributes(calloutObj, attributes); + // the list is nested in another list + if(property === RDF_FIRST) { + // empty list + if(node['@id'] === RDF_NIL) { + // can't convert rdf:nil to a @list object because it would + // result in a list of lists which isn't supported + continue; + } - // children - if(this.point != null) { - calloutObj.point = this.point.buildJsObj(); - } - return calloutObj; -}; + // preserve list head + head = graphObject[head['@id']][RDF_REST][0]; + list.pop(); + listNodes.pop(); + } -/** - * @return {string} - */ -Callout.prototype.toXML = function () { - return utils.buildString({callout: this.buildJsObj()}) -}; + // transform list into @list object + delete head['@id']; + head['@list'] = list.reverse(); + for(var j = 0; j < listNodes.length; ++j) { + delete graphObject[listNodes[j]]; + } + } -/** - * @param {String} string - * @return {Callout} - */ -Callout.fromXML = function (string) { - var callout; - function fn (err, result) { - callout = Callout.fromObj(result); - }; - utils.parseString(string, fn); - return callout; -}; + delete nil.usages; + } -/** - * @param {Object} jsObj - xml2js formatted object - * @return {Callout} - */ -Callout.fromObj = function (jsObj) { - if (typeof jsObj.callout == 'undefined') { - throw new Error("Bad XML provided, expected tagName callout, got: " + Object.keys(jsObj)[0]); - } - - var callout = new ns.Callout(); - jsObj = jsObj.callout; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return callout; - } - - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - callout.target = attributes.target || null; - } + var result = []; + var subjects = Object.keys(defaultGraph).sort(); + for(var i = 0; i < subjects.length; ++i) { + var subject = subjects[i]; + var node = defaultGraph[subject]; + if(subject in graphMap) { + var graph = node['@graph'] = []; + var graphObject = graphMap[subject]; + var subjects_ = Object.keys(graphObject).sort(); + for(var si = 0; si < subjects_.length; ++si) { + var node_ = graphObject[subjects_[si]]; + // only add full subjects to top-level + if(!_isSubjectReference(node_)) { + graph.push(node_); + } + } + } + // only add full subjects to top-level + if(!_isSubjectReference(node)) { + result.push(node); + } + } - // children - if(jsObj.point) { - var point = ns.Point.fromObj({point: jsObj.point[0]}); - callout.setPoint(point); - } - return callout; + callback(null, result); }; -ns.Callout = Callout; -// ------- END CALLOUT ------- - -// ------- ARCGROUP ------- /** - * Represents the <arcgroup> element. - * @class - * @extends SBGNBase - * @param {Object} params - * @param {string=} params.class_ - * @param {Glyph[]=} params.glyphs - * @param {Arc[]=} params.arcs + * Outputs an RDF dataset for the expanded JSON-LD input. + * + * @param input the expanded JSON-LD input. + * @param options the RDF serialization options. + * + * @return the RDF dataset. */ -var Arcgroup = function (params) { - ns.SBGNBase.call(this, params); - var params = checkParams(params, ['class_', 'glyphs', 'arcs']); - this.class_ = params.class_; - this.glyphs = params.glyphs || []; - this.arcs = params.arcs || []; -}; - -Arcgroup.prototype = Object.create(ns.SBGNBase.prototype); -Arcgroup.prototype.constructor = Arcgroup; +Processor.prototype.toRDF = function(input, options) { + // create node map for default graph (and any named graphs) + var issuer = new IdentifierIssuer('_:b'); + var nodeMap = {'@default': {}}; + _createNodeMap(input, nodeMap, '@default', issuer); -/** - * @param {Glyph} glyph - */ -Arcgroup.prototype.addGlyph = function (glyph) { - this.glyphs.push(glyph); + var dataset = {}; + var graphNames = Object.keys(nodeMap).sort(); + for(var i = 0; i < graphNames.length; ++i) { + var graphName = graphNames[i]; + // skip relative IRIs + if(graphName === '@default' || _isAbsoluteIri(graphName)) { + dataset[graphName] = _graphToRDF(nodeMap[graphName], issuer, options); + } + } + return dataset; }; /** - * @param {Arc} arc + * Processes a local context and returns a new active context. + * + * @param activeCtx the current active context. + * @param localCtx the local context to process. + * @param options the context processing options. + * + * @return the new active context. */ -Arcgroup.prototype.addArc = function (arc) { - this.arcs.push(arc); -}; +Processor.prototype.processContext = function(activeCtx, localCtx, options) { + // normalize local context to an array of @context objects + if(_isObject(localCtx) && '@context' in localCtx && + _isArray(localCtx['@context'])) { + localCtx = localCtx['@context']; + } + var ctxs = _isArray(localCtx) ? localCtx : [localCtx]; -/** - * @return {Object} - xml2js formatted object - */ -Arcgroup.prototype.buildJsObj = function () { - var arcgroupObj = {}; + // no contexts in array, clone existing context + if(ctxs.length === 0) { + return activeCtx.clone(); + } - // attributes - var attributes = {}; - if(this.class_ != null) { - attributes.class = this.class_; - } - utils.addAttributes(arcgroupObj, attributes); + // process each context in order, update active context + // on each iteration to ensure proper caching + var rval = activeCtx; + for(var i = 0; i < ctxs.length; ++i) { + var ctx = ctxs[i]; - // children - this.baseToJsObj(arcgroupObj); - for(var i=0; i < this.glyphs.length; i++) { - if (i==0) { - arcgroupObj.glyph = []; - } - arcgroupObj.glyph.push(this.glyphs[i].buildJsObj()); - } - for(var i=0; i < this.arcs.length; i++) { - if (i==0) { - arcgroupObj.arc = []; - } - arcgroupObj.arc.push(this.arcs[i].buildJsObj()); - } - return arcgroupObj; -}; + // reset to initial context + if(ctx === null) { + rval = activeCtx = _getInitialContext(options); + continue; + } -/** - * @return {string} - */ -Arcgroup.prototype.toXML = function () { - return utils.buildString({arcgroup: this.buildJsObj()}); -}; + // dereference @context key if present + if(_isObject(ctx) && '@context' in ctx) { + ctx = ctx['@context']; + } -/** - * @param {String} string - * @return {Arcgroup} - */ -Arcgroup.fromXML = function (string) { - var arcgroup; - function fn (err, result) { - arcgroup = Arcgroup.fromObj(result); - }; - utils.parseString(string, fn); - return arcgroup; -}; + // context must be an object by now, all URLs retrieved before this call + if(!_isObject(ctx)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; @context must be an object.', + 'jsonld.SyntaxError', {code: 'invalid local context', context: ctx}); + } -/** - * @param {Object} jsObj - xml2js formatted object - * @return {Arcgroup} - */ -Arcgroup.fromObj = function (jsObj) { - if (typeof jsObj.arcgroup == 'undefined') { - throw new Error("Bad XML provided, expected tagName arcgroup, got: " + Object.keys(jsObj)[0]); - } + // get context from cache if available + if(jsonld.cache.activeCtx) { + var cached = jsonld.cache.activeCtx.get(activeCtx, ctx); + if(cached) { + rval = activeCtx = cached; + continue; + } + } - var arcgroup = new ns.Arcgroup(); - jsObj = jsObj.arcgroup; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return arcgroup; - } + // update active context and clone new one before updating + activeCtx = rval; + rval = rval.clone(); - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - arcgroup.class_ = attributes.class || null; - } + // define context mappings for keys in local context + var defined = {}; - if(jsObj.glyph) { - var glyphs = jsObj.glyph; - for (var i=0; i < glyphs.length; i++) { - var glyph = ns.Glyph.fromObj({glyph: glyphs[i]}); - arcgroup.addGlyph(glyph); - } - } - if(jsObj.arc) { - var arcs = jsObj.arc; - for (var i=0; i < arcs.length; i++) { - var arc = ns.Arc.fromObj({arc: arcs[i]}); - arcgroup.addArc(arc); - } - } + // handle @base + if('@base' in ctx) { + var base = ctx['@base']; - arcgroup.baseFromObj(jsObj); - return arcgroup; -}; + // clear base + if(base === null) { + base = null; + } else if(!_isString(base)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; the value of "@base" in a ' + + '@context must be a string or null.', + 'jsonld.SyntaxError', {code: 'invalid base IRI', context: ctx}); + } else if(base !== '' && !_isAbsoluteIri(base)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; the value of "@base" in a ' + + '@context must be an absolute IRI or the empty string.', + 'jsonld.SyntaxError', {code: 'invalid base IRI', context: ctx}); + } -ns.Arcgroup = Arcgroup; -// ------- END ARCGROUP ------- + if(base !== null) { + base = jsonld.url.parse(base || ''); + } + rval['@base'] = base; + defined['@base'] = true; + } -ns.render = renderExt; -ns.annot = annotExt; -module.exports = ns; -},{"./libsbgn-annotations":21,"./libsbgn-render":22,"./utilities":24,"xml2js":118}],24:[function(_dereq_,module,exports){ -var ns = {}; -var xml2js = _dereq_('xml2js'); + // handle @vocab + if('@vocab' in ctx) { + var value = ctx['@vocab']; + if(value === null) { + delete rval['@vocab']; + } else if(!_isString(value)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; the value of "@vocab" in a ' + + '@context must be a string or null.', + 'jsonld.SyntaxError', {code: 'invalid vocab mapping', context: ctx}); + } else if(!_isAbsoluteIri(value)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; the value of "@vocab" in a ' + + '@context must be an absolute IRI.', + 'jsonld.SyntaxError', {code: 'invalid vocab mapping', context: ctx}); + } else { + rval['@vocab'] = value; + } + defined['@vocab'] = true; + } -/* - guarantees to return an object with given args being set to null if not present, other args returned as is -*/ -ns.checkParams = function (params, names) { - if (typeof params == "undefined" || params == null) { - params = {}; - } - if (typeof params != 'object') { - throw new Error("Bad params. Object with named parameters must be passed."); - } - for(var i=0; i < names.length; i++) { - var argName = names[i]; - if (typeof params[argName] == 'undefined') { - params[argName] = null; - } - } - return params; -} + // handle @language + if('@language' in ctx) { + var value = ctx['@language']; + if(value === null) { + delete rval['@language']; + } else if(!_isString(value)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; the value of "@language" in a ' + + '@context must be a string or null.', + 'jsonld.SyntaxError', + {code: 'invalid default language', context: ctx}); + } else { + rval['@language'] = value.toLowerCase(); + } + defined['@language'] = true; + } -ns.getFirstLevelByName = function (xmlObj, localName) { - var result = []; - for(var i=0; i\\"\{\}\|\^\`]/; + // do @id expansion (automatic for @graph) + if(type === '@id' || (expandedProperty === '@graph' && _isString(value))) { + return {'@id': _expandIri(activeCtx, value, {base: true})}; + } + // do @id expansion w/vocab + if(type === '@vocab') { + return {'@id': _expandIri(activeCtx, value, {vocab: true, base: true})}; + } -// ## Constructor -function N3Lexer(options) { - if (!(this instanceof N3Lexer)) - return new N3Lexer(options); - options = options || {}; + // do not expand keyword values + if(_isKeyword(expandedProperty)) { + return value; + } - // In line mode (N-Triples or N-Quads), only simple features may be parsed - if (options.lineMode) { - // Don't tokenize special literals - this._tripleQuotedString = this._number = this._boolean = /$0^/; - // Swap the tokenize method for a restricted version - var self = this; - this._tokenize = this.tokenize; - this.tokenize = function (input, callback) { - this._tokenize(input, function (error, token) { - if (!error && /^(?:IRI|prefixed|literal|langcode|type|\.|eof)$/.test(token.type)) - callback && callback(error, token); - else - callback && callback(error || self._syntaxError(token.type, callback = null)); - }); - }; - } - // Enable N3 functionality by default - this._n3Mode = options.n3 !== false; - // Disable comment tokens by default - this._comments = !!options.comments; -} - -N3Lexer.prototype = { - // ## Regular expressions - // It's slightly faster to have these as properties than as in-scope variables + var rval = {}; - _iri: /^<((?:[^ <>{}\\]|\\[uU])+)>[ \t]*/, // IRI with escape sequences; needs sanity check after unescaping - _unescapedIri: /^<([^\x00-\x20<>\\"\{\}\|\^\`]*)>[ \t]*/, // IRI without escape sequences; no unescaping - _unescapedString: /^"[^"\\]+"(?=[^"\\])/, // non-empty string without escape sequences - _singleQuotedString: /^"[^"\\]*(?:\\.[^"\\]*)*"(?=[^"\\])|^'[^'\\]*(?:\\.[^'\\]*)*'(?=[^'\\])/, - _tripleQuotedString: /^""("[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*")""|^''('[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*')''/, - _langcode: /^@([a-z]+(?:-[a-z0-9]+)*)(?=[^a-z0-9\-])/i, - _prefix: /^((?:[A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:(?=[#\s<])/, - _prefixed: /^((?:[A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:((?:(?:[0-:A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])(?:(?:[\.\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])*(?:[\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~]))?)?)(?:[ \t]+|(?=\.?[,;!\^\s#()\[\]\{\}"'<]))/, - _variable: /^\?(?:(?:[A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:[\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)(?=[.,;!\^\s#()\[\]\{\}"'<])/, - _blank: /^_:((?:[0-9A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)(?:[ \t]+|(?=\.?[,;:\s#()\[\]\{\}"'<]))/, - _number: /^[\-+]?(?:\d+\.?\d*([eE](?:[\-\+])?\d+)|\d*\.?\d+)(?=[.,;:\s#()\[\]\{\}"'<])/, - _boolean: /^(?:true|false)(?=[.,;\s#()\[\]\{\}"'<])/, - _keyword: /^@[a-z]+(?=[\s#<])/i, - _sparqlKeyword: /^(?:PREFIX|BASE|GRAPH)(?=[\s#<])/i, - _shortPredicates: /^a(?=\s+|<)/, - _newline: /^[ \t]*(?:#[^\n\r]*)?(?:\r\n|\n|\r)[ \t]*/, - _comment: /#([^\n\r]*)/, - _whitespace: /^[ \t]+/, - _endOfFile: /^(?:#[^\n\r]*)?$/, + if(type !== null) { + // other type + rval['@type'] = type; + } else if(_isString(value)) { + // check for language tagging for strings + var language = jsonld.getContextValue( + activeCtx, activeProperty, '@language'); + if(language !== null) { + rval['@language'] = language; + } + } + // do conversion of values that aren't basic JSON types to strings + if(['boolean', 'number', 'string'].indexOf(typeof value) === -1) { + value = value.toString(); + } + rval['@value'] = value; - // ## Private methods + return rval; +} - // ### `_tokenizeToEnd` tokenizes as for as possible, emitting tokens through the callback - _tokenizeToEnd: function (callback, inputFinished) { - // Continue parsing as far as possible; the loop will return eventually - var input = this._input, outputComments = this._comments; - while (true) { - // Count and skip whitespace lines - var whiteSpaceMatch, comment; - while (whiteSpaceMatch = this._newline.exec(input)) { - // Try to find a comment - if (outputComments && (comment = this._comment.exec(whiteSpaceMatch[0]))) - callback(null, { line: this._line, type: 'comment', value: comment[1], prefix: '' }); - // Advance the input - input = input.substr(whiteSpaceMatch[0].length, input.length); - this._line++; - } - // Skip whitespace on current line - if (whiteSpaceMatch = this._whitespace.exec(input)) - input = input.substr(whiteSpaceMatch[0].length, input.length); +/** + * Creates an array of RDF triples for the given graph. + * + * @param graph the graph to create RDF triples for. + * @param issuer a IdentifierIssuer for assigning blank node names. + * @param options the RDF serialization options. + * + * @return the array of RDF triples for the given graph. + */ +function _graphToRDF(graph, issuer, options) { + var rval = []; - // Stop for now if we're at the end - if (this._endOfFile.test(input)) { - // If the input is finished, emit EOF - if (inputFinished) { - // Try to find a final comment - if (outputComments && (comment = this._comment.exec(input))) - callback(null, { line: this._line, type: 'comment', value: comment[1], prefix: '' }); - callback(input = null, { line: this._line, type: 'eof', value: '', prefix: '' }); - } - return this._input = input; + var ids = Object.keys(graph).sort(); + for(var i = 0; i < ids.length; ++i) { + var id = ids[i]; + var node = graph[id]; + var properties = Object.keys(node).sort(); + for(var pi = 0; pi < properties.length; ++pi) { + var property = properties[pi]; + var items = node[property]; + if(property === '@type') { + property = RDF_TYPE; + } else if(_isKeyword(property)) { + continue; } - // Look for specific token types based on the first character - var line = this._line, type = '', value = '', prefix = '', - firstChar = input[0], match = null, matchLength = 0, unescaped, inconclusive = false; - switch (firstChar) { - case '^': - // We need at least 3 tokens lookahead to distinguish ^^ and ^^pre:fixed - if (input.length < 3) - break; - // Try to match a type - else if (input[1] === '^') { - this._prevTokenType = '^^'; - // Move to type IRI or prefixed name - input = input.substr(2); - if (input[0] !== '<') { - inconclusive = true; - break; - } - } - // If no type, it must be a path expression - else { - if (this._n3Mode) { - matchLength = 1; - type = '^'; - } - break; - } - // Fall through in case the type is an IRI - case '<': - // Try to find a full IRI without escape sequences - if (match = this._unescapedIri.exec(input)) - type = 'IRI', value = match[1]; - // Try to find a full IRI with escape sequences - else if (match = this._iri.exec(input)) { - unescaped = this._unescape(match[1]); - if (unescaped === null || illegalIriChars.test(unescaped)) - return reportSyntaxError(this); - type = 'IRI', value = unescaped; - } - // Try to find a backwards implication arrow - else if (this._n3Mode && input.length > 1 && input[1] === '=') - type = 'inverse', matchLength = 2, value = 'http://www.w3.org/2000/10/swap/log#implies'; - break; + for(var ii = 0; ii < items.length; ++ii) { + var item = items[ii]; - case '_': - // Try to find a blank node. Since it can contain (but not end with) a dot, - // we always need a non-dot character before deciding it is a prefixed name. - // Therefore, try inserting a space if we're at the end of the input. - if ((match = this._blank.exec(input)) || - inputFinished && (match = this._blank.exec(input + ' '))) - type = 'blank', prefix = '_', value = match[1]; - break; + // RDF subject + var subject = {}; + subject.type = (id.indexOf('_:') === 0) ? 'blank node' : 'IRI'; + subject.value = id; - case '"': - case "'": - // Try to find a non-empty double-quoted literal without escape sequences - if (match = this._unescapedString.exec(input)) - type = 'literal', value = match[0]; - // Try to find any other literal wrapped in a pair of single or double quotes - else if (match = this._singleQuotedString.exec(input)) { - unescaped = this._unescape(match[0]); - if (unescaped === null) - return reportSyntaxError(this); - type = 'literal', value = unescaped.replace(/^'|'$/g, '"'); - } - // Try to find a literal wrapped in three pairs of single or double quotes - else if (match = this._tripleQuotedString.exec(input)) { - unescaped = match[1] || match[2]; - // Count the newlines and advance line counter - this._line += unescaped.split(/\r\n|\r|\n/).length - 1; - unescaped = this._unescape(unescaped); - if (unescaped === null) - return reportSyntaxError(this); - type = 'literal', value = unescaped.replace(/^'|'$/g, '"'); + // skip relative IRI subjects + if(!_isAbsoluteIri(id)) { + continue; } - break; - - case '?': - // Try to find a variable - if (this._n3Mode && (match = this._variable.exec(input))) - type = 'var', value = match[0]; - break; - case '@': - // Try to find a language code - if (this._prevTokenType === 'literal' && (match = this._langcode.exec(input))) - type = 'langcode', value = match[1]; - // Try to find a keyword - else if (match = this._keyword.exec(input)) - type = match[0]; - break; + // RDF predicate + var predicate = {}; + predicate.type = (property.indexOf('_:') === 0) ? 'blank node' : 'IRI'; + predicate.value = property; - case '.': - // Try to find a dot as punctuation - if (input.length === 1 ? inputFinished : (input[1] < '0' || input[1] > '9')) { - type = '.'; - matchLength = 1; - break; + // skip relative IRI predicates + if(!_isAbsoluteIri(property)) { + continue; } - // Fall through to numerical case (could be a decimal dot) - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '+': - case '-': - // Try to find a number - if (match = this._number.exec(input)) { - type = 'literal'; - value = '"' + match[0] + '"^^http://www.w3.org/2001/XMLSchema#' + - (match[1] ? 'double' : (/^[+\-]?\d+$/.test(match[0]) ? 'integer' : 'decimal')); + // skip blank node predicates unless producing generalized RDF + if(predicate.type === 'blank node' && !options.produceGeneralizedRdf) { + continue; } - break; - - case 'B': - case 'b': - case 'p': - case 'P': - case 'G': - case 'g': - // Try to find a SPARQL-style keyword - if (match = this._sparqlKeyword.exec(input)) - type = match[0].toUpperCase(); - else - inconclusive = true; - break; - - case 'f': - case 't': - // Try to match a boolean - if (match = this._boolean.exec(input)) - type = 'literal', value = '"' + match[0] + '"^^http://www.w3.org/2001/XMLSchema#boolean'; - else - inconclusive = true; - break; - - case 'a': - // Try to find an abbreviated predicate - if (match = this._shortPredicates.exec(input)) - type = 'abbreviation', value = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; - else - inconclusive = true; - break; - case '=': - // Try to find an implication arrow or equals sign - if (this._n3Mode && input.length > 1) { - type = 'abbreviation'; - if (input[1] !== '>') - matchLength = 1, value = 'http://www.w3.org/2002/07/owl#sameAs'; - else - matchLength = 2, value = 'http://www.w3.org/2000/10/swap/log#implies'; + // convert @list to triples + if(_isList(item)) { + _listToRDF(item['@list'], issuer, subject, predicate, rval); + } else { + // convert value or node object to triple + var object = _objectToRDF(item); + // skip null objects (they are relative IRIs) + if(object) { + rval.push({subject: subject, predicate: predicate, object: object}); + } } - break; - - case '!': - if (!this._n3Mode) - break; - case ',': - case ';': - case '[': - case ']': - case '(': - case ')': - case '{': - case '}': - // The next token is punctuation - matchLength = 1; - type = firstChar; - break; - - default: - inconclusive = true; - } - - // Some first characters do not allow an immediate decision, so inspect more - if (inconclusive) { - // Try to find a prefix - if ((this._prevTokenType === '@prefix' || this._prevTokenType === 'PREFIX') && - (match = this._prefix.exec(input))) - type = 'prefix', value = match[1] || ''; - // Try to find a prefixed name. Since it can contain (but not end with) a dot, - // we always need a non-dot character before deciding it is a prefixed name. - // Therefore, try inserting a space if we're at the end of the input. - else if ((match = this._prefixed.exec(input)) || - inputFinished && (match = this._prefixed.exec(input + ' '))) - type = 'prefixed', prefix = match[1] || '', value = this._unescape(match[2]); } + } + } - // A type token is special: it can only be emitted after an IRI or prefixed name is read - if (this._prevTokenType === '^^') { - switch (type) { - case 'prefixed': type = 'type'; break; - case 'IRI': type = 'typeIRI'; break; - default: type = ''; - } - } + return rval; +} - // What if nothing of the above was found? - if (!type) { - // We could be in streaming mode, and then we just wait for more input to arrive. - // Otherwise, a syntax error has occurred in the input. - // One exception: error on an unaccounted linebreak (= not inside a triple-quoted literal). - if (inputFinished || (!/^'''|^"""/.test(input) && /\n|\r/.test(input))) - return reportSyntaxError(this); - else - return this._input = input; - } +/** + * Converts a @list value into linked list of blank node RDF triples + * (an RDF collection). + * + * @param list the @list value. + * @param issuer a IdentifierIssuer for assigning blank node names. + * @param subject the subject for the head of the list. + * @param predicate the predicate for the head of the list. + * @param triples the array of triples to append to. + */ +function _listToRDF(list, issuer, subject, predicate, triples) { + var first = {type: 'IRI', value: RDF_FIRST}; + var rest = {type: 'IRI', value: RDF_REST}; + var nil = {type: 'IRI', value: RDF_NIL}; - // Emit the parsed token - callback(null, { line: line, type: type, value: value, prefix: prefix }); - this._prevTokenType = type; + for(var i = 0; i < list.length; ++i) { + var item = list[i]; - // Advance to next part to tokenize - input = input.substr(matchLength || match[0].length, input.length); - } + var blankNode = {type: 'blank node', value: issuer.getId()}; + triples.push({subject: subject, predicate: predicate, object: blankNode}); - // Signals the syntax error through the callback - function reportSyntaxError(self) { callback(self._syntaxError(/^\S*/.exec(input)[0])); } - }, + subject = blankNode; + predicate = first; + var object = _objectToRDF(item); - // ### `_unescape` replaces N3 escape codes by their corresponding characters - _unescape: function (item) { - try { - return item.replace(escapeSequence, function (sequence, unicode4, unicode8, escapedChar) { - var charCode; - if (unicode4) { - charCode = parseInt(unicode4, 16); - if (isNaN(charCode)) throw new Error(); // can never happen (regex), but helps performance - return fromCharCode(charCode); - } - else if (unicode8) { - charCode = parseInt(unicode8, 16); - if (isNaN(charCode)) throw new Error(); // can never happen (regex), but helps performance - if (charCode <= 0xFFFF) return fromCharCode(charCode); - return fromCharCode(0xD800 + ((charCode -= 0x10000) / 0x400), 0xDC00 + (charCode & 0x3FF)); - } - else { - var replacement = escapeReplacements[escapedChar]; - if (!replacement) - throw new Error(); - return replacement; - } - }); + // skip null objects (they are relative IRIs) + if(object) { + triples.push({subject: subject, predicate: predicate, object: object}); } - catch (error) { return null; } - }, - // ### `_syntaxError` creates a syntax error for the given issue - _syntaxError: function (issue) { - this._input = null; - return new Error('Unexpected "' + issue + '" on line ' + this._line + '.'); - }, + predicate = rest; + } + triples.push({subject: subject, predicate: predicate, object: nil}); +} - // ## Public methods +/** + * Converts a JSON-LD value object to an RDF literal or a JSON-LD string or + * node object to an RDF resource. + * + * @param item the JSON-LD value or node object. + * + * @return the RDF literal or RDF resource. + */ +function _objectToRDF(item) { + var object = {}; - // ### `tokenize` starts the transformation of an N3 document into an array of tokens. - // The input can be a string or a stream. - tokenize: function (input, callback) { - var self = this; - this._line = 1; + // convert value object to RDF + if(_isValue(item)) { + object.type = 'literal'; + var value = item['@value']; + var datatype = item['@type'] || null; - // If the input is a string, continuously emit tokens through the callback until the end - if (typeof input === 'string') { - this._input = input; - // If a callback was passed, asynchronously call it - if (typeof callback === 'function') - immediately(function () { self._tokenizeToEnd(callback, true); }); - // If no callback was passed, tokenize synchronously and return - else { - var tokens = [], error; - this._tokenizeToEnd(function (e, t) { e ? (error = e) : tokens.push(t); }, true); - if (error) throw error; - return tokens; + // convert to XSD datatypes as appropriate + if(_isBoolean(value)) { + object.value = value.toString(); + object.datatype = datatype || XSD_BOOLEAN; + } else if(_isDouble(value) || datatype === XSD_DOUBLE) { + if(!_isDouble(value)) { + value = parseFloat(value); } + // canonical double representation + object.value = value.toExponential(15).replace(/(\d)0*e\+?/, '$1E'); + object.datatype = datatype || XSD_DOUBLE; + } else if(_isNumber(value)) { + object.value = value.toFixed(0); + object.datatype = datatype || XSD_INTEGER; + } else if('@language' in item) { + object.value = value; + object.datatype = datatype || RDF_LANGSTRING; + object.language = item['@language']; + } else { + object.value = value; + object.datatype = datatype || XSD_STRING; } - // Otherwise, the input must be a stream - else { - this._input = ''; - if (typeof input.setEncoding === 'function') - input.setEncoding('utf8'); - // Adds the data chunk to the buffer and parses as far as possible - input.on('data', function (data) { - if (self._input !== null) { - self._input += data; - self._tokenizeToEnd(callback, false); - } - }); - // Parses until the end - input.on('end', function () { - if (self._input !== null) - self._tokenizeToEnd(callback, true); - }); - } - }, -}; + } else { + // convert string/node object to RDF + var id = _isObject(item) ? item['@id'] : item; + object.type = (id.indexOf('_:') === 0) ? 'blank node' : 'IRI'; + object.value = id; + } -// ## Exports -module.exports = N3Lexer; + // skip relative IRIs + if(object.type === 'IRI' && !_isAbsoluteIri(object.value)) { + return null; + } -},{}],27:[function(_dereq_,module,exports){ -// **N3Parser** parses N3 documents. -var N3Lexer = _dereq_('./N3Lexer'); + return object; +} -var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', - RDF_NIL = RDF_PREFIX + 'nil', - RDF_FIRST = RDF_PREFIX + 'first', - RDF_REST = RDF_PREFIX + 'rest'; +/** + * Converts an RDF triple object to a JSON-LD object. + * + * @param o the RDF triple object to convert. + * @param useNativeTypes true to output native types, false not to. + * + * @return the JSON-LD object. + */ +function _RDFToObject(o, useNativeTypes) { + // convert IRI/blank node object to JSON-LD + if(o.type === 'IRI' || o.type === 'blank node') { + return {'@id': o.value}; + } -var QUANTIFIERS_GRAPH = 'urn:n3:quantifiers'; - -var absoluteIRI = /^[a-z][a-z0-9+.-]*:/i, - schemeAuthority = /^(?:([a-z][a-z0-9+.-]*:))?(?:\/\/[^\/]*)?/i, - dotSegments = /(?:^|\/)\.\.?(?:$|[\/#?])/; - -// The next ID for new blank nodes -var blankNodePrefix = 0, blankNodeCount = 0; + // convert literal to JSON-LD + var rval = {'@value': o.value}; -// ## Constructor -function N3Parser(options) { - if (!(this instanceof N3Parser)) - return new N3Parser(options); - this._contextStack = []; - this._graph = null; + // add language + if(o.language) { + rval['@language'] = o.language; + } else { + var type = o.datatype; + if(!type) { + type = XSD_STRING; + } + // use native types for certain xsd types + if(useNativeTypes) { + if(type === XSD_BOOLEAN) { + if(rval['@value'] === 'true') { + rval['@value'] = true; + } else if(rval['@value'] === 'false') { + rval['@value'] = false; + } + } else if(_isNumeric(rval['@value'])) { + if(type === XSD_INTEGER) { + var i = parseInt(rval['@value'], 10); + if(i.toFixed(0) === rval['@value']) { + rval['@value'] = i; + } + } else if(type === XSD_DOUBLE) { + rval['@value'] = parseFloat(rval['@value']); + } + } + // do not add native type + if([XSD_BOOLEAN, XSD_INTEGER, XSD_DOUBLE, XSD_STRING] + .indexOf(type) === -1) { + rval['@type'] = type; + } + } else if(type !== XSD_STRING) { + rval['@type'] = type; + } + } - // Set the document IRI - options = options || {}; - this._setBase(options.documentIRI); + return rval; +} - // Set supported features depending on the format - var format = (typeof options.format === 'string') ? - options.format.match(/\w*$/)[0].toLowerCase() : '', - isTurtle = format === 'turtle', isTriG = format === 'trig', - isNTriples = /triple/.test(format), isNQuads = /quad/.test(format), - isN3 = this._n3Mode = /n3/.test(format), - isLineMode = isNTriples || isNQuads; - if (!(this._supportsNamedGraphs = !(isTurtle || isN3))) - this._readPredicateOrNamedGraph = this._readPredicate; - this._supportsQuads = !(isTurtle || isTriG || isNTriples || isN3); - // Disable relative IRIs in N-Triples or N-Quads mode - if (isLineMode) { - this._base = ''; - this._resolveIRI = function (token) { - this._error('Disallowed relative IRI', token); - return this._callback = noop, this._subject = null; - }; +/** + * Compares two RDF triples for equality. + * + * @param t1 the first triple. + * @param t2 the second triple. + * + * @return true if the triples are the same, false if not. + */ +function _compareRDFTriples(t1, t2) { + var attrs = ['subject', 'predicate', 'object']; + for(var i = 0; i < attrs.length; ++i) { + var attr = attrs[i]; + if(t1[attr].type !== t2[attr].type || t1[attr].value !== t2[attr].value) { + return false; + } } - this._blankNodePrefix = typeof options.blankNodePrefix !== 'string' ? '' : - '_:' + options.blankNodePrefix.replace(/^_:/, ''); - this._lexer = options.lexer || new N3Lexer({ lineMode: isLineMode, n3: isN3 }); - // Disable explicit quantifiers by default - this._explicitQuantifiers = !!options.explicitQuantifiers; + if(t1.object.language !== t2.object.language) { + return false; + } + if(t1.object.datatype !== t2.object.datatype) { + return false; + } + return true; } -// ## Private class methods +/////////////////////////////// DEFINE URDNA2015 ////////////////////////////// -// ### `_resetBlankNodeIds` restarts blank node identification -N3Parser._resetBlankNodeIds = function () { - blankNodePrefix = blankNodeCount = 0; +var URDNA2015 = (function() { + +var POSITIONS = {'subject': 's', 'object': 'o', 'name': 'g'}; + +var Normalize = function(options) { + options = options || {}; + this.name = 'URDNA2015'; + this.options = options; + this.blankNodeInfo = {}; + this.hashToBlankNodes = {}; + this.canonicalIssuer = new IdentifierIssuer('_:c14n'); + this.quads = []; + this.schedule = {}; + if('maxCallStackDepth' in options) { + this.schedule.MAX_DEPTH = options.maxCallStackDepth; + } else { + this.schedule.MAX_DEPTH = 500; + } + if('maxTotalCallStackDepth' in options) { + this.schedule.MAX_TOTAL_DEPTH = options.maxCallStackDepth; + } else { + this.schedule.MAX_TOTAL_DEPTH = 0xFFFFFFFF; + } + this.schedule.depth = 0; + this.schedule.totalDepth = 0; + if('timeSlice' in options) { + this.schedule.timeSlice = options.timeSlice; + } else { + // milliseconds + this.schedule.timeSlice = 10; + } }; -N3Parser.prototype = { - // ## Private methods +// do some work in a time slice, but in serial +Normalize.prototype.doWork = function(fn, callback) { + var schedule = this.schedule; - // ### `_setBase` sets the base IRI to resolve relative IRIs - _setBase: function (baseIRI) { - if (!baseIRI) - this._base = null; - else { - // Remove fragment if present - var fragmentPos = baseIRI.indexOf('#'); - if (fragmentPos >= 0) - baseIRI = baseIRI.substr(0, fragmentPos); - // Set base IRI and its components - this._base = baseIRI; - this._basePath = baseIRI.indexOf('/') < 0 ? baseIRI : - baseIRI.replace(/[^\/?]*(?:\?.*)?$/, ''); - baseIRI = baseIRI.match(schemeAuthority); - this._baseRoot = baseIRI[0]; - this._baseScheme = baseIRI[1]; + if(schedule.totalDepth >= schedule.MAX_TOTAL_DEPTH) { + return callback(new Error( + 'Maximum total call stack depth exceeded; normalization aborting.')); + } + + (function work() { + if(schedule.depth === schedule.MAX_DEPTH) { + // stack too deep, run on next tick + schedule.depth = 0; + schedule.running = false; + return jsonld.nextTick(work); } - }, - // ### `_saveContext` stores the current parsing context - // when entering a new scope (list, blank node, formula) - _saveContext: function (type, graph, subject, predicate, object) { - var n3Mode = this._n3Mode; - this._contextStack.push({ - subject: subject, predicate: predicate, object: object, - graph: graph, type: type, - inverse: n3Mode ? this._inversePredicate : false, - blankPrefix: n3Mode ? this._prefixes._ : '', - quantified: n3Mode ? this._quantified : null, - }); - // The settings below only apply to N3 streams - if (n3Mode) { - // Every new scope resets the predicate direction - this._inversePredicate = false; - // In N3, blank nodes are scoped to a formula - // (using a dot as separator, as a blank node label cannot start with it) - this._prefixes._ = this._graph + '.'; - // Quantifiers are scoped to a formula - this._quantified = Object.create(this._quantified); + // if not yet running, force run + var now = new Date().getTime(); + if(!schedule.running) { + schedule.start = new Date().getTime(); + schedule.deadline = schedule.start + schedule.timeSlice; } - }, - // ### `_restoreContext` restores the parent context - // when leaving a scope (list, blank node, formula) - _restoreContext: function () { - var context = this._contextStack.pop(), n3Mode = this._n3Mode; - this._subject = context.subject; - this._predicate = context.predicate; - this._object = context.object; - this._graph = context.graph; - // The settings below only apply to N3 streams - if (n3Mode) { - this._inversePredicate = context.inverse; - this._prefixes._ = context.blankPrefix; - this._quantified = context.quantified; + // TODO: should also include an estimate of expectedWorkTime + if(now < schedule.deadline) { + schedule.running = true; + schedule.depth++; + schedule.totalDepth++; + return fn(function(err, result) { + schedule.depth--; + schedule.totalDepth--; + callback(err, result); + }); } - }, - // ### `_readInTopContext` reads a token when in the top context - _readInTopContext: function (token) { - switch (token.type) { - // If an EOF token arrives in the top context, signal that we're done - case 'eof': - if (this._graph !== null) - return this._error('Unclosed graph', token); - delete this._prefixes._; - return this._callback(null, null, this._prefixes); - // It could be a prefix declaration - case 'PREFIX': - this._sparqlStyle = true; - case '@prefix': - return this._readPrefix; - // It could be a base declaration - case 'BASE': - this._sparqlStyle = true; - case '@base': - return this._readBaseIRI; - // It could be a graph - case '{': - if (this._supportsNamedGraphs) { - this._graph = ''; - this._subject = null; - return this._readSubject; + // not enough time left in this slice, run after letting browser + // do some other things + schedule.depth = 0; + schedule.running = false; + jsonld.setImmediate(work); + })(); +}; + +// asynchronously loop +Normalize.prototype.forEach = function(iterable, fn, callback) { + var self = this; + var iterator; + var idx = 0; + var length; + if(_isArray(iterable)) { + length = iterable.length; + iterator = function() { + if(idx === length) { + return false; } - case 'GRAPH': - if (this._supportsNamedGraphs) - return this._readNamedGraphLabel; - // Otherwise, the next token must be a subject - default: - return this._readSubject(token); - } - }, + iterator.value = iterable[idx++]; + iterator.key = idx; + return true; + }; + } else { + var keys = Object.keys(iterable); + length = keys.length; + iterator = function() { + if(idx === length) { + return false; + } + iterator.key = keys[idx++]; + iterator.value = iterable[iterator.key]; + return true; + }; + } - // ### `_readEntity` reads an IRI, prefixed name, blank node, or variable - _readEntity: function (token, quantifier) { - var value; - switch (token.type) { - // Read a relative or absolute IRI - case 'IRI': - case 'typeIRI': - value = (this._base === null || absoluteIRI.test(token.value)) ? - token.value : this._resolveIRI(token); - break; - // Read a blank node or prefixed name - case 'type': - case 'blank': - case 'prefixed': - var prefix = this._prefixes[token.prefix]; - if (prefix === undefined) - return this._error('Undefined prefix "' + token.prefix + ':"', token); - value = prefix + token.value; - break; - // Read a variable - case 'var': - return token.value; - // Everything else is not an entity - default: - return this._error('Expected entity but got ' + token.type, token); + (function iterate(err, result) { + if(err) { + return callback(err); } - // In N3 mode, replace the entity if it is quantified - if (!quantifier && this._n3Mode && (value in this._quantified)) - value = this._quantified[value]; - return value; - }, - - // ### `_readSubject` reads a triple's subject - _readSubject: function (token) { - this._predicate = null; - switch (token.type) { - case '[': - // Start a new triple with a new blank node as subject - this._saveContext('blank', this._graph, - this._subject = '_:b' + blankNodeCount++, null, null); - return this._readBlankNodeHead; - case '(': - // Start a new list - this._saveContext('list', this._graph, RDF_NIL, null, null); - this._subject = null; - return this._readListItem; - case '{': - // Start a new formula - if (!this._n3Mode) - return this._error('Unexpected graph', token); - this._saveContext('formula', this._graph, - this._graph = '_:b' + blankNodeCount++, null, null); - return this._readSubject; - case '}': - // No subject; the graph in which we are reading is closed instead - return this._readPunctuation(token); - case '@forSome': - this._subject = null; - this._predicate = 'http://www.w3.org/2000/10/swap/reify#forSome'; - this._quantifiedPrefix = '_:b'; - return this._readQuantifierList; - case '@forAll': - this._subject = null; - this._predicate = 'http://www.w3.org/2000/10/swap/reify#forAll'; - this._quantifiedPrefix = '?b-'; - return this._readQuantifierList; - default: - // Read the subject entity - if ((this._subject = this._readEntity(token)) === undefined) - return; - // In N3 mode, the subject might be a path - if (this._n3Mode) - return this._getPathReader(this._readPredicateOrNamedGraph); + if(iterator()) { + return self.doWork(function() { + fn(iterator.value, iterator.key, iterate); + }); } + callback(); + })(); +}; - // The next token must be a predicate, - // or, if the subject was actually a graph IRI, a named graph - return this._readPredicateOrNamedGraph; - }, +// asynchronous waterfall +Normalize.prototype.waterfall = function(fns, callback) { + var self = this; + self.forEach(fns, function(fn, idx, callback) { + self.doWork(fn, callback); + }, callback); +}; - // ### `_readPredicate` reads a triple's predicate - _readPredicate: function (token) { - var type = token.type; - switch (type) { - case 'inverse': - this._inversePredicate = true; - case 'abbreviation': - this._predicate = token.value; - break; - case '.': - case ']': - case '}': - // Expected predicate didn't come, must have been trailing semicolon - if (this._predicate === null) - return this._error('Unexpected ' + type, token); - this._subject = null; - return type === ']' ? this._readBlankNodeTail(token) : this._readPunctuation(token); - case ';': - // Extra semicolons can be safely ignored - return this._readPredicate; - case 'blank': - if (!this._n3Mode) - return this._error('Disallowed blank node as predicate', token); - default: - if ((this._predicate = this._readEntity(token)) === undefined) - return; +// asynchronous while +Normalize.prototype.whilst = function(condition, fn, callback) { + var self = this; + (function loop(err) { + if(err) { + return callback(err); } - // The next token must be an object - return this._readObject; - }, - - // ### `_readObject` reads a triple's object - _readObject: function (token) { - switch (token.type) { - case 'literal': - this._object = token.value; - return this._readDataTypeOrLang; - case '[': - // Start a new triple with a new blank node as subject - this._saveContext('blank', this._graph, this._subject, this._predicate, - this._subject = '_:b' + blankNodeCount++); - return this._readBlankNodeHead; - case '(': - // Start a new list - this._saveContext('list', this._graph, this._subject, this._predicate, RDF_NIL); - this._subject = null; - return this._readListItem; - case '{': - // Start a new formula - if (!this._n3Mode) - return this._error('Unexpected graph', token); - this._saveContext('formula', this._graph, this._subject, this._predicate, - this._graph = '_:b' + blankNodeCount++); - return this._readSubject; - default: - // Read the object entity - if ((this._object = this._readEntity(token)) === undefined) - return; - // In N3 mode, the object might be a path - if (this._n3Mode) - return this._getPathReader(this._getContextEndReader()); + if(!condition()) { + return callback(); } - return this._getContextEndReader(); - }, - - // ### `_readPredicateOrNamedGraph` reads a triple's predicate, or a named graph - _readPredicateOrNamedGraph: function (token) { - return token.type === '{' ? this._readGraph(token) : this._readPredicate(token); - }, + self.doWork(fn, loop); + })(); +}; - // ### `_readGraph` reads a graph - _readGraph: function (token) { - if (token.type !== '{') - return this._error('Expected graph but got ' + token.type, token); - // The "subject" we read is actually the GRAPH's label - this._graph = this._subject, this._subject = null; - return this._readSubject; - }, +// 4.4) Normalization Algorithm +Normalize.prototype.main = function(dataset, callback) { + var self = this; + self.schedule.start = new Date().getTime(); + var result; - // ### `_readBlankNodeHead` reads the head of a blank node - _readBlankNodeHead: function (token) { - if (token.type === ']') { - this._subject = null; - return this._readBlankNodeTail(token); - } - else { - this._predicate = null; - return this._readPredicate(token); + // handle invalid output format + if(self.options.format) { + if(self.options.format !== 'application/nquads') { + return callback(new JsonLdError( + 'Unknown output format.', + 'jsonld.UnknownFormat', {format: self.options.format})); } - }, - - // ### `_readBlankNodeTail` reads the end of a blank node - _readBlankNodeTail: function (token) { - if (token.type !== ']') - return this._readBlankNodePunctuation(token); + } - // Store blank node triple - if (this._subject !== null) - this._triple(this._subject, this._predicate, this._object, this._graph); + // 1) Create the normalization state. - // Restore the parent context containing this blank node - var empty = this._predicate === null; - this._restoreContext(); - // If the blank node was the subject, continue reading the predicate - if (this._object === null) - // If the blank node was empty, it could be a named graph label - return empty ? this._readPredicateOrNamedGraph : this._readPredicateAfterBlank; - // If the blank node was the object, restore previous context and read punctuation - else - return this._getContextEndReader(); - }, + // Note: Optimize by generating non-normalized blank node map concurrently. + var nonNormalized = {}; - // ### `_readPredicateAfterBlank` reads a predicate after an anonymous blank node - _readPredicateAfterBlank: function (token) { - // If a dot follows a blank node in top context, there is no predicate - if (token.type === '.' && !this._contextStack.length) { - this._subject = null; // cancel the current triple - return this._readPunctuation(token); - } - return this._readPredicate(token); - }, - - // ### `_readListItem` reads items from a list - _readListItem: function (token) { - var item = null, // The item of the list - list = null, // The list itself - prevList = this._subject, // The previous list that contains this list - stack = this._contextStack, // The stack of parent contexts - parent = stack[stack.length - 1], // The parent containing the current list - next = this._readListItem, // The next function to execute - itemComplete = true; // Whether the item has been read fully + self.waterfall([ + function(callback) { + // 2) For every quad in input dataset: + self.forEach(dataset, function(triples, graphName, callback) { + if(graphName === '@default') { + graphName = null; + } + self.forEach(triples, function(quad, idx, callback) { + if(graphName !== null) { + if(graphName.indexOf('_:') === 0) { + quad.name = {type: 'blank node', value: graphName}; + } else { + quad.name = {type: 'IRI', value: graphName}; + } + } + self.quads.push(quad); - switch (token.type) { - case '[': - // Stack the current list triple and start a new triple with a blank node as subject - this._saveContext('blank', this._graph, list = '_:b' + blankNodeCount++, - RDF_FIRST, this._subject = item = '_:b' + blankNodeCount++); - next = this._readBlankNodeHead; - break; - case '(': - // Stack the current list triple and start a new list - this._saveContext('list', this._graph, list = '_:b' + blankNodeCount++, - RDF_FIRST, RDF_NIL); - this._subject = null; - break; - case ')': - // Closing the list; restore the parent context - this._restoreContext(); - // If this list is contained within a parent list, return the membership triple here. - // This will be ` rdf:first .`. - if (stack.length !== 0 && stack[stack.length - 1].type === 'list') - this._triple(this._subject, this._predicate, this._object, this._graph); - // Was this list the parent's subject? - if (this._predicate === null) { - // The next token is the predicate - next = this._readPredicate; - // No list tail if this was an empty list - if (this._subject === RDF_NIL) - return next; - } - // The list was in the parent context's object - else { - next = this._getContextEndReader(); - // No list tail if this was an empty list - if (this._object === RDF_NIL) - return next; - } - // Close the list by making the head nil - list = RDF_NIL; - break; - case 'literal': - item = token.value; - itemComplete = false; // Can still have a datatype or language - next = this._readListItemDataTypeOrLang; - break; - default: - if ((item = this._readEntity(token)) === undefined) - return; - } + // 2.1) For each blank node that occurs in the quad, add a reference + // to the quad using the blank node identifier in the blank node to + // quads map, creating a new entry if necessary. + self.forEachComponent(quad, function(component) { + if(component.type !== 'blank node') { + return; + } + var id = component.value; + if(id in self.blankNodeInfo) { + self.blankNodeInfo[id].quads.push(quad); + } else { + nonNormalized[id] = true; + self.blankNodeInfo[id] = {quads: [quad]}; + } + }); + callback(); + }, callback); + }, callback); + }, + function(callback) { + // 3) Create a list of non-normalized blank node identifiers + // non-normalized identifiers and populate it using the keys from the + // blank node to quads map. + // Note: We use a map here and it was generated during step 2. - // Create a new blank node if no item head was assigned yet - if (list === null) - this._subject = list = '_:b' + blankNodeCount++; + // 4) Initialize simple, a boolean flag, to true. + var simple = true; - // Is this the first element of the list? - if (prevList === null) { - // This list is either the subject or the object of its parent - if (parent.predicate === null) - parent.subject = list; - else - parent.object = list; - } - else { - // Continue the previous list with the current list - this._triple(prevList, RDF_REST, list, this._graph); - } - // Add the item's value - if (item !== null) { - // In N3 mode, the item might be a path - if (this._n3Mode && (token.type === 'IRI' || token.type === 'prefixed')) { - // Create a new context to add the item's path - this._saveContext('item', this._graph, list, RDF_FIRST, item); - this._subject = item, this._predicate = null; - // _readPath will restore the context and output the item - return this._getPathReader(this._readListItem); - } - // Output the item if it is complete - if (itemComplete) - this._triple(list, RDF_FIRST, item, this._graph); - // Otherwise, save it for completion - else - this._object = item; - } - return next; - }, + // 5) While simple is true, issue canonical identifiers for blank nodes: + self.whilst(function() { return simple; }, function(callback) { + // 5.1) Set simple to false. + simple = false; - // ### `_readDataTypeOrLang` reads an _optional_ data type or language - _readDataTypeOrLang: function (token) { - return this._completeLiteral(token, false); - }, + // 5.2) Clear hash to blank nodes map. + self.hashToBlankNodes = {}; - // ### `_readListItemDataTypeOrLang` reads an _optional_ data type or language in a list - _readListItemDataTypeOrLang: function (token) { - return this._completeLiteral(token, true); - }, + self.waterfall([ + function(callback) { + // 5.3) For each blank node identifier identifier in non-normalized + // identifiers: + self.forEach(nonNormalized, function(value, id, callback) { + // 5.3.1) Create a hash, hash, according to the Hash First Degree + // Quads algorithm. + self.hashFirstDegreeQuads(id, function(err, hash) { + if(err) { + return callback(err); + } + // 5.3.2) Add hash and identifier to hash to blank nodes map, + // creating a new entry if necessary. + if(hash in self.hashToBlankNodes) { + self.hashToBlankNodes[hash].push(id); + } else { + self.hashToBlankNodes[hash] = [id]; + } + callback(); + }); + }, callback); + }, + function(callback) { + // 5.4) For each hash to identifier list mapping in hash to blank + // nodes map, lexicographically-sorted by hash: + var hashes = Object.keys(self.hashToBlankNodes).sort(); + self.forEach(hashes, function(hash, i, callback) { + // 5.4.1) If the length of identifier list is greater than 1, + // continue to the next mapping. + var idList = self.hashToBlankNodes[hash]; + if(idList.length > 1) { + return callback(); + } - // ### `_completeLiteral` completes the object with a data type or language - _completeLiteral: function (token, listItem) { - var suffix = false; - switch (token.type) { - // Add a "^^type" suffix for types (IRIs and blank nodes) - case 'type': - case 'typeIRI': - suffix = true; - this._object += '^^' + this._readEntity(token); - break; - // Add an "@lang" suffix for language tags - case 'langcode': - suffix = true; - this._object += '@' + token.value.toLowerCase(); - break; - } - // If this literal was part of a list, write the item - // (we could also check the context stack, but passing in a flag is faster) - if (listItem) - this._triple(this._subject, RDF_FIRST, this._object, this._graph); - // Continue with the rest of the input - if (suffix) - return this._getContextEndReader(); - else { - this._readCallback = this._getContextEndReader(); - return this._readCallback(token); - } - }, + // 5.4.2) Use the Issue Identifier algorithm, passing canonical + // issuer and the single blank node identifier in identifier + // list, identifier, to issue a canonical replacement identifier + // for identifier. + // TODO: consider changing `getId` to `issue` + var id = idList[0]; + self.canonicalIssuer.getId(id); - // ### `_readFormulaTail` reads the end of a formula - _readFormulaTail: function (token) { - if (token.type !== '}') - return this._readPunctuation(token); + // 5.4.3) Remove identifier from non-normalized identifiers. + delete nonNormalized[id]; - // Store the last triple of the formula - if (this._subject !== null) - this._triple(this._subject, this._predicate, this._object, this._graph); + // 5.4.4) Remove hash from the hash to blank nodes map. + delete self.hashToBlankNodes[hash]; - // Restore the parent context containing this formula - this._restoreContext(); - // If the formula was the subject, continue reading the predicate. - // If the formula was the object, read punctuation. - return this._object === null ? this._readPredicate : this._getContextEndReader(); - }, + // 5.4.5) Set simple to true. + simple = true; + callback(); + }, callback); + } + ], callback); + }, callback); + }, + function(callback) { + // 6) For each hash to identifier list mapping in hash to blank nodes map, + // lexicographically-sorted by hash: + var hashes = Object.keys(self.hashToBlankNodes).sort(); + self.forEach(hashes, function(hash, idx, callback) { + // 6.1) Create hash path list where each item will be a result of + // running the Hash N-Degree Quads algorithm. + var hashPathList = []; - // ### `_readPunctuation` reads punctuation between triples or triple parts - _readPunctuation: function (token) { - var next, subject = this._subject, graph = this._graph, - inversePredicate = this._inversePredicate; - switch (token.type) { - // A closing brace ends a graph - case '}': - if (this._graph === null) - return this._error('Unexpected graph closing', token); - if (this._n3Mode) - return this._readFormulaTail(token); - this._graph = null; - // A dot just ends the statement, without sharing anything with the next - case '.': - this._subject = null; - next = this._contextStack.length ? this._readSubject : this._readInTopContext; - if (inversePredicate) this._inversePredicate = false; - break; - // Semicolon means the subject is shared; predicate and object are different - case ';': - next = this._readPredicate; - break; - // Comma means both the subject and predicate are shared; the object is different - case ',': - next = this._readObject; - break; - default: - // An entity means this is a quad (only allowed if not already inside a graph) - if (this._supportsQuads && this._graph === null && (graph = this._readEntity(token)) !== undefined) { - next = this._readQuadPunctuation; - break; - } - return this._error('Expected punctuation to follow "' + this._object + '"', token); - } - // A triple has been completed now, so return it - if (subject !== null) { - var predicate = this._predicate, object = this._object; - if (!inversePredicate) - this._triple(subject, predicate, object, graph); - else - this._triple(object, predicate, subject, graph); - } - return next; - }, + // 6.2) For each blank node identifier identifier in identifier list: + var idList = self.hashToBlankNodes[hash]; + self.waterfall([ + function(callback) { + self.forEach(idList, function(id, idx, callback) { + // 6.2.1) If a canonical identifier has already been issued for + // identifier, continue to the next identifier. + if(self.canonicalIssuer.hasId(id)) { + return callback(); + } - // ### `_readBlankNodePunctuation` reads punctuation in a blank node - _readBlankNodePunctuation: function (token) { - var next; - switch (token.type) { - // Semicolon means the subject is shared; predicate and object are different - case ';': - next = this._readPredicate; - break; - // Comma means both the subject and predicate are shared; the object is different - case ',': - next = this._readObject; - break; - default: - return this._error('Expected punctuation to follow "' + this._object + '"', token); - } - // A triple has been completed now, so return it - this._triple(this._subject, this._predicate, this._object, this._graph); - return next; - }, + // 6.2.2) Create temporary issuer, an identifier issuer + // initialized with the prefix _:b. + var issuer = new IdentifierIssuer('_:b'); - // ### `_readQuadPunctuation` reads punctuation after a quad - _readQuadPunctuation: function (token) { - if (token.type !== '.') - return this._error('Expected dot to follow quad', token); - return this._readInTopContext; - }, + // 6.2.3) Use the Issue Identifier algorithm, passing temporary + // issuer and identifier, to issue a new temporary blank node + // identifier for identifier. + issuer.getId(id); - // ### `_readPrefix` reads the prefix of a prefix declaration - _readPrefix: function (token) { - if (token.type !== 'prefix') - return this._error('Expected prefix to follow @prefix', token); - this._prefix = token.value; - return this._readPrefixIRI; - }, + // 6.2.4) Run the Hash N-Degree Quads algorithm, passing + // temporary issuer, and append the result to the hash path list. + self.hashNDegreeQuads(id, issuer, function(err, result) { + if(err) { + return callback(err); + } + hashPathList.push(result); + callback(); + }); + }, callback); + }, + function(callback) { + // 6.3) For each result in the hash path list, + // lexicographically-sorted by the hash in result: + hashPathList.sort(function(a, b) { + return (a.hash < b.hash) ? -1 : ((a.hash > b.hash) ? 1 : 0); + }); + self.forEach(hashPathList, function(result, idx, callback) { + // 6.3.1) For each blank node identifier, existing identifier, + // that was issued a temporary identifier by identifier issuer + // in result, issue a canonical identifier, in the same order, + // using the Issue Identifier algorithm, passing canonical + // issuer and existing identifier. + for(var existing in result.issuer.existing) { + self.canonicalIssuer.getId(existing); + } + callback(); + }, callback); + } + ], callback); + }, callback); + }, function(callback) { + /* Note: At this point all blank nodes in the set of RDF quads have been + assigned canonical identifiers, which have been stored in the canonical + issuer. Here each quad is updated by assigning each of its blank nodes + its new identifier. */ - // ### `_readPrefixIRI` reads the IRI of a prefix declaration - _readPrefixIRI: function (token) { - if (token.type !== 'IRI') - return this._error('Expected IRI to follow prefix "' + this._prefix + ':"', token); - var prefixIRI = this._readEntity(token); - this._prefixes[this._prefix] = prefixIRI; - this._prefixCallback(this._prefix, prefixIRI); - return this._readDeclarationPunctuation; - }, + // 7) For each quad, quad, in input dataset: + var normalized = []; + self.waterfall([ + function(callback) { + self.forEach(self.quads, function(quad, idx, callback) { + // 7.1) Create a copy, quad copy, of quad and replace any existing + // blank node identifiers using the canonical identifiers + // previously issued by canonical issuer. + // Note: We optimize away the copy here. + self.forEachComponent(quad, function(component) { + if(component.type === 'blank node' && + component.value.indexOf(self.canonicalIssuer.prefix) !== 0) { + component.value = self.canonicalIssuer.getId(component.value); + } + }); + // 7.2) Add quad copy to the normalized dataset. + normalized.push(_toNQuad(quad)); + callback(); + }, callback); + }, + function(callback) { + // sort normalized output + normalized.sort(); - // ### `_readBaseIRI` reads the IRI of a base declaration - _readBaseIRI: function (token) { - if (token.type !== 'IRI') - return this._error('Expected IRI to follow base declaration', token); - this._setBase(this._base === null || absoluteIRI.test(token.value) ? - token.value : this._resolveIRI(token)); - return this._readDeclarationPunctuation; - }, + // 8) Return the normalized dataset. + if(self.options.format === 'application/nquads') { + result = normalized.join(''); + return callback(); + } - // ### `_readNamedGraphLabel` reads the label of a named graph - _readNamedGraphLabel: function (token) { - switch (token.type) { - case 'IRI': - case 'blank': - case 'prefixed': - return this._readSubject(token), this._readGraph; - case '[': - return this._readNamedGraphBlankLabel; - default: - return this._error('Invalid graph label', token); + result = _parseNQuads(normalized.join('')); + callback(); + } + ], callback); } - }, + ], function(err) { + callback(err, result); + }); +}; - // ### `_readNamedGraphLabel` reads a blank node label of a named graph - _readNamedGraphBlankLabel: function (token) { - if (token.type !== ']') - return this._error('Invalid graph label', token); - this._subject = '_:b' + blankNodeCount++; - return this._readGraph; - }, +// 4.6) Hash First Degree Quads +Normalize.prototype.hashFirstDegreeQuads = function(id, callback) { + var self = this; - // ### `_readDeclarationPunctuation` reads the punctuation of a declaration - _readDeclarationPunctuation: function (token) { - // SPARQL-style declarations don't have punctuation - if (this._sparqlStyle) { - this._sparqlStyle = false; - return this._readInTopContext(token); - } + // return cached hash + var info = self.blankNodeInfo[id]; + if('hash' in info) { + return callback(null, info.hash); + } - if (token.type !== '.') - return this._error('Expected declaration to end with a dot', token); - return this._readInTopContext; - }, + // 1) Initialize nquads to an empty list. It will be used to store quads in + // N-Quads format. + var nquads = []; - // Reads a list of quantified symbols from a @forSome or @forAll statement - _readQuantifierList: function (token) { - var entity; - switch (token.type) { - case 'IRI': - case 'prefixed': - if ((entity = this._readEntity(token, true)) !== undefined) - break; - default: - return this._error('Unexpected ' + token.type, token); - } - // Without explicit quantifiers, map entities to a quantified entity - if (!this._explicitQuantifiers) - this._quantified[entity] = this._quantifiedPrefix + blankNodeCount++; - // With explicit quantifiers, output the reified quantifier - else { - // If this is the first item, start a new quantifier list - if (this._subject === null) - this._triple(this._graph || '', this._predicate, - this._subject = '_:b' + blankNodeCount++, QUANTIFIERS_GRAPH); - // Otherwise, continue the previous list - else - this._triple(this._subject, RDF_REST, - this._subject = '_:b' + blankNodeCount++, QUANTIFIERS_GRAPH); - // Output the list item - this._triple(this._subject, RDF_FIRST, entity, QUANTIFIERS_GRAPH); - } - return this._readQuantifierPunctuation; - }, + // 2) Get the list of quads quads associated with the reference blank node + // identifier in the blank node to quads map. + var quads = info.quads; - // Reads punctuation from a @forSome or @forAll statement - _readQuantifierPunctuation: function (token) { - // Read more quantifiers - if (token.type === ',') - return this._readQuantifierList; - // End of the quantifier list - else { - // With explicit quantifiers, close the quantifier list - if (this._explicitQuantifiers) { - this._triple(this._subject, RDF_REST, RDF_NIL, QUANTIFIERS_GRAPH); - this._subject = null; - } - // Read a dot - this._readCallback = this._getContextEndReader(); - return this._readCallback(token); - } - }, - - // ### `_getPathReader` reads a potential path and then resumes with the given function - _getPathReader: function (afterPath) { - this._afterPath = afterPath; - return this._readPath; - }, + // 3) For each quad quad in quads: + self.forEach(quads, function(quad, idx, callback) { + // 3.1) Serialize the quad in N-Quads format with the following special + // rule: - // ### `_readPath` reads a potential path - _readPath: function (token) { - switch (token.type) { - // Forward path - case '!': return this._readForwardPath; - // Backward path - case '^': return this._readBackwardPath; - // Not a path; resume reading where we left off - default: - var stack = this._contextStack, parent = stack.length && stack[stack.length - 1]; - // If we were reading a list item, we still need to output it - if (parent && parent.type === 'item') { - // The list item is the remaining subejct after reading the path - var item = this._subject; - // Switch back to the context of the list - this._restoreContext(); - // Output the list item - this._triple(this._subject, RDF_FIRST, item, this._graph); - } - return this._afterPath(token); + // 3.1.1) If any component in quad is an blank node, then serialize it + // using a special identifier as follows: + var copy = {predicate: quad.predicate}; + self.forEachComponent(quad, function(component, key) { + // 3.1.2) If the blank node's existing blank node identifier matches the + // reference blank node identifier then use the blank node identifier _:a, + // otherwise, use the blank node identifier _:z. + copy[key] = self.modifyFirstDegreeComponent(id, component, key); + }); + nquads.push(_toNQuad(copy)); + callback(); + }, function(err) { + if(err) { + return callback(err); } - }, + // 4) Sort nquads in lexicographical order. + nquads.sort(); - // ### `_readForwardPath` reads a '!' path - _readForwardPath: function (token) { - var subject, predicate, object = '_:b' + blankNodeCount++; - // The next token is the predicate - if ((predicate = this._readEntity(token)) === undefined) - return; - // If we were reading a subject, replace the subject by the path's object - if (this._predicate === null) - subject = this._subject, this._subject = object; - // If we were reading an object, replace the subject by the path's object - else - subject = this._object, this._object = object; - // Emit the path's current triple and read its next section - this._triple(subject, predicate, object, this._graph); - return this._readPath; - }, + // 5) Return the hash that results from passing the sorted, joined nquads + // through the hash algorithm. + info.hash = NormalizeHash.hashNQuads(self.name, nquads); + callback(null, info.hash); + }); +}; - // ### `_readBackwardPath` reads a '^' path - _readBackwardPath: function (token) { - var subject = '_:b' + blankNodeCount++, predicate, object; - // The next token is the predicate - if ((predicate = this._readEntity(token)) === undefined) - return; - // If we were reading a subject, replace the subject by the path's subject - if (this._predicate === null) - object = this._subject, this._subject = subject; - // If we were reading an object, replace the subject by the path's subject - else - object = this._object, this._object = subject; - // Emit the path's current triple and read its next section - this._triple(subject, predicate, object, this._graph); - return this._readPath; - }, +// helper for modifying component during Hash First Degree Quads +Normalize.prototype.modifyFirstDegreeComponent = function(id, component) { + if(component.type !== 'blank node') { + return component; + } + component = _clone(component); + component.value = (component.value === id ? '_:a' : '_:z'); + return component; +}; - // ### `_getContextEndReader` gets the next reader function at the end of a context - _getContextEndReader: function () { - var contextStack = this._contextStack; - if (!contextStack.length) - return this._readPunctuation; +// 4.7) Hash Related Blank Node +Normalize.prototype.hashRelatedBlankNode = function( + related, quad, issuer, position, callback) { + var self = this; - switch (contextStack[contextStack.length - 1].type) { - case 'blank': - return this._readBlankNodeTail; - case 'list': - return this._readListItem; - case 'formula': - return this._readFormulaTail; + // 1) Set the identifier to use for related, preferring first the canonical + // identifier for related if issued, second the identifier issued by issuer + // if issued, and last, if necessary, the result of the Hash First Degree + // Quads algorithm, passing related. + var id; + self.waterfall([ + function(callback) { + if(self.canonicalIssuer.hasId(related)) { + id = self.canonicalIssuer.getId(related); + return callback(); + } + if(issuer.hasId(related)) { + id = issuer.getId(related); + return callback(); + } + self.hashFirstDegreeQuads(related, function(err, hash) { + if(err) { + return callback(err); + } + id = hash; + callback(); + }); + } + ], function(err) { + if(err) { + return callback(err); } - }, - - // ### `_triple` emits a triple through the callback - _triple: function (subject, predicate, object, graph) { - this._callback(null, - { subject: subject, predicate: predicate, object: object, graph: graph || '' }); - }, - // ### `_error` emits an error message through the callback - _error: function (message, token) { - this._callback(new Error(message + ' on line ' + token.line + '.')); - }, + // 2) Initialize a string input to the value of position. + // Note: We use a hash object instead. + var md = new NormalizeHash(self.name); + md.update(position); - // ### `_resolveIRI` resolves a relative IRI token against the base path, - // assuming that a base path has been set and that the IRI is indeed relative - _resolveIRI: function (token) { - var iri = token.value; - switch (iri[0]) { - // An empty relative IRI indicates the base IRI - case undefined: return this._base; - // Resolve relative fragment IRIs against the base IRI - case '#': return this._base + iri; - // Resolve relative query string IRIs by replacing the query string - case '?': return this._base.replace(/(?:\?.*)?$/, iri); - // Resolve root-relative IRIs at the root of the base IRI - case '/': - // Resolve scheme-relative IRIs to the scheme - return (iri[1] === '/' ? this._baseScheme : this._baseRoot) + this._removeDotSegments(iri); - // Resolve all other IRIs at the base IRI's path - default: - return this._removeDotSegments(this._basePath + iri); + // 3) If position is not g, append <, the value of the predicate in quad, + // and > to input. + if(position !== 'g') { + md.update(self.getRelatedPredicate(quad)); } - }, - - // ### `_removeDotSegments` resolves './' and '../' path segments in an IRI as per RFC3986 - _removeDotSegments: function (iri) { - // Don't modify the IRI if it does not contain any dot segments - if (!dotSegments.test(iri)) - return iri; - // Start with an imaginary slash before the IRI in order to resolve trailing './' and '../' - var result = '', length = iri.length, i = -1, pathStart = -1, segmentStart = 0, next = '/'; + // 4) Append identifier to input. + md.update(id); - while (i < length) { - switch (next) { - // The path starts with the first slash after the authority - case ':': - if (pathStart < 0) { - // Skip two slashes before the authority - if (iri[++i] === '/' && iri[++i] === '/') - // Skip to slash after the authority - while ((pathStart = i + 1) < length && iri[pathStart] !== '/') - i = pathStart; - } - break; - // Don't modify a query string or fragment - case '?': - case '#': - i = length; - break; - // Handle '/.' or '/..' path segments - case '/': - if (iri[i + 1] === '.') { - next = iri[++i + 1]; - switch (next) { - // Remove a '/.' segment - case '/': - result += iri.substring(segmentStart, i - 1); - segmentStart = i + 1; - break; - // Remove a trailing '/.' segment - case undefined: - case '?': - case '#': - return result + iri.substring(segmentStart, i) + iri.substr(i + 1); - // Remove a '/..' segment - case '.': - next = iri[++i + 1]; - if (next === undefined || next === '/' || next === '?' || next === '#') { - result += iri.substring(segmentStart, i - 2); - // Try to remove the parent path from result - if ((segmentStart = result.lastIndexOf('/')) >= pathStart) - result = result.substr(0, segmentStart); - // Remove a trailing '/..' segment - if (next !== '/') - return result + '/' + iri.substr(i + 1); - segmentStart = i + 1; - } - } - } - } - next = iri[++i]; - } - return result + iri.substring(segmentStart); - }, + // 5) Return the hash that results from passing input through the hash + // algorithm. + return callback(null, md.digest()); + }); +}; - // ## Public methods +// helper for getting a related predicate +Normalize.prototype.getRelatedPredicate = function(quad) { + return '<' + quad.predicate.value + '>'; +}; - // ### `parse` parses the N3 input and emits each parsed triple through the callback - parse: function (input, tripleCallback, prefixCallback) { - var self = this; - // The read callback is the next function to be executed when a token arrives. - // We start reading in the top context. - this._readCallback = this._readInTopContext; - this._sparqlStyle = false; - this._prefixes = Object.create(null); - this._prefixes._ = this._blankNodePrefix || '_:b' + blankNodePrefix++ + '_'; - this._prefixCallback = prefixCallback || noop; - this._inversePredicate = false; - this._quantified = Object.create(null); +// 4.8) Hash N-Degree Quads +Normalize.prototype.hashNDegreeQuads = function(id, issuer, callback) { + var self = this; - // Parse synchronously if no triple callback is given - if (!tripleCallback) { - var triples = [], error; - this._callback = function (e, t) { e ? (error = e) : t && triples.push(t); }; - this._lexer.tokenize(input).every(function (token) { - return self._readCallback = self._readCallback(token); + // 1) Create a hash to related blank nodes map for storing hashes that + // identify related blank nodes. + // Note: 2) and 3) handled within `createHashToRelated` + var hashToRelated; + var md = new NormalizeHash(self.name); + self.waterfall([ + function(callback) { + self.createHashToRelated(id, issuer, function(err, result) { + if(err) { + return callback(err); + } + hashToRelated = result; + callback(); }); - if (error) throw error; - return triples; - } + }, + function(callback) { + // 4) Create an empty string, data to hash. + // Note: We created a hash object `md` above instead. - // Parse asynchronously otherwise, executing the read callback when a token arrives - this._callback = tripleCallback; - this._lexer.tokenize(input, function (error, token) { - if (error !== null) - self._callback(error), self._callback = noop; - else if (self._readCallback) - self._readCallback = self._readCallback(token); - }); - }, -}; + // 5) For each related hash to blank node list mapping in hash to related + // blank nodes map, sorted lexicographically by related hash: + var hashes = Object.keys(hashToRelated).sort(); + self.forEach(hashes, function(hash, idx, callback) { + // 5.1) Append the related hash to the data to hash. + md.update(hash); -// The empty function -function noop() {} + // 5.2) Create a string chosen path. + var chosenPath = ''; -// ## Exports -module.exports = N3Parser; + // 5.3) Create an unset chosen issuer variable. + var chosenIssuer; -},{"./N3Lexer":26}],28:[function(_dereq_,module,exports){ -// **N3Store** objects store N3 triples by graph in memory. + // 5.4) For each permutation of blank node list: + var permutator = new Permutator(hashToRelated[hash]); + self.whilst( + function() { return permutator.hasNext(); }, + function(nextPermutation) { + var permutation = permutator.next(); -var expandPrefixedName = _dereq_('./N3Util').expandPrefixedName; + // 5.4.1) Create a copy of issuer, issuer copy. + var issuerCopy = issuer.clone(); -// ## Constructor -function N3Store(triples, options) { - if (!(this instanceof N3Store)) - return new N3Store(triples, options); + // 5.4.2) Create a string path. + var path = ''; - // The number of triples is initially zero - this._size = 0; - // `_graphs` contains subject, predicate, and object indexes per graph - this._graphs = Object.create(null); - // `_ids` maps entities such as `http://xmlns.com/foaf/0.1/name` to numbers, - // saving memory by using only numbers as keys in `_graphs` - this._id = 0; - this._ids = Object.create(null); - this._ids['><'] = 0; // dummy entry, so the first actual key is non-zero - this._entities = Object.create(null); // inverse of `_ids` - // `_blankNodeIndex` is the index of the last automatically named blank node - this._blankNodeIndex = 0; + // 5.4.3) Create a recursion list, to store blank node identifiers + // that must be recursively processed by this algorithm. + var recursionList = []; - // Shift parameters if `triples` is not given - if (!options && triples && !triples[0]) - options = triples, triples = null; - options = options || {}; + self.waterfall([ + function(callback) { + // 5.4.4) For each related in permutation: + self.forEach(permutation, function(related, idx, callback) { + // 5.4.4.1) If a canonical identifier has been issued for + // related, append it to path. + if(self.canonicalIssuer.hasId(related)) { + path += self.canonicalIssuer.getId(related); + } else { + // 5.4.4.2) Otherwise: + // 5.4.4.2.1) If issuer copy has not issued an identifier for + // related, append related to recursion list. + if(!issuerCopy.hasId(related)) { + recursionList.push(related); + } + // 5.4.4.2.2) Use the Issue Identifier algorithm, passing + // issuer copy and related and append the result to path. + path += issuerCopy.getId(related); + } - // Add triples and prefixes if passed - this._prefixes = Object.create(null); - if (options.prefixes) - this.addPrefixes(options.prefixes); - if (triples) - this.addTriples(triples); -} + // 5.4.4.3) If chosen path is not empty and the length of path + // is greater than or equal to the length of chosen path and + // path is lexicographically greater than chosen path, then + // skip to the next permutation. + if(chosenPath.length !== 0 && + path.length >= chosenPath.length && path > chosenPath) { + // FIXME: may cause inaccurate total depth calculation + return nextPermutation(); + } + callback(); + }, callback); + }, + function(callback) { + // 5.4.5) For each related in recursion list: + self.forEach(recursionList, function(related, idx, callback) { + // 5.4.5.1) Set result to the result of recursively executing + // the Hash N-Degree Quads algorithm, passing related for + // identifier and issuer copy for path identifier issuer. + self.hashNDegreeQuads( + related, issuerCopy, function(err, result) { + if(err) { + return callback(err); + } -N3Store.prototype = { - // ## Public properties + // 5.4.5.2) Use the Issue Identifier algorithm, passing issuer + // copy and related and append the result to path. + path += issuerCopy.getId(related); - // ### `size` returns the number of triples in the store - get size() { - // Return the triple count if if was cached - var size = this._size; - if (size !== null) - return size; + // 5.4.5.3) Append <, the hash in result, and > to path. + path += '<' + result.hash + '>'; - // Calculate the number of triples by counting to the deepest level - size = 0; - var graphs = this._graphs, subjects, subject; - for (var graphKey in graphs) - for (var subjectKey in (subjects = graphs[graphKey].subjects)) - for (var predicateKey in (subject = subjects[subjectKey])) - size += Object.keys(subject[predicateKey]).length; - return this._size = size; - }, + // 5.4.5.4) Set issuer copy to the identifier issuer in + // result. + issuerCopy = result.issuer; - // ## Private methods + // 5.4.5.5) If chosen path is not empty and the length of path + // is greater than or equal to the length of chosen path and + // path is lexicographically greater than chosen path, then + // skip to the next permutation. + if(chosenPath.length !== 0 && + path.length >= chosenPath.length && path > chosenPath) { + // FIXME: may cause inaccurate total depth calculation + return nextPermutation(); + } + callback(); + }); + }, callback); + }, + function(callback) { + // 5.4.6) If chosen path is empty or path is lexicographically + // less than chosen path, set chosen path to path and chosen + // issuer to issuer copy. + if(chosenPath.length === 0 || path < chosenPath) { + chosenPath = path; + chosenIssuer = issuerCopy; + } + callback(); + } + ], nextPermutation); + }, function(err) { + if(err) { + return callback(err); + } - // ### `_addToIndex` adds a triple to a three-layered index. - // Returns if the index has changed, if the entry did not already exist. - _addToIndex: function (index0, key0, key1, key2) { - // Create layers as necessary - var index1 = index0[key0] || (index0[key0] = {}); - var index2 = index1[key1] || (index1[key1] = {}); - // Setting the key to _any_ value signals the presence of the triple - var existed = key2 in index2; - if (!existed) - index2[key2] = null; - return !existed; - }, + // 5.5) Append chosen path to data to hash. + md.update(chosenPath); - // ### `_removeFromIndex` removes a triple from a three-layered index - _removeFromIndex: function (index0, key0, key1, key2) { - // Remove the triple from the index - var index1 = index0[key0], index2 = index1[key1], key; - delete index2[key2]; + // 5.6) Replace issuer, by reference, with chosen issuer. + issuer = chosenIssuer; + callback(); + }); + }, callback); + } + ], function(err) { + // 6) Return issuer and the hash that results from passing data to hash + // through the hash algorithm. + callback(err, {hash: md.digest(), issuer: issuer}); + }); +}; - // Remove intermediary index layers if they are empty - for (key in index2) return; - delete index1[key1]; - for (key in index1) return; - delete index0[key0]; - }, +// helper for creating hash to related blank nodes map +Normalize.prototype.createHashToRelated = function(id, issuer, callback) { + var self = this; - // ### `_findInIndex` finds a set of triples in a three-layered index. - // The index base is `index0` and the keys at each level are `key0`, `key1`, and `key2`. - // Any of these keys can be undefined, which is interpreted as a wildcard. - // `name0`, `name1`, and `name2` are the names of the keys at each level, - // used when reconstructing the resulting triple - // (for instance: _subject_, _predicate_, and _object_). - // Finally, `graph` will be the graph of the created triples. - // If `callback` is given, each result is passed through it - // and iteration halts when it returns truthy for any triple. - // If instead `array` is given, each result is added to the array. - _findInIndex: function (index0, key0, key1, key2, name0, name1, name2, graph, callback, array) { - var tmp, index1, index2, varCount = !key0 + !key1 + !key2, - // depending on the number of variables, keys or reverse index are faster - entityKeys = varCount > 1 ? Object.keys(this._ids) : this._entities; - - // If a key is specified, use only that part of index 0. - if (key0) (tmp = index0, index0 = {})[key0] = tmp[key0]; - for (var value0 in index0) { - var entity0 = entityKeys[value0]; + // 1) Create a hash to related blank nodes map for storing hashes that + // identify related blank nodes. + var hashToRelated = {}; - if (index1 = index0[value0]) { - // If a key is specified, use only that part of index 1. - if (key1) (tmp = index1, index1 = {})[key1] = tmp[key1]; - for (var value1 in index1) { - var entity1 = entityKeys[value1]; + // 2) Get a reference, quads, to the list of quads in the blank node to + // quads map for the key identifier. + var quads = self.blankNodeInfo[id].quads; - if (index2 = index1[value1]) { - // If a key is specified, use only that part of index 2, if it exists. - var values = key2 ? (key2 in index2 ? [key2] : []) : Object.keys(index2); - // Create triples for all items found in index 2. - for (var l = values.length - 1; l >= 0; l--) { - var result = { subject: '', predicate: '', object: '', graph: graph }; - result[name0] = entity0; - result[name1] = entity1; - result[name2] = entityKeys[values[l]]; - if (array) - array.push(result); - else if (callback(result)) - return true; - } - } - } + // 3) For each quad in quads: + self.forEach(quads, function(quad, idx, callback) { + // 3.1) For each component in quad, if component is the subject, object, + // and graph name and it is a blank node that is not identified by + // identifier: + self.forEach(quad, function(component, key, callback) { + if(key === 'predicate' || + !(component.type === 'blank node' && component.value !== id)) { + return callback(); } + // 3.1.1) Set hash to the result of the Hash Related Blank Node + // algorithm, passing the blank node identifier for component as + // related, quad, path identifier issuer as issuer, and position as + // either s, o, or g based on whether component is a subject, object, + // graph name, respectively. + var related = component.value; + var position = POSITIONS[key]; + self.hashRelatedBlankNode( + related, quad, issuer, position, function(err, hash) { + if(err) { + return callback(err); + } + // 3.1.2) Add a mapping of hash to the blank node identifier for + // component to hash to related blank nodes map, adding an entry as + // necessary. + if(hash in hashToRelated) { + hashToRelated[hash].push(related); + } else { + hashToRelated[hash] = [related]; + } + callback(); + }); + }, callback); + }, function(err) { + callback(err, hashToRelated); + }); +}; + +// helper that iterates over quad components (skips predicate) +Normalize.prototype.forEachComponent = function(quad, op) { + for(var key in quad) { + // skip `predicate` + if(key === 'predicate') { + continue; } - return array; - }, + op(quad[key], key, quad); + } +}; - // ### `_loop` executes the callback on all keys of index 0 - _loop: function (index0, callback) { - for (var key0 in index0) - callback(key0); - }, +return Normalize; - // ### `_loopByKey0` executes the callback on all keys of a certain entry in index 0 - _loopByKey0: function (index0, key0, callback) { - var index1, key1; - if (index1 = index0[key0]) { - for (key1 in index1) - callback(key1); - } - }, +})(); // end of define URDNA2015 - // ### `_loopByKey1` executes the callback on given keys of all entries in index 0 - _loopByKey1: function (index0, key1, callback) { - var key0, index1; - for (key0 in index0) { - index1 = index0[key0]; - if (index1[key1]) - callback(key0); - } - }, +/////////////////////////////// DEFINE URGNA2012 ////////////////////////////// - // ### `_loopBy2Keys` executes the callback on given keys of certain entries in index 2 - _loopBy2Keys: function (index0, key0, key1, callback) { - var index1, index2, key2; - if ((index1 = index0[key0]) && (index2 = index1[key1])) { - for (key2 in index2) - callback(key2); - } - }, +var URGNA2012 = (function() { - // ### `_countInIndex` counts matching triples in a three-layered index. - // The index base is `index0` and the keys at each level are `key0`, `key1`, and `key2`. - // Any of these keys can be undefined, which is interpreted as a wildcard. - _countInIndex: function (index0, key0, key1, key2) { - var count = 0, tmp, index1, index2; +var Normalize = function(options) { + URDNA2015.call(this, options); + this.name = 'URGNA2012'; +}; +Normalize.prototype = new URDNA2015(); - // If a key is specified, count only that part of index 0 - if (key0) (tmp = index0, index0 = {})[key0] = tmp[key0]; - for (var value0 in index0) { - if (index1 = index0[value0]) { - // If a key is specified, count only that part of index 1 - if (key1) (tmp = index1, index1 = {})[key1] = tmp[key1]; - for (var value1 in index1) { - if (index2 = index1[value1]) { - // If a key is specified, count the triple if it exists - if (key2) (key2 in index2) && count++; - // Otherwise, count all triples - else count += Object.keys(index2).length; - } - } - } - } - return count; - }, +// helper for modifying component during Hash First Degree Quads +Normalize.prototype.modifyFirstDegreeComponent = function(id, component, key) { + if(component.type !== 'blank node') { + return component; + } + component = _clone(component); + if(key === 'name') { + component.value = '_:g'; + } else { + component.value = (component.value === id ? '_:a' : '_:z'); + } + return component; +}; - // ### `_getGraphs` returns an array with the given graph, - // or all graphs if the argument is null or undefined. - _getGraphs: function (graph) { - if (!isString(graph)) - return this._graphs; - var graphs = {}; - graphs[graph] = this._graphs[graph]; - return graphs; - }, +// helper for getting a related predicate +Normalize.prototype.getRelatedPredicate = function(quad) { + return quad.predicate.value; +}; - // ### `_uniqueEntities` returns a function that accepts an entity ID - // and passes the corresponding entity to callback if it hasn't occurred before. - _uniqueEntities: function (callback) { - var uniqueIds = Object.create(null), entities = this._entities; - return function (id) { - if (!(id in uniqueIds)) { - uniqueIds[id] = true; - callback(entities[id]); - } - }; - }, +// helper for creating hash to related blank nodes map +Normalize.prototype.createHashToRelated = function(id, issuer, callback) { + var self = this; - // ## Public methods + // 1) Create a hash to related blank nodes map for storing hashes that + // identify related blank nodes. + var hashToRelated = {}; - // ### `addTriple` adds a new N3 triple to the store. - // Returns if the triple index has changed, if the triple did not already exist. - addTriple: function (subject, predicate, object, graph) { - // Shift arguments if a triple object is given instead of components - if (!predicate) - graph = subject.graph, object = subject.object, - predicate = subject.predicate, subject = subject.subject; + // 2) Get a reference, quads, to the list of quads in the blank node to + // quads map for the key identifier. + var quads = self.blankNodeInfo[id].quads; - // Find the graph that will contain the triple - graph = graph || ''; - var graphItem = this._graphs[graph]; - // Create the graph if it doesn't exist yet - if (!graphItem) { - graphItem = this._graphs[graph] = { subjects: {}, predicates: {}, objects: {} }; - // Freezing a graph helps subsequent `add` performance, - // and properties will never be modified anyway - Object.freeze(graphItem); + // 3) For each quad in quads: + self.forEach(quads, function(quad, idx, callback) { + // 3.1) If the quad's subject is a blank node that does not match + // identifier, set hash to the result of the Hash Related Blank Node + // algorithm, passing the blank node identifier for subject as related, + // quad, path identifier issuer as issuer, and p as position. + var position; + var related; + if(quad.subject.type === 'blank node' && quad.subject.value !== id) { + related = quad.subject.value; + position = 'p'; + } else if(quad.object.type === 'blank node' && quad.object.value !== id) { + // 3.2) Otherwise, if quad's object is a blank node that does not match + // identifier, to the result of the Hash Related Blank Node algorithm, + // passing the blank node identifier for object as related, quad, path + // identifier issuer as issuer, and r as position. + related = quad.object.value; + position = 'r'; + } else { + // 3.3) Otherwise, continue to the next quad. + return callback(); } + // 3.4) Add a mapping of hash to the blank node identifier for the + // component that matched (subject or object) to hash to related blank + // nodes map, adding an entry as necessary. + self.hashRelatedBlankNode( + related, quad, issuer, position, function(err, hash) { + if(hash in hashToRelated) { + hashToRelated[hash].push(related); + } else { + hashToRelated[hash] = [related]; + } + callback(); + }); + }, function(err) { + callback(err, hashToRelated); + }); +}; - // Since entities can often be long IRIs, we avoid storing them in every index. - // Instead, we have a separate index that maps entities to numbers, - // which are then used as keys in the other indexes. - var ids = this._ids; - var entities = this._entities; - subject = ids[subject] || (ids[entities[++this._id] = subject] = this._id); - predicate = ids[predicate] || (ids[entities[++this._id] = predicate] = this._id); - object = ids[object] || (ids[entities[++this._id] = object] = this._id); - - var changed = this._addToIndex(graphItem.subjects, subject, predicate, object); - this._addToIndex(graphItem.predicates, predicate, object, subject); - this._addToIndex(graphItem.objects, object, subject, predicate); +return Normalize; - // The cached triple count is now invalid - this._size = null; - return changed; - }, +})(); // end of define URGNA2012 - // ### `addTriples` adds multiple N3 triples to the store - addTriples: function (triples) { - for (var i = triples.length - 1; i >= 0; i--) - this.addTriple(triples[i]); - }, +/** + * Recursively flattens the subjects in the given JSON-LD expanded input + * into a node map. + * + * @param input the JSON-LD expanded input. + * @param graphs a map of graph name to subject map. + * @param graph the name of the current graph. + * @param issuer the blank node identifier issuer. + * @param name the name assigned to the current input if it is a bnode. + * @param list the list to append to, null for none. + */ +function _createNodeMap(input, graphs, graph, issuer, name, list) { + // recurse through array + if(_isArray(input)) { + for(var i = 0; i < input.length; ++i) { + _createNodeMap(input[i], graphs, graph, issuer, undefined, list); + } + return; + } - // ### `addPrefix` adds support for querying with the given prefix - addPrefix: function (prefix, iri) { - this._prefixes[prefix] = iri; - }, + // add non-object to list + if(!_isObject(input)) { + if(list) { + list.push(input); + } + return; + } - // ### `addPrefixes` adds support for querying with the given prefixes - addPrefixes: function (prefixes) { - for (var prefix in prefixes) - this.addPrefix(prefix, prefixes[prefix]); - }, + // add values to list + if(_isValue(input)) { + if('@type' in input) { + var type = input['@type']; + // rename @type blank node + if(type.indexOf('_:') === 0) { + input['@type'] = type = issuer.getId(type); + } + } + if(list) { + list.push(input); + } + return; + } - // ### `removeTriple` removes an N3 triple from the store if it exists - removeTriple: function (subject, predicate, object, graph) { - // Shift arguments if a triple object is given instead of components - if (!predicate) - graph = subject.graph, object = subject.object, - predicate = subject.predicate, subject = subject.subject; - graph = graph || ''; + // Note: At this point, input must be a subject. - // Find internal identifiers for all components - // and verify the triple exists. - var graphItem, ids = this._ids, graphs = this._graphs, subjects, predicates; - if (!(subject = ids[subject]) || !(predicate = ids[predicate]) || - !(object = ids[object]) || !(graphItem = graphs[graph]) || - !(subjects = graphItem.subjects[subject]) || - !(predicates = subjects[predicate]) || - !(object in predicates)) - return false; + // spec requires @type to be named first, so assign names early + if('@type' in input) { + var types = input['@type']; + for(var i = 0; i < types.length; ++i) { + var type = types[i]; + if(type.indexOf('_:') === 0) { + issuer.getId(type); + } + } + } - // Remove it from all indexes - this._removeFromIndex(graphItem.subjects, subject, predicate, object); - this._removeFromIndex(graphItem.predicates, predicate, object, subject); - this._removeFromIndex(graphItem.objects, object, subject, predicate); - if (this._size !== null) this._size--; + // get name for subject + if(_isUndefined(name)) { + name = _isBlankNode(input) ? issuer.getId(input['@id']) : input['@id']; + } - // Remove the graph if it is empty - for (subject in graphItem.subjects) return true; - delete graphs[graph]; - return true; - }, + // add subject reference to list + if(list) { + list.push({'@id': name}); + } - // ### `removeTriples` removes multiple N3 triples from the store - removeTriples: function (triples) { - for (var i = triples.length - 1; i >= 0; i--) - this.removeTriple(triples[i]); - }, + // create new subject or merge into existing one + var subjects = graphs[graph]; + var subject = subjects[name] = subjects[name] || {}; + subject['@id'] = name; + var properties = Object.keys(input).sort(); + for(var pi = 0; pi < properties.length; ++pi) { + var property = properties[pi]; - // ### `getTriples` returns an array of triples matching a pattern, expanding prefixes as necessary. - // Setting any field to `undefined` or `null` indicates a wildcard. - getTriples: function (subject, predicate, object, graph) { - var prefixes = this._prefixes; - return this.getTriplesByIRI( - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, + // skip @id + if(property === '@id') { + continue; + } - // ### `getTriplesByIRI` returns an array of triples matching a pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getTriplesByIRI: function (subject, predicate, object, graph) { - var quads = [], graphs = this._getGraphs(graph), content, - ids = this._ids, subjectId, predicateId, objectId; + // handle reverse properties + if(property === '@reverse') { + var referencedNode = {'@id': name}; + var reverseMap = input['@reverse']; + for(var reverseProperty in reverseMap) { + var items = reverseMap[reverseProperty]; + for(var ii = 0; ii < items.length; ++ii) { + var item = items[ii]; + var itemName = item['@id']; + if(_isBlankNode(item)) { + itemName = issuer.getId(itemName); + } + _createNodeMap(item, graphs, graph, issuer, itemName); + jsonld.addValue( + subjects[itemName], reverseProperty, referencedNode, + {propertyIsArray: true, allowDuplicate: false}); + } + } + continue; + } - // Translate IRIs to internal index keys. - if (isString(subject) && !(subjectId = ids[subject]) || - isString(predicate) && !(predicateId = ids[predicate]) || - isString(object) && !(objectId = ids[object])) - return quads; + // recurse into graph + if(property === '@graph') { + // add graph subjects map entry + if(!(name in graphs)) { + graphs[name] = {}; + } + var g = (graph === '@merged') ? graph : name; + _createNodeMap(input[property], graphs, g, issuer); + continue; + } - for (var graphId in graphs) { - // Only if the specified graph contains triples, there can be results - if (content = graphs[graphId]) { - // Choose the optimal index, based on what fields are present - if (subjectId) { - if (objectId) - // If subject and object are given, the object index will be the fastest - this._findInIndex(content.objects, objectId, subjectId, predicateId, - 'object', 'subject', 'predicate', graphId, null, quads); - else - // If only subject and possibly predicate are given, the subject index will be the fastest - this._findInIndex(content.subjects, subjectId, predicateId, null, - 'subject', 'predicate', 'object', graphId, null, quads); - } - else if (predicateId) - // If only predicate and possibly object are given, the predicate index will be the fastest - this._findInIndex(content.predicates, predicateId, objectId, null, - 'predicate', 'object', 'subject', graphId, null, quads); - else if (objectId) - // If only object is given, the object index will be the fastest - this._findInIndex(content.objects, objectId, null, null, - 'object', 'subject', 'predicate', graphId, null, quads); - else - // If nothing is given, iterate subjects and predicates first - this._findInIndex(content.subjects, null, null, null, - 'subject', 'predicate', 'object', graphId, null, quads); + // copy non-@type keywords + if(property !== '@type' && _isKeyword(property)) { + if(property === '@index' && property in subject && + (input[property] !== subject[property] || + input[property]['@id'] !== subject[property]['@id'])) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; conflicting @index property detected.', + 'jsonld.SyntaxError', + {code: 'conflicting indexes', subject: subject}); } + subject[property] = input[property]; + continue; } - return quads; - }, - // ### `countTriples` returns the number of triples matching a pattern, expanding prefixes as necessary. - // Setting any field to `undefined` or `null` indicates a wildcard. - countTriples: function (subject, predicate, object, graph) { - var prefixes = this._prefixes; - return this.countTriplesByIRI( - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, + // iterate over objects + var objects = input[property]; - // ### `countTriplesByIRI` returns the number of triples matching a pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - countTriplesByIRI: function (subject, predicate, object, graph) { - var count = 0, graphs = this._getGraphs(graph), content, - ids = this._ids, subjectId, predicateId, objectId; + // if property is a bnode, assign it a new id + if(property.indexOf('_:') === 0) { + property = issuer.getId(property); + } - // Translate IRIs to internal index keys. - if (isString(subject) && !(subjectId = ids[subject]) || - isString(predicate) && !(predicateId = ids[predicate]) || - isString(object) && !(objectId = ids[object])) - return 0; + // ensure property is added for empty arrays + if(objects.length === 0) { + jsonld.addValue(subject, property, [], {propertyIsArray: true}); + continue; + } + for(var oi = 0; oi < objects.length; ++oi) { + var o = objects[oi]; - for (var graphId in graphs) { - // Only if the specified graph contains triples, there can be results - if (content = graphs[graphId]) { - // Choose the optimal index, based on what fields are present - if (subject) { - if (object) - // If subject and object are given, the object index will be the fastest - count += this._countInIndex(content.objects, objectId, subjectId, predicateId); - else - // If only subject and possibly predicate are given, the subject index will be the fastest - count += this._countInIndex(content.subjects, subjectId, predicateId, objectId); - } - else if (predicate) { - // If only predicate and possibly object are given, the predicate index will be the fastest - count += this._countInIndex(content.predicates, predicateId, objectId, subjectId); - } - else { - // If only object is possibly given, the object index will be the fastest - count += this._countInIndex(content.objects, objectId, subjectId, predicateId); - } + if(property === '@type') { + // rename @type blank nodes + o = (o.indexOf('_:') === 0) ? issuer.getId(o) : o; + } + + // handle embedded subject or subject reference + if(_isSubject(o) || _isSubjectReference(o)) { + // relabel blank node @id + var id = _isBlankNode(o) ? issuer.getId(o['@id']) : o['@id']; + + // add reference and recurse + jsonld.addValue( + subject, property, {'@id': id}, + {propertyIsArray: true, allowDuplicate: false}); + _createNodeMap(o, graphs, graph, issuer, id); + } else if(_isList(o)) { + // handle @list + var _list = []; + _createNodeMap(o['@list'], graphs, graph, issuer, name, _list); + o = {'@list': _list}; + jsonld.addValue( + subject, property, o, + {propertyIsArray: true, allowDuplicate: false}); + } else { + // handle @value + _createNodeMap(o, graphs, graph, issuer, name); + jsonld.addValue( + subject, property, o, {propertyIsArray: true, allowDuplicate: false}); } } - return count; - }, + } +} - // ### `forEach` executes the callback on all triples. - // Setting any field to `undefined` or `null` indicates a wildcard. - forEach: function (callback, subject, predicate, object, graph) { - var prefixes = this._prefixes; - this.forEachByIRI( - callback, - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, +function _mergeNodeMaps(graphs) { + // add all non-default graphs to default graph + var defaultGraph = graphs['@default']; + var graphNames = Object.keys(graphs).sort(); + for(var i = 0; i < graphNames.length; ++i) { + var graphName = graphNames[i]; + if(graphName === '@default') { + continue; + } + var nodeMap = graphs[graphName]; + var subject = defaultGraph[graphName]; + if(!subject) { + defaultGraph[graphName] = subject = { + '@id': graphName, + '@graph': [] + }; + } else if(!('@graph' in subject)) { + subject['@graph'] = []; + } + var graph = subject['@graph']; + var ids = Object.keys(nodeMap).sort(); + for(var ii = 0; ii < ids.length; ++ii) { + var node = nodeMap[ids[ii]]; + // only add full subjects + if(!_isSubjectReference(node)) { + graph.push(node); + } + } + } + return defaultGraph; +} - // ### `forEachByIRI` executes the callback on all triples. - // Setting any field to `undefined` or `null` indicates a wildcard. - forEachByIRI: function (callback, subject, predicate, object, graph) { - this.someByIRI(function (quad) { - callback(quad); - return false; - }, subject, predicate, object, graph); - }, +/** + * Frames subjects according to the given frame. + * + * @param state the current framing state. + * @param subjects the subjects to filter. + * @param frame the frame. + * @param parent the parent subject or top-level array. + * @param property the parent property, initialized to null. + */ +function _frame(state, subjects, frame, parent, property) { + // validate the frame + _validateFrame(frame); + frame = frame[0]; - // ### `every` executes the callback on all triples, - // and returns `true` if it returns truthy for all them. - // Setting any field to `undefined` or `null` indicates a wildcard. - every: function (callback, subject, predicate, object, graph) { - var prefixes = this._prefixes; - return this.everyByIRI( - callback, - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, + // get flags for current frame + var options = state.options; + var flags = { + embed: _getFrameFlag(frame, options, 'embed'), + explicit: _getFrameFlag(frame, options, 'explicit'), + requireAll: _getFrameFlag(frame, options, 'requireAll') + }; - // ### `everyByIRI` executes the callback on all triples, - // and returns `true` if it returns truthy for all them. - // Setting any field to `undefined` or `null` indicates a wildcard. - everyByIRI: function (callback, subject, predicate, object, graph) { - var some = false; - var every = !this.someByIRI(function (quad) { - some = true; - return !callback(quad); - }, subject, predicate, object, graph); - return some && every; - }, + // filter out subjects that match the frame + var matches = _filterSubjects(state, subjects, frame, flags); - // ### `some` executes the callback on all triples, - // and returns `true` if it returns truthy for any of them. - // Setting any field to `undefined` or `null` indicates a wildcard. - some: function (callback, subject, predicate, object, graph) { - var prefixes = this._prefixes; - return this.someByIRI( - callback, - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, + // add matches to output + var ids = Object.keys(matches).sort(); + for(var idx = 0; idx < ids.length; ++idx) { + var id = ids[idx]; + var subject = matches[id]; - // ### `someByIRI` executes the callback on all triples, - // and returns `true` if it returns truthy for any of them. - // Setting any field to `undefined` or `null` indicates a wildcard. - someByIRI: function (callback, subject, predicate, object, graph) { - var graphs = this._getGraphs(graph), content, - ids = this._ids, subjectId, predicateId, objectId; + if(flags.embed === '@link' && id in state.link) { + // TODO: may want to also match an existing linked subject against + // the current frame ... so different frames could produce different + // subjects that are only shared in-memory when the frames are the same - // Translate IRIs to internal index keys. - if (isString(subject) && !(subjectId = ids[subject]) || - isString(predicate) && !(predicateId = ids[predicate]) || - isString(object) && !(objectId = ids[object])) - return false; + // add existing linked subject + _addFrameOutput(parent, property, state.link[id]); + continue; + } - for (var graphId in graphs) { - // Only if the specified graph contains triples, there can be result - if (content = graphs[graphId]) { - // Choose the optimal index, based on what fields are present - if (subjectId) { - if (objectId) { - // If subject and object are given, the object index will be the fastest - if (this._findInIndex(content.objects, objectId, subjectId, predicateId, - 'object', 'subject', 'predicate', graphId, callback, null)) - return true; - } - else - // If only subject and possibly predicate are given, the subject index will be the fastest - if (this._findInIndex(content.subjects, subjectId, predicateId, null, - 'subject', 'predicate', 'object', graphId, callback, null)) - return true; - } - else if (predicateId) { - // If only predicate and possibly object are given, the predicate index will be the fastest - if (this._findInIndex(content.predicates, predicateId, objectId, null, - 'predicate', 'object', 'subject', graphId, callback, null)) { - return true; - } - } - else if (objectId) { - // If only object is given, the object index will be the fastest - if (this._findInIndex(content.objects, objectId, null, null, - 'object', 'subject', 'predicate', graphId, callback, null)) { - return true; - } - } - else - // If nothing is given, iterate subjects and predicates first - if (this._findInIndex(content.subjects, null, null, null, - 'subject', 'predicate', 'object', graphId, callback, null)) { - return true; - } - } + /* Note: In order to treat each top-level match as a compartmentalized + result, clear the unique embedded subjects map when the property is null, + which only occurs at the top-level. */ + if(property === null) { + state.uniqueEmbeds = {}; } - return false; - }, - // ### `getSubjects` returns all subjects that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getSubjects: function (predicate, object, graph) { - var prefixes = this._prefixes; - return this.getSubjectsByIRI( - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, + // start output for subject + var output = {}; + output['@id'] = id; + state.link[id] = output; - // ### `getSubjectsByIRI` returns all subjects that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getSubjectsByIRI: function (predicate, object, graph) { - var results = []; - this.forSubjectsByIRI(function (s) { results.push(s); }, predicate, object, graph); - return results; - }, + // if embed is @never or if a circular reference would be created by an + // embed, the subject cannot be embedded, just add the reference; + // note that a circular reference won't occur when the embed flag is + // `@link` as the above check will short-circuit before reaching this point + if(flags.embed === '@never' || + _createsCircularReference(subject, state.subjectStack)) { + _addFrameOutput(parent, property, output); + continue; + } - // ### `forSubjects` executes the callback on all subjects that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - forSubjects: function (callback, predicate, object, graph) { - var prefixes = this._prefixes; - this.forSubjectsByIRI( - callback, - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, + // if only the last match should be embedded + if(flags.embed === '@last') { + // remove any existing embed + if(id in state.uniqueEmbeds) { + _removeEmbed(state, id); + } + state.uniqueEmbeds[id] = {parent: parent, property: property}; + } - // ### `forSubjectsByIRI` executes the callback on all subjects that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - forSubjectsByIRI: function (callback, predicate, object, graph) { - var ids = this._ids, graphs = this._getGraphs(graph), content, predicateId, objectId; - callback = this._uniqueEntities(callback); + // push matching subject onto stack to enable circular embed checks + state.subjectStack.push(subject); - // Translate IRIs to internal index keys. - if (isString(predicate) && !(predicateId = ids[predicate]) || - isString(object) && !(objectId = ids[object])) - return; + // iterate over subject properties + var props = Object.keys(subject).sort(); + for(var i = 0; i < props.length; i++) { + var prop = props[i]; - for (graph in graphs) { - // Only if the specified graph contains triples, there can be results - if (content = graphs[graph]) { - // Choose optimal index based on which fields are wildcards - if (predicateId) { - if (objectId) - // If predicate and object are given, the POS index is best. - this._loopBy2Keys(content.predicates, predicateId, objectId, callback); - else - // If only predicate is given, the SPO index is best. - this._loopByKey1(content.subjects, predicateId, callback); - } - else if (objectId) - // If only object is given, the OSP index is best. - this._loopByKey0(content.objects, objectId, callback); - else - // If no params given, iterate all the subjects - this._loop(content.subjects, callback); + // copy keywords to output + if(_isKeyword(prop)) { + output[prop] = _clone(subject[prop]); + continue; } - } - }, - - // ### `getPredicates` returns all predicates that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getPredicates: function (subject, object, graph) { - var prefixes = this._prefixes; - return this.getPredicatesByIRI( - expandPrefixedName(subject, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - // ### `getPredicatesByIRI` returns all predicates that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getPredicatesByIRI: function (subject, object, graph) { - var results = []; - this.forPredicatesByIRI(function (p) { results.push(p); }, subject, object, graph); - return results; - }, + // explicit is on and property isn't in the frame, skip processing + if(flags.explicit && !(prop in frame)) { + continue; + } - // ### `forPredicates` executes the callback on all predicates that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - forPredicates: function (callback, subject, object, graph) { - var prefixes = this._prefixes; - this.forPredicatesByIRI( - callback, - expandPrefixedName(subject, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, + // add objects + var objects = subject[prop]; + for(var oi = 0; oi < objects.length; ++oi) { + var o = objects[oi]; - // ### `forPredicatesByIRI` executes the callback on all predicates that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - forPredicatesByIRI: function (callback, subject, object, graph) { - var ids = this._ids, graphs = this._getGraphs(graph), content, subjectId, objectId; - callback = this._uniqueEntities(callback); + // recurse into list + if(_isList(o)) { + // add empty list + var list = {'@list': []}; + _addFrameOutput(output, prop, list); - // Translate IRIs to internal index keys. - if (isString(subject) && !(subjectId = ids[subject]) || - isString(object) && !(objectId = ids[object])) - return; + // add list objects + var src = o['@list']; + for(var n in src) { + o = src[n]; + if(_isSubjectReference(o)) { + var subframe = (prop in frame ? + frame[prop][0]['@list'] : _createImplicitFrame(flags)); + // recurse into subject reference + _frame(state, [o['@id']], subframe, list, '@list'); + } else { + // include other values automatically + _addFrameOutput(list, '@list', _clone(o)); + } + } + continue; + } - for (graph in graphs) { - // Only if the specified graph contains triples, there can be results - if (content = graphs[graph]) { - // Choose optimal index based on which fields are wildcards - if (subjectId) { - if (objectId) - // If subject and object are given, the OSP index is best. - this._loopBy2Keys(content.objects, objectId, subjectId, callback); - else - // If only subject is given, the SPO index is best. - this._loopByKey0(content.subjects, subjectId, callback); + if(_isSubjectReference(o)) { + // recurse into subject reference + var subframe = (prop in frame ? + frame[prop] : _createImplicitFrame(flags)); + _frame(state, [o['@id']], subframe, output, prop); + } else { + // include other values automatically + _addFrameOutput(output, prop, _clone(o)); } - else if (objectId) - // If only object is given, the POS index is best. - this._loopByKey1(content.predicates, objectId, callback); - else - // If no params given, iterate all the predicates. - this._loop(content.predicates, callback); } } - }, - - // ### `getObjects` returns all objects that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getObjects: function (subject, predicate, graph) { - var prefixes = this._prefixes; - return this.getObjectsByIRI( - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - - // ### `getObjectsByIRI` returns all objects that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getObjectsByIRI: function (subject, predicate, graph) { - var results = []; - this.forObjectsByIRI(function (o) { results.push(o); }, subject, predicate, graph); - return results; - }, - - // ### `forObjects` executes the callback on all objects that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - forObjects: function (callback, subject, predicate, graph) { - var prefixes = this._prefixes; - this.forObjectsByIRI( - callback, - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, - // ### `forObjectsByIRI` executes the callback on all objects that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - forObjectsByIRI: function (callback, subject, predicate, graph) { - var ids = this._ids, graphs = this._getGraphs(graph), content, subjectId, predicateId; - callback = this._uniqueEntities(callback); + // handle defaults + var props = Object.keys(frame).sort(); + for(var i = 0; i < props.length; ++i) { + var prop = props[i]; - // Translate IRIs to internal index keys. - if (isString(subject) && !(subjectId = ids[subject]) || - isString(predicate) && !(predicateId = ids[predicate])) - return; + // skip keywords + if(_isKeyword(prop)) { + continue; + } - for (graph in graphs) { - // Only if the specified graph contains triples, there can be results - if (content = graphs[graph]) { - // Choose optimal index based on which fields are wildcards - if (subjectId) { - if (predicateId) - // If subject and predicate are given, the SPO index is best. - this._loopBy2Keys(content.subjects, subjectId, predicateId, callback); - else - // If only subject is given, the OSP index is best. - this._loopByKey1(content.objects, subjectId, callback); + // if omit default is off, then include default values for properties + // that appear in the next frame but are not in the matching subject + var next = frame[prop][0]; + var omitDefaultOn = _getFrameFlag(next, options, 'omitDefault'); + if(!omitDefaultOn && !(prop in output)) { + var preserve = '@null'; + if('@default' in next) { + preserve = _clone(next['@default']); } - else if (predicateId) - // If only predicate is given, the POS index is best. - this._loopByKey0(content.predicates, predicateId, callback); - else - // If no params given, iterate all the objects. - this._loop(content.objects, callback); + if(!_isArray(preserve)) { + preserve = [preserve]; + } + output[prop] = [{'@preserve': preserve}]; } } - }, - // ### `getGraphs` returns all graphs that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getGraphs: function (subject, predicate, object) { - var prefixes = this._prefixes; - return this.getGraphsByIRI( - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes) - ); - }, + // add output to parent + _addFrameOutput(parent, property, output); - // ### `getGraphsByIRI` returns all graphs that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - getGraphsByIRI: function (subject, predicate, object) { - var results = []; - this.forGraphsByIRI(function (g) { results.push(g); }, subject, predicate, object); - return results; - }, + // pop matching subject from circular ref-checking stack + state.subjectStack.pop(); + } +} - // ### `forGraphs` executes the callback on all graphs that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - forGraphs: function (callback, subject, predicate, object) { - var prefixes = this._prefixes; - this.forGraphsByIRI( - callback, - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes) - ); - }, - - // ### `forGraphsByIRI` executes the callback on all graphs that match the pattern. - // Setting any field to `undefined` or `null` indicates a wildcard. - forGraphsByIRI: function (callback, subject, predicate, object) { - for (var graph in this._graphs) { - this.someByIRI(function (quad) { - callback(quad.graph); - return true; // Halt iteration of some() - }, subject, predicate, object, graph); +/** + * Creates an implicit frame when recursing through subject matches. If + * a frame doesn't have an explicit frame for a particular property, then + * a wildcard child frame will be created that uses the same flags that the + * parent frame used. + * + * @param flags the current framing flags. + * + * @return the implicit frame. + */ +function _createImplicitFrame(flags) { + var frame = {}; + for(var key in flags) { + if(flags[key] !== undefined) { + frame['@' + key] = [flags[key]]; } - }, + } + return [frame]; +} - // ### `createBlankNode` creates a new blank node, returning its name - createBlankNode: function (suggestedName) { - var name, index; - // Generate a name based on the suggested name - if (suggestedName) { - name = suggestedName = '_:' + suggestedName, index = 1; - while (this._ids[name]) - name = suggestedName + index++; - } - // Generate a generic blank node name - else { - do { name = '_:b' + this._blankNodeIndex++; } - while (this._ids[name]); +/** + * Checks the current subject stack to see if embedding the given subject + * would cause a circular reference. + * + * @param subjectToEmbed the subject to embed. + * @param subjectStack the current stack of subjects. + * + * @return true if a circular reference would be created, false if not. + */ +function _createsCircularReference(subjectToEmbed, subjectStack) { + for(var i = subjectStack.length - 1; i >= 0; --i) { + if(subjectStack[i]['@id'] === subjectToEmbed['@id']) { + return true; } - // Add the blank node to the entities, avoiding the generation of duplicates - this._ids[name] = ++this._id; - this._entities[this._id] = name; - return name; - }, -}; - -// Determines whether the argument is a string -function isString(s) { - return typeof s === 'string' || s instanceof String; + } + return false; } -// ## Exports -module.exports = N3Store; - -},{"./N3Util":31}],29:[function(_dereq_,module,exports){ -// **N3StreamParser** parses an N3 stream into a triple stream. -var Transform = _dereq_('stream').Transform, - util = _dereq_('util'), - N3Parser = _dereq_('./N3Parser.js'); - -// ## Constructor -function N3StreamParser(options) { - if (!(this instanceof N3StreamParser)) - return new N3StreamParser(options); - - // Initialize Transform base class - Transform.call(this, { decodeStrings: true }); - this._readableState.objectMode = true; - - // Set up parser - var self = this, parser = new N3Parser(options), onData, onEnd; - parser.parse( - // Pass dummy stream to obtain `data` and `end` callbacks - { on: function (event, cb) { event === 'data' ? (onData = cb) : (onEnd = cb); } }, - // Handle triples by pushing them down the pipeline - function (error, t) { error && self.emit('error', error) || t && self.push(t); }, - // Emit prefixes through the `prefix` event - function (prefix, uri) { self.emit('prefix', prefix, uri); }); - - // Implement Transform methods through parser callbacks - this._transform = function (chunk, encoding, done) { onData(chunk); done(); }; - this._flush = function (done) { onEnd(); done(); }; +/** + * Gets the frame flag value for the given flag name. + * + * @param frame the frame. + * @param options the framing options. + * @param name the flag name. + * + * @return the flag value. + */ +function _getFrameFlag(frame, options, name) { + var flag = '@' + name; + var rval = (flag in frame ? frame[flag][0] : options[name]); + if(name === 'embed') { + // default is "@last" + // backwards-compatibility support for "embed" maps: + // true => "@last" + // false => "@never" + if(rval === true) { + rval = '@last'; + } else if(rval === false) { + rval = '@never'; + } else if(rval !== '@always' && rval !== '@never' && rval !== '@link') { + rval = '@last'; + } + } + return rval; } -util.inherits(N3StreamParser, Transform); - -// ## Exports -module.exports = N3StreamParser; - -},{"./N3Parser.js":27,"stream":101,"util":112}],30:[function(_dereq_,module,exports){ -// **N3StreamWriter** serializes a triple stream into an N3 stream. -var Transform = _dereq_('stream').Transform, - util = _dereq_('util'), - N3Writer = _dereq_('./N3Writer.js'); -// ## Constructor -function N3StreamWriter(options) { - if (!(this instanceof N3StreamWriter)) - return new N3StreamWriter(options); +/** + * Validates a JSON-LD frame, throwing an exception if the frame is invalid. + * + * @param frame the frame to validate. + */ +function _validateFrame(frame) { + if(!_isArray(frame) || frame.length !== 1 || !_isObject(frame[0])) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; a JSON-LD frame must be a single object.', + 'jsonld.SyntaxError', {frame: frame}); + } +} - // Initialize Transform base class - Transform.call(this, { encoding: 'utf8' }); - this._writableState.objectMode = true; +/** + * Returns a map of all of the subjects that match a parsed frame. + * + * @param state the current framing state. + * @param subjects the set of subjects to filter. + * @param frame the parsed frame. + * @param flags the frame flags. + * + * @return all of the matched subjects. + */ +function _filterSubjects(state, subjects, frame, flags) { + // filter subjects in @id order + var rval = {}; + for(var i = 0; i < subjects.length; ++i) { + var id = subjects[i]; + var subject = state.subjects[id]; + if(_filterSubject(subject, frame, flags)) { + rval[id] = subject; + } + } + return rval; +} - // Set up writer with a dummy stream object - var self = this; - var writer = new N3Writer({ - write: function (chunk, encoding, callback) { self.push(chunk); callback && callback(); }, - end: function (callback) { self.push(null); callback && callback(); }, - }, options); +/** + * Returns true if the given subject matches the given frame. + * + * @param subject the subject to check. + * @param frame the frame to check. + * @param flags the frame flags. + * + * @return true if the subject matches, false if not. + */ +function _filterSubject(subject, frame, flags) { + // check @type (object value means 'any' type, fall through to ducktyping) + if('@type' in frame && + !(frame['@type'].length === 1 && _isObject(frame['@type'][0]))) { + var types = frame['@type']; + for(var i = 0; i < types.length; ++i) { + // any matching @type is a match + if(jsonld.hasValue(subject, '@type', types[i])) { + return true; + } + } + return false; + } - // Implement Transform methods on top of writer - this._transform = function (triple, encoding, done) { writer.addTriple(triple, done); }; - this._flush = function (done) { writer.end(done); }; -} -util.inherits(N3StreamWriter, Transform); + // check ducktype + var wildcard = true; + var matchesSome = false; + for(var key in frame) { + if(_isKeyword(key)) { + // skip non-@id and non-@type + if(key !== '@id' && key !== '@type') { + continue; + } + wildcard = false; -// ## Exports -module.exports = N3StreamWriter; + // check @id for a specific @id value + if(key === '@id' && _isString(frame[key])) { + if(subject[key] !== frame[key]) { + return false; + } + matchesSome = true; + continue; + } + } -},{"./N3Writer.js":32,"stream":101,"util":112}],31:[function(_dereq_,module,exports){ -// **N3Util** provides N3 utility functions. + wildcard = false; -var Xsd = 'http://www.w3.org/2001/XMLSchema#'; -var XsdString = Xsd + 'string'; -var XsdInteger = Xsd + 'integer'; -var XsdDouble = Xsd + 'double'; -var XsdBoolean = Xsd + 'boolean'; -var RdfLangString = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'; + if(key in subject) { + // frame[key] === [] means do not match if property is present + if(_isArray(frame[key]) && frame[key].length === 0 && + subject[key] !== undefined) { + return false; + } + matchesSome = true; + continue; + } -var N3Util = { - // Tests whether the given entity (triple object) represents an IRI in the N3 library - isIRI: function (entity) { - if (typeof entity !== 'string') + // all properties must match to be a duck unless a @default is specified + var hasDefault = (_isArray(frame[key]) && _isObject(frame[key][0]) && + '@default' in frame[key][0]); + if(flags.requireAll && !hasDefault) { return false; - else if (entity.length === 0) - return true; - else { - var firstChar = entity[0]; - return firstChar !== '"' && firstChar !== '_'; } - }, - - // Tests whether the given entity (triple object) represents a literal in the N3 library - isLiteral: function (entity) { - return typeof entity === 'string' && entity[0] === '"'; - }, - - // Tests whether the given entity (triple object) represents a blank node in the N3 library - isBlank: function (entity) { - return typeof entity === 'string' && entity.substr(0, 2) === '_:'; - }, + } - // Tests whether the given entity represents the default graph - isDefaultGraph: function (entity) { - return !entity; - }, + // return true if wildcard or subject matches some properties + return wildcard || matchesSome; +} - // Tests whether the given triple is in the default graph - inDefaultGraph: function (triple) { - return !triple.graph; - }, +/** + * Removes an existing embed. + * + * @param state the current framing state. + * @param id the @id of the embed to remove. + */ +function _removeEmbed(state, id) { + // get existing embed + var embeds = state.uniqueEmbeds; + var embed = embeds[id]; + var parent = embed.parent; + var property = embed.property; - // Gets the string value of a literal in the N3 library - getLiteralValue: function (literal) { - var match = /^"([^]*)"/.exec(literal); - if (!match) - throw new Error(literal + ' is not a literal'); - return match[1]; - }, + // create reference to replace embed + var subject = {'@id': id}; - // Gets the type of a literal in the N3 library - getLiteralType: function (literal) { - var match = /^"[^]*"(?:\^\^([^"]+)|(@)[^@"]+)?$/.exec(literal); - if (!match) - throw new Error(literal + ' is not a literal'); - return match[1] || (match[2] ? RdfLangString : XsdString); - }, + // remove existing embed + if(_isArray(parent)) { + // replace subject with reference + for(var i = 0; i < parent.length; ++i) { + if(jsonld.compareValues(parent[i], subject)) { + parent[i] = subject; + break; + } + } + } else { + // replace subject with reference + var useArray = _isArray(parent[property]); + jsonld.removeValue(parent, property, subject, {propertyIsArray: useArray}); + jsonld.addValue(parent, property, subject, {propertyIsArray: useArray}); + } - // Gets the language of a literal in the N3 library - getLiteralLanguage: function (literal) { - var match = /^"[^]*"(?:@([^@"]+)|\^\^[^"]+)?$/.exec(literal); - if (!match) - throw new Error(literal + ' is not a literal'); - return match[1] ? match[1].toLowerCase() : ''; - }, + // recursively remove dependent dangling embeds + var removeDependents = function(id) { + // get embed keys as a separate array to enable deleting keys in map + var ids = Object.keys(embeds); + for(var i = 0; i < ids.length; ++i) { + var next = ids[i]; + if(next in embeds && _isObject(embeds[next].parent) && + embeds[next].parent['@id'] === id) { + delete embeds[next]; + removeDependents(next); + } + } + }; + removeDependents(id); +} - // Tests whether the given entity (triple object) represents a prefixed name - isPrefixedName: function (entity) { - return typeof entity === 'string' && /^[^:\/"']*:[^:\/"']+$/.test(entity); - }, +/** + * Adds framing output to the given parent. + * + * @param parent the parent to add to. + * @param property the parent property. + * @param output the output to add. + */ +function _addFrameOutput(parent, property, output) { + if(_isObject(parent)) { + jsonld.addValue(parent, property, output, {propertyIsArray: true}); + } else { + parent.push(output); + } +} - // Expands the prefixed name to a full IRI (also when it occurs as a literal's type) - expandPrefixedName: function (prefixedName, prefixes) { - var match = /(?:^|"\^\^)([^:\/#"'\^_]*):[^\/]*$/.exec(prefixedName), prefix, base, index; - if (match) - prefix = match[1], base = prefixes[prefix], index = match.index; - if (base === undefined) - return prefixedName; +/** + * Removes the @preserve keywords as the last step of the framing algorithm. + * + * @param ctx the active context used to compact the input. + * @param input the framed, compacted output. + * @param options the compaction options used. + * + * @return the resulting output. + */ +function _removePreserve(ctx, input, options) { + // recurse through arrays + if(_isArray(input)) { + var output = []; + for(var i = 0; i < input.length; ++i) { + var result = _removePreserve(ctx, input[i], options); + // drop nulls from arrays + if(result !== null) { + output.push(result); + } + } + input = output; + } else if(_isObject(input)) { + // remove @preserve + if('@preserve' in input) { + if(input['@preserve'] === '@null') { + return null; + } + return input['@preserve']; + } - // The match index is non-zero when expanding a literal's type - return index === 0 ? base + prefixedName.substr(prefix.length + 1) - : prefixedName.substr(0, index + 3) + - base + prefixedName.substr(index + prefix.length + 4); - }, + // skip @values + if(_isValue(input)) { + return input; + } - // Creates an IRI in N3.js representation - createIRI: function (iri) { - return iri && iri[0] === '"' ? N3Util.getLiteralValue(iri) : iri; - }, + // recurse through @lists + if(_isList(input)) { + input['@list'] = _removePreserve(ctx, input['@list'], options); + return input; + } - // Creates a literal in N3.js representation - createLiteral: function (value, modifier) { - if (!modifier) { - switch (typeof value) { - case 'boolean': - modifier = XsdBoolean; - break; - case 'number': - if (isFinite(value)) - modifier = value % 1 === 0 ? XsdInteger : XsdDouble; - else { - modifier = XsdDouble; - if (!isNaN(value)) - value = value > 0 ? 'INF' : '-INF'; + // handle in-memory linked nodes + var idAlias = _compactIri(ctx, '@id'); + if(idAlias in input) { + var id = input[idAlias]; + if(id in options.link) { + var idx = options.link[id].indexOf(input); + if(idx === -1) { + // prevent circular visitation + options.link[id].push(input); + } else { + // already visited + return options.link[id][idx]; } - break; - default: - return '"' + value + '"'; + } else { + // prevent circular visitation + options.link[id] = [input]; } } - return '"' + value + - (/^[a-z]+(-[a-z0-9]+)*$/i.test(modifier) ? '"@' + modifier.toLowerCase() - : '"^^' + modifier); - }, - - // Creates a function that prepends the given IRI to a local name - prefix: function (iri) { - return N3Util.prefixes({ '': iri })(''); - }, - - // Creates a function that allows registering and expanding prefixes - prefixes: function (defaultPrefixes) { - // Add all of the default prefixes - var prefixes = Object.create(null); - for (var prefix in defaultPrefixes) - processPrefix(prefix, defaultPrefixes[prefix]); - // Registers a new prefix (if an IRI was specified) - // or retrieves a function that expands an existing prefix (if no IRI was specified) - function processPrefix(prefix, iri) { - // Create a new prefix if an IRI is specified or the prefix doesn't exist - if (iri || !(prefix in prefixes)) { - var cache = Object.create(null); - iri = iri || ''; - // Create a function that expands the prefix - prefixes[prefix] = function (localName) { - return cache[localName] || (cache[localName] = iri + localName); - }; + // recurse through properties + for(var prop in input) { + var result = _removePreserve(ctx, input[prop], options); + var container = jsonld.getContextValue(ctx, prop, '@container'); + if(options.compactArrays && _isArray(result) && result.length === 1 && + container === null) { + result = result[0]; } - return prefixes[prefix]; + input[prop] = result; } - return processPrefix; - }, -}; + } + return input; +} -// ## Exports -module.exports = N3Util; +/** + * Compares two strings first based on length and then lexicographically. + * + * @param a the first string. + * @param b the second string. + * + * @return -1 if a < b, 1 if a > b, 0 if a == b. + */ +function _compareShortestLeast(a, b) { + if(a.length < b.length) { + return -1; + } + if(b.length < a.length) { + return 1; + } + if(a === b) { + return 0; + } + return (a < b) ? -1 : 1; +} -},{}],32:[function(_dereq_,module,exports){ -// **N3Writer** writes N3 documents. - -// Matches a literal as represented in memory by the N3 library -var N3LiteralMatcher = /^"([^]*)"(?:\^\^(.+)|@([\-a-z]+))?$/i; - -// rdf:type predicate (for 'a' abbreviation) -var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', - RDF_TYPE = RDF_PREFIX + 'type'; - -// Characters in literals that require escaping -var escape = /["\\\t\n\r\b\f\u0000-\u0019\ud800-\udbff]/, - escapeAll = /["\\\t\n\r\b\f\u0000-\u0019]|[\ud800-\udbff][\udc00-\udfff]/g, - escapeReplacements = { - '\\': '\\\\', '"': '\\"', '\t': '\\t', - '\n': '\\n', '\r': '\\r', '\b': '\\b', '\f': '\\f', - }; - -// ## Constructor -function N3Writer(outputStream, options) { - if (!(this instanceof N3Writer)) - return new N3Writer(outputStream, options); - - // Shift arguments if the first argument is not a stream - if (outputStream && typeof outputStream.write !== 'function') - options = outputStream, outputStream = null; - options = options || {}; - - // If no output stream given, send the output as string through the end callback - if (!outputStream) { - var output = ''; - this._outputStream = { - write: function (chunk, encoding, done) { output += chunk; done && done(); }, - end: function (done) { done && done(null, output); }, - }; - this._endStream = true; - } - else { - this._outputStream = outputStream; - this._endStream = options.end === undefined ? true : !!options.end; +/** + * Picks the preferred compaction term from the given inverse context entry. + * + * @param activeCtx the active context. + * @param iri the IRI to pick the term for. + * @param value the value to pick the term for. + * @param containers the preferred containers. + * @param typeOrLanguage either '@type' or '@language'. + * @param typeOrLanguageValue the preferred value for '@type' or '@language'. + * + * @return the preferred term. + */ +function _selectTerm( + activeCtx, iri, value, containers, typeOrLanguage, typeOrLanguageValue) { + if(typeOrLanguageValue === null) { + typeOrLanguageValue = '@null'; } - // Initialize writer, depending on the format - this._subject = null; - if (!(/triple|quad/i).test(options.format)) { - this._graph = ''; - this._prefixIRIs = Object.create(null); - options.prefixes && this.addPrefixes(options.prefixes); - } - else { - this._writeTriple = this._writeTripleLine; - } -} + // preferences for the value of @type or @language + var prefs = []; -N3Writer.prototype = { - // ## Private methods + // determine prefs for @id based on whether or not value compacts to a term + if((typeOrLanguageValue === '@id' || typeOrLanguageValue === '@reverse') && + _isSubjectReference(value)) { + // prefer @reverse first + if(typeOrLanguageValue === '@reverse') { + prefs.push('@reverse'); + } + // try to compact value to a term + var term = _compactIri(activeCtx, value['@id'], null, {vocab: true}); + if(term in activeCtx.mappings && + activeCtx.mappings[term] && + activeCtx.mappings[term]['@id'] === value['@id']) { + // prefer @vocab + prefs.push.apply(prefs, ['@vocab', '@id']); + } else { + // prefer @id + prefs.push.apply(prefs, ['@id', '@vocab']); + } + } else { + prefs.push(typeOrLanguageValue); + } + prefs.push('@none'); - // ### `_write` writes the argument to the output stream - _write: function (string, callback) { - this._outputStream.write(string, 'utf8', callback); - }, + var containerMap = activeCtx.inverse[iri]; + for(var ci = 0; ci < containers.length; ++ci) { + // if container not available in the map, continue + var container = containers[ci]; + if(!(container in containerMap)) { + continue; + } - // ### `_writeTriple` writes the triple to the output stream - _writeTriple: function (subject, predicate, object, graph, done) { - try { - // Write the graph's label if it has changed - if (this._graph !== graph) { - // Close the previous graph and start the new one - this._write((this._subject === null ? '' : (this._graph ? '\n}\n' : '.\n')) + - (graph ? this._encodeIriOrBlankNode(graph) + ' {\n' : '')); - this._subject = null; - // Don't treat identical blank nodes as repeating graphs - this._graph = graph[0] !== '[' ? graph : ']'; - } - // Don't repeat the subject if it's the same - if (this._subject === subject) { - // Don't repeat the predicate if it's the same - if (this._predicate === predicate) - this._write(', ' + this._encodeObject(object), done); - // Same subject, different predicate - else - this._write(';\n ' + - this._encodePredicate(this._predicate = predicate) + ' ' + - this._encodeObject(object), done); + var typeOrLanguageValueMap = containerMap[container][typeOrLanguage]; + for(var pi = 0; pi < prefs.length; ++pi) { + // if type/language option not available in the map, continue + var pref = prefs[pi]; + if(!(pref in typeOrLanguageValueMap)) { + continue; } - // Different subject; write the whole triple - else - this._write((this._subject === null ? '' : '.\n') + - this._encodeSubject(this._subject = subject) + ' ' + - this._encodePredicate(this._predicate = predicate) + ' ' + - this._encodeObject(object), done); - } - catch (error) { done && done(error); } - }, - // ### `_writeTripleLine` writes the triple or quad to the output stream as a single line - _writeTripleLine: function (subject, predicate, object, graph, done) { - // Don't use prefixes - delete this._prefixMatch; - // Write the triple - try { - this._write(this._encodeIriOrBlankNode(subject) + ' ' + - this._encodeIriOrBlankNode(predicate) + ' ' + - this._encodeObject(object) + - (graph ? ' ' + this._encodeIriOrBlankNode(graph) + '.\n' : '.\n'), done); + // select term + return typeOrLanguageValueMap[pref]; } - catch (error) { done && done(error); } - }, - - // ### `_encodeIriOrBlankNode` represents an IRI or blank node - _encodeIriOrBlankNode: function (entity) { - // A blank node or list is represented as-is - var firstChar = entity[0]; - if (firstChar === '[' || firstChar === '(' || firstChar === '_' && entity[1] === ':') - return entity; - // Escape special characters - if (escape.test(entity)) - entity = entity.replace(escapeAll, characterReplacer); - // Try to represent the IRI as prefixed name - var prefixMatch = this._prefixRegex.exec(entity); - return !prefixMatch ? '<' + entity + '>' : - (!prefixMatch[1] ? entity : this._prefixIRIs[prefixMatch[1]] + prefixMatch[2]); - }, + } - // ### `_encodeLiteral` represents a literal - _encodeLiteral: function (value, type, language) { - // Escape special characters - if (escape.test(value)) - value = value.replace(escapeAll, characterReplacer); - // Write the literal, possibly with type or language - if (language) - return '"' + value + '"@' + language; - else if (type) - return '"' + value + '"^^' + this._encodeIriOrBlankNode(type); - else - return '"' + value + '"'; - }, + return null; +} - // ### `_encodeSubject` represents a subject - _encodeSubject: function (subject) { - if (subject[0] === '"') - throw new Error('A literal as subject is not allowed: ' + subject); - // Don't treat identical blank nodes as repeating subjects - if (subject[0] === '[') - this._subject = ']'; - return this._encodeIriOrBlankNode(subject); - }, +/** + * Compacts an IRI or keyword into a term or prefix if it can be. If the + * IRI has an associated value it may be passed. + * + * @param activeCtx the active context to use. + * @param iri the IRI to compact. + * @param value the value to check or null. + * @param relativeTo options for how to compact IRIs: + * vocab: true to split after @vocab, false not to. + * @param reverse true if a reverse property is being compacted, false if not. + * + * @return the compacted term, prefix, keyword alias, or the original IRI. + */ +function _compactIri(activeCtx, iri, value, relativeTo, reverse) { + // can't compact null + if(iri === null) { + return iri; + } - // ### `_encodePredicate` represents a predicate - _encodePredicate: function (predicate) { - if (predicate[0] === '"') - throw new Error('A literal as predicate is not allowed: ' + predicate); - return predicate === RDF_TYPE ? 'a' : this._encodeIriOrBlankNode(predicate); - }, + // default value and parent to null + if(_isUndefined(value)) { + value = null; + } + // default reverse to false + if(_isUndefined(reverse)) { + reverse = false; + } + relativeTo = relativeTo || {}; - // ### `_encodeObject` represents an object - _encodeObject: function (object) { - // Represent an IRI or blank node - if (object[0] !== '"') - return this._encodeIriOrBlankNode(object); - // Represent a literal - var match = N3LiteralMatcher.exec(object); - if (!match) throw new Error('Invalid literal: ' + object); - return this._encodeLiteral(match[1], match[2], match[3]); - }, + var inverseCtx = activeCtx.getInverse(); - // ### `_blockedWrite` replaces `_write` after the writer has been closed - _blockedWrite: function () { - throw new Error('Cannot write because the writer has been closed.'); - }, + // if term is a keyword, it can only be compacted to a simple alias + if(_isKeyword(iri)) { + if(iri in inverseCtx) { + return inverseCtx[iri]['@none']['@type']['@none']; + } + return iri; + } - // ### `addTriple` adds the triple to the output stream - addTriple: function (subject, predicate, object, graph, done) { - // The triple was given as a triple object, so shift parameters - if (object === undefined) - this._writeTriple(subject.subject, subject.predicate, subject.object, - subject.graph || '', predicate); - // The optional `graph` parameter was not provided - else if (typeof graph !== 'string') - this._writeTriple(subject, predicate, object, '', graph); - // The `graph` parameter was provided - else - this._writeTriple(subject, predicate, object, graph, done); - }, + // use inverse context to pick a term if iri is relative to vocab + if(relativeTo.vocab && iri in inverseCtx) { + var defaultLanguage = activeCtx['@language'] || '@none'; - // ### `addTriples` adds the triples to the output stream - addTriples: function (triples) { - for (var i = 0; i < triples.length; i++) - this.addTriple(triples[i]); - }, + // prefer @index if available in value + var containers = []; + if(_isObject(value) && '@index' in value) { + containers.push('@index'); + } - // ### `addPrefix` adds the prefix to the output stream - addPrefix: function (prefix, iri, done) { - var prefixes = {}; - prefixes[prefix] = iri; - this.addPrefixes(prefixes, done); - }, + // defaults for term selection based on type/language + var typeOrLanguage = '@language'; + var typeOrLanguageValue = '@null'; - // ### `addPrefixes` adds the prefixes to the output stream - addPrefixes: function (prefixes, done) { - // Add all useful prefixes - var prefixIRIs = this._prefixIRIs, hasPrefixes = false; - for (var prefix in prefixes) { - // Verify whether the prefix can be used and does not exist yet - var iri = prefixes[prefix]; - if (/[#\/]$/.test(iri) && prefixIRIs[iri] !== (prefix += ':')) { - hasPrefixes = true; - prefixIRIs[iri] = prefix; - // Finish a possible pending triple - if (this._subject !== null) { - this._write(this._graph ? '\n}\n' : '.\n'); - this._subject = null, this._graph = ''; + if(reverse) { + typeOrLanguage = '@type'; + typeOrLanguageValue = '@reverse'; + containers.push('@set'); + } else if(_isList(value)) { + // choose the most specific term that works for all elements in @list + // only select @list containers if @index is NOT in value + if(!('@index' in value)) { + containers.push('@list'); + } + var list = value['@list']; + var commonLanguage = (list.length === 0) ? defaultLanguage : null; + var commonType = null; + for(var i = 0; i < list.length; ++i) { + var item = list[i]; + var itemLanguage = '@none'; + var itemType = '@none'; + if(_isValue(item)) { + if('@language' in item) { + itemLanguage = item['@language']; + } else if('@type' in item) { + itemType = item['@type']; + } else { + // plain literal + itemLanguage = '@null'; + } + } else { + itemType = '@id'; + } + if(commonLanguage === null) { + commonLanguage = itemLanguage; + } else if(itemLanguage !== commonLanguage && _isValue(item)) { + commonLanguage = '@none'; + } + if(commonType === null) { + commonType = itemType; + } else if(itemType !== commonType) { + commonType = '@none'; + } + // there are different languages and types in the list, so choose + // the most generic term, no need to keep iterating the list + if(commonLanguage === '@none' && commonType === '@none') { + break; } - // Write prefix - this._write('@prefix ' + prefix + ' <' + iri + '>.\n'); } - } - // Recreate the prefix matcher - if (hasPrefixes) { - var IRIlist = '', prefixList = ''; - for (var prefixIRI in prefixIRIs) { - IRIlist += IRIlist ? '|' + prefixIRI : prefixIRI; - prefixList += (prefixList ? '|' : '') + prefixIRIs[prefixIRI]; + commonLanguage = commonLanguage || '@none'; + commonType = commonType || '@none'; + if(commonType !== '@none') { + typeOrLanguage = '@type'; + typeOrLanguageValue = commonType; + } else { + typeOrLanguageValue = commonLanguage; } - IRIlist = IRIlist.replace(/[\]\/\(\)\*\+\?\.\\\$]/g, '\\$&'); - this._prefixRegex = new RegExp('^(?:' + prefixList + ')[^\/]*$|' + - '^(' + IRIlist + ')([a-zA-Z][\\-_a-zA-Z0-9]*)$'); - } - // End a prefix block with a newline - this._write(hasPrefixes ? '\n' : '', done); - }, - - // ### `blank` creates a blank node with the given content - blank: function (predicate, object) { - var children = predicate, child, length; - // Empty blank node - if (predicate === undefined) - children = []; - // Blank node passed as blank("predicate", "object") - else if (typeof predicate === 'string') - children = [{ predicate: predicate, object: object }]; - // Blank node passed as blank({ predicate: predicate, object: object }) - else if (!('length' in predicate)) - children = [predicate]; - - switch (length = children.length) { - // Generate an empty blank node - case 0: - return '[]'; - // Generate a non-nested one-triple blank node - case 1: - child = children[0]; - if (child.object[0] !== '[') - return '[ ' + this._encodePredicate(child.predicate) + ' ' + - this._encodeObject(child.object) + ' ]'; - // Generate a multi-triple or nested blank node - default: - var contents = '['; - // Write all triples in order - for (var i = 0; i < length; i++) { - child = children[i]; - // Write only the object is the predicate is the same as the previous - if (child.predicate === predicate) - contents += ', ' + this._encodeObject(child.object); - // Otherwise, write the predicate and the object - else { - contents += (i ? ';\n ' : '\n ') + - this._encodePredicate(child.predicate) + ' ' + - this._encodeObject(child.object); - predicate = child.predicate; + } else { + if(_isValue(value)) { + if('@language' in value && !('@index' in value)) { + containers.push('@language'); + typeOrLanguageValue = value['@language']; + } else if('@type' in value) { + typeOrLanguage = '@type'; + typeOrLanguageValue = value['@type']; } + } else { + typeOrLanguage = '@type'; + typeOrLanguageValue = '@id'; } - return contents + '\n]'; + containers.push('@set'); } - }, - - // ### `list` creates a list node with the given content - list: function (elements) { - var length = elements && elements.length || 0, contents = new Array(length); - for (var i = 0; i < length; i++) - contents[i] = this._encodeObject(elements[i]); - return '(' + contents.join(' ') + ')'; - }, - - // ### `_prefixRegex` matches a prefixed name or IRI that begins with one of the added prefixes - _prefixRegex: /$0^/, - // ### `end` signals the end of the output stream - end: function (done) { - // Finish a possible pending triple - if (this._subject !== null) { - this._write(this._graph ? '\n}\n' : '.\n'); - this._subject = null; + // do term selection + containers.push('@none'); + var term = _selectTerm( + activeCtx, iri, value, containers, typeOrLanguage, typeOrLanguageValue); + if(term !== null) { + return term; } - // Disallow further writing - this._write = this._blockedWrite; + } - // Try to end the underlying stream, ensuring done is called exactly one time - var singleDone = done && function (error, result) { singleDone = null, done(error, result); }; - if (this._endStream) { - try { return this._outputStream.end(singleDone); } - catch (error) { /* error closing stream */ } + // no term match, use @vocab if available + if(relativeTo.vocab) { + if('@vocab' in activeCtx) { + // determine if vocab is a prefix of the iri + var vocab = activeCtx['@vocab']; + if(iri.indexOf(vocab) === 0 && iri !== vocab) { + // use suffix as relative iri if it is not a term in the active context + var suffix = iri.substr(vocab.length); + if(!(suffix in activeCtx.mappings)) { + return suffix; + } + } } - singleDone && singleDone(); - }, -}; + } -// Replaces a character by its escaped version -function characterReplacer(character) { - // Replace a single character by its escaped version - var result = escapeReplacements[character]; - if (result === undefined) { - // Replace a single character with its 4-bit unicode escape sequence - if (character.length === 1) { - result = character.charCodeAt(0).toString(16); - result = '\\u0000'.substr(0, 6 - result.length) + result; + // no term or @vocab match, check for possible CURIEs + var choice = null; + var idx = 0; + var partialMatches = []; + var iriMap = activeCtx.fastCurieMap; + // check for partial matches of against `iri`, which means look until + // iri.length - 1, not full length + var maxPartialLength = iri.length - 1; + for(; idx < maxPartialLength && iri[idx] in iriMap; ++idx) { + iriMap = iriMap[iri[idx]]; + if('' in iriMap) { + partialMatches.push(iriMap[''][0]); } - // Replace a surrogate pair with its 8-bit unicode escape sequence - else { - result = ((character.charCodeAt(0) - 0xD800) * 0x400 + - character.charCodeAt(1) + 0x2400).toString(16); - result = '\\U00000000'.substr(0, 10 - result.length) + result; + } + // check partial matches in reverse order to prefer longest ones first + for(var i = partialMatches.length - 1; i >= 0; --i) { + var entry = partialMatches[i]; + var terms = entry.terms; + for(var ti = 0; ti < terms.length; ++ti) { + // a CURIE is usable if: + // 1. it has no mapping, OR + // 2. value is null, which means we're not compacting an @value, AND + // the mapping matches the IRI + var curie = terms[ti] + ':' + iri.substr(entry.iri.length); + var isUsableCurie = (!(curie in activeCtx.mappings) || + (value === null && activeCtx.mappings[curie]['@id'] === iri)); + + // select curie if it is shorter or the same length but lexicographically + // less than the current choice + if(isUsableCurie && (choice === null || + _compareShortestLeast(curie, choice) < 0)) { + choice = curie; + } } } - return result; -} -// ## Exports -module.exports = N3Writer; + // return chosen curie + if(choice !== null) { + return choice; + } -},{}],33:[function(_dereq_,module,exports){ -'use strict'; + // compact IRI relative to base + if(!relativeTo.vocab) { + return _removeBase(activeCtx['@base'], iri); + } -// modified from https://github.com/es-shims/es5-shim -var has = Object.prototype.hasOwnProperty; -var toStr = Object.prototype.toString; -var slice = Array.prototype.slice; -var isArgs = _dereq_('./isArguments'); -var isEnumerable = Object.prototype.propertyIsEnumerable; -var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString'); -var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype'); -var dontEnums = [ - 'toString', - 'toLocaleString', - 'valueOf', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'constructor' -]; -var equalsConstructorPrototype = function (o) { - var ctor = o.constructor; - return ctor && ctor.prototype === o; -}; -var excludedKeys = { - $console: true, - $external: true, - $frame: true, - $frameElement: true, - $frames: true, - $innerHeight: true, - $innerWidth: true, - $outerHeight: true, - $outerWidth: true, - $pageXOffset: true, - $pageYOffset: true, - $parent: true, - $scrollLeft: true, - $scrollTop: true, - $scrollX: true, - $scrollY: true, - $self: true, - $webkitIndexedDB: true, - $webkitStorageInfo: true, - $window: true -}; -var hasAutomationEqualityBug = (function () { - /* global window */ - if (typeof window === 'undefined') { return false; } - for (var k in window) { - try { - if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { - try { - equalsConstructorPrototype(window[k]); - } catch (e) { - return true; - } - } - } catch (e) { - return true; - } - } - return false; -}()); -var equalsConstructorPrototypeIfNotBuggy = function (o) { - /* global window */ - if (typeof window === 'undefined' || !hasAutomationEqualityBug) { - return equalsConstructorPrototype(o); - } - try { - return equalsConstructorPrototype(o); - } catch (e) { - return false; - } -}; + // return IRI as is + return iri; +} -var keysShim = function keys(object) { - var isObject = object !== null && typeof object === 'object'; - var isFunction = toStr.call(object) === '[object Function]'; - var isArguments = isArgs(object); - var isString = isObject && toStr.call(object) === '[object String]'; - var theKeys = []; +/** + * Performs value compaction on an object with '@value' or '@id' as the only + * property. + * + * @param activeCtx the active context. + * @param activeProperty the active property that points to the value. + * @param value the value to compact. + * + * @return the compaction result. + */ +function _compactValue(activeCtx, activeProperty, value) { + // value is a @value + if(_isValue(value)) { + // get context rules + var type = jsonld.getContextValue(activeCtx, activeProperty, '@type'); + var language = jsonld.getContextValue( + activeCtx, activeProperty, '@language'); + var container = jsonld.getContextValue( + activeCtx, activeProperty, '@container'); - if (!isObject && !isFunction && !isArguments) { - throw new TypeError('Object.keys called on a non-object'); - } + // whether or not the value has an @index that must be preserved + var preserveIndex = (('@index' in value) && + container !== '@index'); - var skipProto = hasProtoEnumBug && isFunction; - if (isString && object.length > 0 && !has.call(object, 0)) { - for (var i = 0; i < object.length; ++i) { - theKeys.push(String(i)); - } - } + // if there's no @index to preserve ... + if(!preserveIndex) { + // matching @type or @language specified in context, compact value + if(value['@type'] === type || value['@language'] === language) { + return value['@value']; + } + } - if (isArguments && object.length > 0) { - for (var j = 0; j < object.length; ++j) { - theKeys.push(String(j)); - } - } else { - for (var name in object) { - if (!(skipProto && name === 'prototype') && has.call(object, name)) { - theKeys.push(String(name)); - } - } - } + // return just the value of @value if all are true: + // 1. @value is the only key or @index isn't being preserved + // 2. there is no default language or @value is not a string or + // the key has a mapping with a null @language + var keyCount = Object.keys(value).length; + var isValueOnlyKey = (keyCount === 1 || + (keyCount === 2 && ('@index' in value) && !preserveIndex)); + var hasDefaultLanguage = ('@language' in activeCtx); + var isValueString = _isString(value['@value']); + var hasNullMapping = (activeCtx.mappings[activeProperty] && + activeCtx.mappings[activeProperty]['@language'] === null); + if(isValueOnlyKey && + (!hasDefaultLanguage || !isValueString || hasNullMapping)) { + return value['@value']; + } - if (hasDontEnumBug) { - var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); + var rval = {}; - for (var k = 0; k < dontEnums.length; ++k) { - if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { - theKeys.push(dontEnums[k]); - } - } - } - return theKeys; -}; + // preserve @index + if(preserveIndex) { + rval[_compactIri(activeCtx, '@index')] = value['@index']; + } -keysShim.shim = function shimObjectKeys() { - if (Object.keys) { - var keysWorksWithArguments = (function () { - // Safari 5.0 bug - return (Object.keys(arguments) || '').length === 2; - }(1, 2)); - if (!keysWorksWithArguments) { - var originalKeys = Object.keys; - Object.keys = function keys(object) { - if (isArgs(object)) { - return originalKeys(slice.call(object)); - } else { - return originalKeys(object); - } - }; - } - } else { - Object.keys = keysShim; - } - return Object.keys || keysShim; -}; + if('@type' in value) { + // compact @type IRI + rval[_compactIri(activeCtx, '@type')] = _compactIri( + activeCtx, value['@type'], null, {vocab: true}); + } else if('@language' in value) { + // alias @language + rval[_compactIri(activeCtx, '@language')] = value['@language']; + } -module.exports = keysShim; + // alias @value + rval[_compactIri(activeCtx, '@value')] = value['@value']; -},{"./isArguments":34}],34:[function(_dereq_,module,exports){ -'use strict'; + return rval; + } -var toStr = Object.prototype.toString; + // value is a subject reference + var expandedProperty = _expandIri(activeCtx, activeProperty, {vocab: true}); + var type = jsonld.getContextValue(activeCtx, activeProperty, '@type'); + var compacted = _compactIri( + activeCtx, value['@id'], null, {vocab: type === '@vocab'}); -module.exports = function isArguments(value) { - var str = toStr.call(value); - var isArgs = str === '[object Arguments]'; - if (!isArgs) { - isArgs = str !== '[object Array]' && - value !== null && - typeof value === 'object' && - typeof value.length === 'number' && - value.length >= 0 && - toStr.call(value.callee) === '[object Function]'; - } - return isArgs; -}; + // compact to scalar + if(type === '@id' || type === '@vocab' || expandedProperty === '@graph') { + return compacted; + } + + var rval = {}; + rval[_compactIri(activeCtx, '@id')] = compacted; + return rval; +} -},{}],35:[function(_dereq_,module,exports){ /** -* pretty-data - nodejs plugin to pretty-print or minify data in XML, JSON and CSS formats. -* -* Version - 0.40.0 -* Copyright (c) 2012 Vadim Kiryukhin -* vkiryukhin @ gmail.com -* http://www.eslinstructor.net/pretty-data/ -* -* Dual licensed under the MIT and GPL licenses: -* http://www.opensource.org/licenses/mit-license.php -* http://www.gnu.org/licenses/gpl.html -* -* pd.xml(data ) - pretty print XML; -* pd.json(data) - pretty print JSON; -* pd.css(data ) - pretty print CSS; -* pd.sql(data) - pretty print SQL; -* -* pd.xmlmin(data [, preserveComments] ) - minify XML; -* pd.jsonmin(data) - minify JSON; -* pd.cssmin(data [, preserveComments] ) - minify CSS; -* pd.sqlmin(data) - minify SQL; -* -* PARAMETERS: -* -* @data - String; XML, JSON, CSS or SQL text to beautify; -* @preserveComments - Bool (optional, used in minxml and mincss only); -* Set this flag to true to prevent removing comments from @text; -* @Return - String; -* -* USAGE: -* -* var pd = require('pretty-data').pd; -* -* var xml_pp = pd.xml(xml_text); -* var xml_min = pd.xmlmin(xml_text [,true]); -* var json_pp = pd.json(json_text); -* var json_min = pd.jsonmin(json_text); -* var css_pp = pd.css(css_text); -* var css_min = pd.cssmin(css_text [, true]); -* var sql_pp = pd.sql(sql_text); -* var sql_min = pd.sqlmin(sql_text); -* -* TEST: -* comp-name:pretty-data$ node ./test/test_xml -* comp-name:pretty-data$ node ./test/test_json -* comp-name:pretty-data$ node ./test/test_css -* comp-name:pretty-data$ node ./test/test_sql -*/ + * Creates a term definition during context processing. + * + * @param activeCtx the current active context. + * @param localCtx the local context being processed. + * @param term the term in the local context to define the mapping for. + * @param defined a map of defining/defined keys to detect cycles and prevent + * double definitions. + */ +function _createTermDefinition(activeCtx, localCtx, term, defined) { + if(term in defined) { + // term already defined + if(defined[term]) { + return; + } + // cycle detected + throw new JsonLdError( + 'Cyclical context definition detected.', + 'jsonld.CyclicalContext', + {code: 'cyclic IRI mapping', context: localCtx, term: term}); + } + // now defining term + defined[term] = false; -function pp() { - this.shift = ['\n']; // array of shifts - this.step = ' ', // 2 spaces - maxdeep = 100, // nesting level - ix = 0; + if(_isKeyword(term)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; keywords cannot be overridden.', + 'jsonld.SyntaxError', + {code: 'keyword redefinition', context: localCtx, term: term}); + } - // initialize array with shifts // - for(ix=0;ix\s{0,}<") - .replace(/ or -1) { - str += this.shift[deep]+ar[ix]; - inComment = true; - // end comment or // - if(ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1 || ar[ix].search(/!DOCTYPE/) > -1 ) { - inComment = false; - } - } else - // end comment or // - if(ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1) { - str += ar[ix]; - inComment = false; - } else - // // - if( /^<\w/.exec(ar[ix-1]) && /^<\/\w/.exec(ar[ix]) && - /^<[\w:\-\.\,]+/.exec(ar[ix-1]) == /^<\/[\w:\-\.\,]+/.exec(ar[ix])[0].replace('/','')) { - str += ar[ix]; - if(!inComment) deep--; - } else - // // - if(ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) == -1 && ar[ix].search(/\/>/) == -1 ) { - str = !inComment ? str += this.shift[deep++]+ar[ix] : str += ar[ix]; - } else - // ... // - if(ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) > -1) { - str = !inComment ? str += this.shift[deep]+ar[ix] : str += ar[ix]; - } else - // // - if(ar[ix].search(/<\//) > -1) { - str = !inComment ? str += this.shift[--deep]+ar[ix] : str += ar[ix]; - } else - // // - if(ar[ix].search(/\/>/) > -1 ) { - str = !inComment ? str += this.shift[deep]+ar[ix] : str += ar[ix]; - } else - // // - if(ar[ix].search(/<\?/) > -1) { - str += this.shift[deep]+ar[ix]; - } else - // xmlns // - if( ar[ix].search(/xmlns\:/) > -1 || ar[ix].search(/xmlns\=/) > -1) { - str += this.shift[deep]+ar[ix]; - } - - else { - str += ar[ix]; - } - } - - return (str[0] == '\n') ? str.slice(1) : str; -} + // convert short-hand value to object w/@id + if(_isString(value)) { + value = {'@id': value}; + } -// ----------------------- JSON section ---------------------------------------------------- + if(!_isObject(value)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; @context property values must be ' + + 'strings or objects.', + 'jsonld.SyntaxError', + {code: 'invalid term definition', context: localCtx}); + } -pp.prototype.json = function(text) { + // create new mapping + var mapping = activeCtx.mappings[term] = {}; + mapping.reverse = false; - if ( typeof text === "string" ) { - return JSON.stringify(JSON.parse(text), null, this.step); - } - if ( typeof text === "object" ) { - return JSON.stringify(text, null, this.step); - } - return null; -} + if('@reverse' in value) { + if('@id' in value) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; a @reverse term definition must not ' + + 'contain @id.', 'jsonld.SyntaxError', + {code: 'invalid reverse property', context: localCtx}); + } + var reverse = value['@reverse']; + if(!_isString(reverse)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; a @context @reverse value must be a string.', + 'jsonld.SyntaxError', {code: 'invalid IRI mapping', context: localCtx}); + } -// ----------------------- CSS section ---------------------------------------------------- + // expand and add @id mapping + var id = _expandIri( + activeCtx, reverse, {vocab: true, base: false}, localCtx, defined); + if(!_isAbsoluteIri(id)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; a @context @reverse value must be an ' + + 'absolute IRI or a blank node identifier.', + 'jsonld.SyntaxError', {code: 'invalid IRI mapping', context: localCtx}); + } + mapping['@id'] = id; + mapping.reverse = true; + } else if('@id' in value) { + var id = value['@id']; + if(!_isString(id)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; a @context @id value must be an array ' + + 'of strings or a string.', + 'jsonld.SyntaxError', {code: 'invalid IRI mapping', context: localCtx}); + } + if(id !== term) { + // expand and add @id mapping + id = _expandIri( + activeCtx, id, {vocab: true, base: false}, localCtx, defined); + if(!_isAbsoluteIri(id) && !_isKeyword(id)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; a @context @id value must be an ' + + 'absolute IRI, a blank node identifier, or a keyword.', + 'jsonld.SyntaxError', + {code: 'invalid IRI mapping', context: localCtx}); + } + mapping['@id'] = id; + } + } -pp.prototype.css = function(text) { + // always compute whether term has a colon as an optimization for + // _compactIri + var colon = term.indexOf(':'); + mapping._termHasColon = (colon !== -1); - var ar = text.replace(/\s{1,}/g,' ') - .replace(/\{/g,"{~::~") - .replace(/\}/g,"~::~}~::~") - .replace(/\;/g,";~::~") - .replace(/\/\*/g,"~::~/*") - .replace(/\*\//g,"*/~::~") - .replace(/~::~\s{0,}~::~/g,"~::~") - .split('~::~'), - len = ar.length, - deep = 0, - str = '', - ix = 0; - - for(ix=0;ix/g,""); - return str.replace(/>\s{0,}<"); -} + // prepend base + var rval = value; + if(relativeTo.base) { + rval = jsonld.prependBase(activeCtx['@base'], rval); + } -pp.prototype.jsonmin = function(text) { - - return text.replace(/\s{0,}\{\s{0,}/g,"{") - .replace(/\s{0,}\[$/g,"[") - .replace(/\[\s{0,}/g,"[") - .replace(/:\s{0,}\[/g,':[') - .replace(/\s{0,}\}\s{0,}/g,"}") - .replace(/\s{0,}\]\s{0,}/g,"]") - .replace(/\"\s{0,}\,/g,'",') - .replace(/\,\s{0,}\"/g,',"') - .replace(/\"\s{0,}:/g,'":') - .replace(/:\s{0,}\"/g,':"') - .replace(/:\s{0,}\[/g,':[') - .replace(/\,\s{0,}\[/g,',[') - .replace(/\,\s{2,}/g,', ') - .replace(/\]\s{0,},\s{0,}\[/g,'],['); + return rval; } -pp.prototype.cssmin = function(text, preserveComments) { - - var str = preserveComments ? text - : text.replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\//g,"") ; - return str.replace(/\s{1,}/g,' ') - .replace(/\{\s{1,}/g,"{") - .replace(/\}\s{1,}/g,"}") - .replace(/\;\s{1,}/g,";") - .replace(/\/\*\s{1,}/g,"/*") - .replace(/\*\/\s{1,}/g,"*/"); -} - -pp.prototype.sqlmin = function(text) { - return text.replace(/\s{1,}/g," ").replace(/\s{1,}\(/,"(").replace(/\s{1,}\)/,")"); -} +function _prependBase(base, iri) { + // skip IRI processing + if(base === null) { + return iri; + } + // already an absolute IRI + if(iri.indexOf(':') !== -1) { + return iri; + } -// -------------------------------------------------------------------------------------------- + // parse base if it is a string + if(_isString(base)) { + base = jsonld.url.parse(base || ''); + } -exports.pd= new pp; + // parse given IRI + var rel = jsonld.url.parse(iri); + // per RFC3986 5.2.2 + var transform = { + protocol: base.protocol || '' + }; + if(rel.authority !== null) { + transform.authority = rel.authority; + transform.path = rel.path; + transform.query = rel.query; + } else { + transform.authority = base.authority; + if(rel.path === '') { + transform.path = base.path; + if(rel.query !== null) { + transform.query = rel.query; + } else { + transform.query = base.query; + } + } else { + if(rel.path.indexOf('/') === 0) { + // IRI represents an absolute path + transform.path = rel.path; + } else { + // merge paths + var path = base.path; + // append relative path to the end of the last directory from base + if(rel.path !== '') { + path = path.substr(0, path.lastIndexOf('/') + 1); + if(path.length > 0 && path.substr(-1) !== '/') { + path += '/'; + } + path += rel.path; + } + transform.path = path; + } + transform.query = rel.query; + } + } + // remove slashes and dots in path + transform.path = _removeDotSegments(transform.path, !!transform.authority); + // construct URL + var rval = transform.protocol; + if(transform.authority !== null) { + rval += '//' + transform.authority; + } + rval += transform.path; + if(transform.query !== null) { + rval += '?' + transform.query; + } + if(rel.fragment !== null) { + rval += '#' + rel.fragment; + } + // handle empty base + if(rval === '') { + rval = './'; + } + return rval; +} +/** + * Removes a base IRI from the given absolute IRI. + * + * @param base the base IRI. + * @param iri the absolute IRI. + * + * @return the relative IRI if relative to base, otherwise the absolute IRI. + */ +function _removeBase(base, iri) { + // skip IRI processing + if(base === null) { + return iri; + } -},{}],36:[function(_dereq_,module,exports){ -(function (process){ -'use strict'; + if(_isString(base)) { + base = jsonld.url.parse(base || ''); + } -if (!process.version || - process.version.indexOf('v0.') === 0 || - process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) { - module.exports = nextTick; -} else { - module.exports = process.nextTick; -} + // establish base root + var root = ''; + if(base.href !== '') { + root += (base.protocol || '') + '//' + (base.authority || ''); + } else if(iri.indexOf('//')) { + // support network-path reference with empty base + root += '//'; + } -function nextTick(fn, arg1, arg2, arg3) { - if (typeof fn !== 'function') { - throw new TypeError('"callback" argument must be a function'); + // IRI not relative to base + if(iri.indexOf(root) !== 0) { + return iri; } - var len = arguments.length; - var args, i; - switch (len) { - case 0: - case 1: - return process.nextTick(fn); - case 2: - return process.nextTick(function afterTickOne() { - fn.call(null, arg1); - }); - case 3: - return process.nextTick(function afterTickTwo() { - fn.call(null, arg1, arg2); - }); - case 4: - return process.nextTick(function afterTickThree() { - fn.call(null, arg1, arg2, arg3); - }); - default: - args = new Array(len - 1); - i = 0; - while (i < args.length) { - args[i++] = arguments[i]; + + // remove root from IRI and parse remainder + var rel = jsonld.url.parse(iri.substr(root.length)); + + // remove path segments that match (do not remove last segment unless there + // is a hash or query) + var baseSegments = base.normalizedPath.split('/'); + var iriSegments = rel.normalizedPath.split('/'); + var last = (rel.fragment || rel.query) ? 0 : 1; + while(baseSegments.length > 0 && iriSegments.length > last) { + if(baseSegments[0] !== iriSegments[0]) { + break; } - return process.nextTick(function afterTick() { - fn.apply(null, args); - }); + baseSegments.shift(); + iriSegments.shift(); } -} -}).call(this,_dereq_('_process')) + // use '../' for each non-matching base segment + var rval = ''; + if(baseSegments.length > 0) { + // don't count the last segment (if it ends with '/' last path doesn't + // count and if it doesn't end with '/' it isn't a path) + baseSegments.pop(); + for(var i = 0; i < baseSegments.length; ++i) { + rval += '../'; + } + } -},{"_process":37}],37:[function(_dereq_,module,exports){ -// shim for using process in browser -var process = module.exports = {}; + // prepend remaining segments + rval += iriSegments.join('/'); -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. + // add query and hash + if(rel.query !== null) { + rval += '?' + rel.query; + } + if(rel.fragment !== null) { + rval += '#' + rel.fragment; + } -var cachedSetTimeout; -var cachedClearTimeout; + // handle empty base + if(rval === '') { + rval = './'; + } -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); + return rval; } -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } +/** + * Gets the initial context. + * + * @param options the options to use: + * [base] the document base IRI. + * + * @return the initial context. + */ +function _getInitialContext(options) { + var base = jsonld.url.parse(options.base || ''); + return { + '@base': base, + mappings: {}, + inverse: null, + getInverse: _createInverseContext, + clone: _cloneActiveContext + }; -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } + /** + * Generates an inverse context for use in the compaction algorithm, if + * not already generated for the given active context. + * + * @return the inverse context. + */ + function _createInverseContext() { + var activeCtx = this; + + // lazily create inverse + if(activeCtx.inverse) { + return activeCtx.inverse; } + var inverse = activeCtx.inverse = {}; + // variables for building fast CURIE map + var fastCurieMap = activeCtx.fastCurieMap = {}; + var irisToTerms = {}; + // handle default language + var defaultLanguage = activeCtx['@language'] || '@none'; -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; + // create term selections for each mapping in the context, ordered by + // shortest and then lexicographically least + var mappings = activeCtx.mappings; + var terms = Object.keys(mappings).sort(_compareShortestLeast); + for(var i = 0; i < terms.length; ++i) { + var term = terms[i]; + var mapping = mappings[term]; + if(mapping === null) { + continue; + } -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} + var container = mapping['@container'] || '@none'; -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; + // iterate over every IRI in the mapping + var ids = mapping['@id']; + if(!_isArray(ids)) { + ids = [ids]; + } + for(var ii = 0; ii < ids.length; ++ii) { + var iri = ids[ii]; + var entry = inverse[iri]; + var isKeyword = _isKeyword(iri); - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); + if(!entry) { + // initialize entry + inverse[iri] = entry = {}; + + if(!isKeyword && !mapping._termHasColon) { + // init IRI to term map and fast CURIE prefixes + irisToTerms[iri] = [term]; + var fastCurieEntry = {iri: iri, terms: irisToTerms[iri]}; + if(iri[0] in fastCurieMap) { + fastCurieMap[iri[0]].push(fastCurieEntry); + } else { + fastCurieMap[iri[0]] = [fastCurieEntry]; } + } + } else if(!isKeyword && !mapping._termHasColon) { + // add IRI to term match + irisToTerms[iri].push(term); } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; + // add new entry + if(!entry[container]) { + entry[container] = { + '@language': {}, + '@type': {} + }; } + entry = entry[container]; + + if(mapping.reverse) { + // term is preferred for values using @reverse + _addPreferredTerm(mapping, term, entry['@type'], '@reverse'); + } else if('@type' in mapping) { + // term is preferred for values using specific type + _addPreferredTerm(mapping, term, entry['@type'], mapping['@type']); + } else if('@language' in mapping) { + // term is preferred for values using specific language + var language = mapping['@language'] || '@null'; + _addPreferredTerm(mapping, term, entry['@language'], language); + } else { + // term is preferred for values w/default language or no type and + // no language + // add an entry for the default language + _addPreferredTerm(mapping, term, entry['@language'], defaultLanguage); + + // add entries for no type and no language + _addPreferredTerm(mapping, term, entry['@type'], '@none'); + _addPreferredTerm(mapping, term, entry['@language'], '@none'); + } + } } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; + // build fast CURIE map + for(var key in fastCurieMap) { + _buildIriMap(fastCurieMap, key, 1); + } -function noop() {} + return inverse; + } -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; + /** + * Runs a recursive algorithm to build a lookup map for quickly finding + * potential CURIEs. + * + * @param iriMap the map to build. + * @param key the current key in the map to work on. + * @param idx the index into the IRI to compare. + */ + function _buildIriMap(iriMap, key, idx) { + var entries = iriMap[key]; + var next = iriMap[key] = {}; -process.listeners = function (name) { return [] } + var iri; + var letter; + for(var i = 0; i < entries.length; ++i) { + iri = entries[i].iri; + if(idx >= iri.length) { + letter = ''; + } else { + letter = iri[idx]; + } + if(letter in next) { + next[letter].push(entries[i]); + } else { + next[letter] = [entries[i]]; + } + } -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; + for(var key in next) { + if(key === '') { + continue; + } + _buildIriMap(next, key, idx + 1); + } + } -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; + /** + * Adds the term for the given entry if not already added. + * + * @param mapping the term mapping. + * @param term the term to add. + * @param entry the inverse context typeOrLanguage entry to add to. + * @param typeOrLanguageValue the key in the entry to add to. + */ + function _addPreferredTerm(mapping, term, entry, typeOrLanguageValue) { + if(!(typeOrLanguageValue in entry)) { + entry[typeOrLanguageValue] = term; + } + } -},{}],38:[function(_dereq_,module,exports){ -(function (global){ -/*! https://mths.be/punycode v1.4.1 by @mathias */ -;(function(root) { + /** + * Clones an active context, creating a child active context. + * + * @return a clone (child) of the active context. + */ + function _cloneActiveContext() { + var child = {}; + child['@base'] = this['@base']; + child.mappings = _clone(this.mappings); + child.clone = this.clone; + child.inverse = null; + child.getInverse = this.getInverse; + if('@language' in this) { + child['@language'] = this['@language']; + } + if('@vocab' in this) { + child['@vocab'] = this['@vocab']; + } + return child; + } +} - /** Detect free variables */ - var freeExports = typeof exports == 'object' && exports && - !exports.nodeType && exports; - var freeModule = typeof module == 'object' && module && - !module.nodeType && module; - var freeGlobal = typeof global == 'object' && global; - if ( - freeGlobal.global === freeGlobal || - freeGlobal.window === freeGlobal || - freeGlobal.self === freeGlobal - ) { - root = freeGlobal; - } +/** + * Returns whether or not the given value is a keyword. + * + * @param v the value to check. + * + * @return true if the value is a keyword, false if not. + */ +function _isKeyword(v) { + if(!_isString(v)) { + return false; + } + switch(v) { + case '@base': + case '@context': + case '@container': + case '@default': + case '@embed': + case '@explicit': + case '@graph': + case '@id': + case '@index': + case '@language': + case '@list': + case '@omitDefault': + case '@preserve': + case '@requireAll': + case '@reverse': + case '@set': + case '@type': + case '@value': + case '@vocab': + return true; + } + return false; +} - /** - * The `punycode` object. - * @name punycode - * @type Object - */ - var punycode, +/** + * Returns true if the given value is an Object. + * + * @param v the value to check. + * + * @return true if the value is an Object, false if not. + */ +function _isObject(v) { + return (Object.prototype.toString.call(v) === '[object Object]'); +} - /** Highest positive signed 32-bit float value */ - maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 +/** + * Returns true if the given value is an empty Object. + * + * @param v the value to check. + * + * @return true if the value is an empty Object, false if not. + */ +function _isEmptyObject(v) { + return _isObject(v) && Object.keys(v).length === 0; +} - /** Bootstring parameters */ - base = 36, - tMin = 1, - tMax = 26, - skew = 38, - damp = 700, - initialBias = 72, - initialN = 128, // 0x80 - delimiter = '-', // '\x2D' +/** + * Returns true if the given value is an Array. + * + * @param v the value to check. + * + * @return true if the value is an Array, false if not. + */ +function _isArray(v) { + return Array.isArray(v); +} - /** Regular expressions */ - regexPunycode = /^xn--/, - regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars - regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators +/** + * Throws an exception if the given value is not a valid @type value. + * + * @param v the value to check. + */ +function _validateTypeValue(v) { + // can be a string or an empty object + if(_isString(v) || _isEmptyObject(v)) { + return; + } - /** Error messages */ - errors = { - 'overflow': 'Overflow: input needs wider integers to process', - 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', - 'invalid-input': 'Invalid input' - }, + // must be an array + var isValid = false; + if(_isArray(v)) { + // must contain only strings + isValid = true; + for(var i = 0; i < v.length; ++i) { + if(!(_isString(v[i]))) { + isValid = false; + break; + } + } + } - /** Convenience shortcuts */ - baseMinusTMin = base - tMin, - floor = Math.floor, - stringFromCharCode = String.fromCharCode, + if(!isValid) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; "@type" value must a string, an array of ' + + 'strings, or an empty object.', 'jsonld.SyntaxError', + {code: 'invalid type value', value: v}); + } +} - /** Temporary variable */ - key; +/** + * Returns true if the given value is a String. + * + * @param v the value to check. + * + * @return true if the value is a String, false if not. + */ +function _isString(v) { + return (typeof v === 'string' || + Object.prototype.toString.call(v) === '[object String]'); +} - /*--------------------------------------------------------------------------*/ +/** + * Returns true if the given value is a Number. + * + * @param v the value to check. + * + * @return true if the value is a Number, false if not. + */ +function _isNumber(v) { + return (typeof v === 'number' || + Object.prototype.toString.call(v) === '[object Number]'); +} - /** - * A generic error utility function. - * @private - * @param {String} type The error type. - * @returns {Error} Throws a `RangeError` with the applicable error message. - */ - function error(type) { - throw new RangeError(errors[type]); - } +/** + * Returns true if the given value is a double. + * + * @param v the value to check. + * + * @return true if the value is a double, false if not. + */ +function _isDouble(v) { + return _isNumber(v) && String(v).indexOf('.') !== -1; +} - /** - * A generic `Array#map` utility function. - * @private - * @param {Array} array The array to iterate over. - * @param {Function} callback The function that gets called for every array - * item. - * @returns {Array} A new array of values returned by the callback function. - */ - function map(array, fn) { - var length = array.length; - var result = []; - while (length--) { - result[length] = fn(array[length]); - } - return result; - } +/** + * Returns true if the given value is numeric. + * + * @param v the value to check. + * + * @return true if the value is numeric, false if not. + */ +function _isNumeric(v) { + return !isNaN(parseFloat(v)) && isFinite(v); +} - /** - * A simple `Array#map`-like wrapper to work with domain name strings or email - * addresses. - * @private - * @param {String} domain The domain name or email address. - * @param {Function} callback The function that gets called for every - * character. - * @returns {Array} A new string of characters returned by the callback - * function. - */ - function mapDomain(string, fn) { - var parts = string.split('@'); - var result = ''; - if (parts.length > 1) { - // In email addresses, only the domain name should be punycoded. Leave - // the local part (i.e. everything up to `@`) intact. - result = parts[0] + '@'; - string = parts[1]; - } - // Avoid `split(regex)` for IE8 compatibility. See #17. - string = string.replace(regexSeparators, '\x2E'); - var labels = string.split('.'); - var encoded = map(labels, fn).join('.'); - return result + encoded; - } +/** + * Returns true if the given value is a Boolean. + * + * @param v the value to check. + * + * @return true if the value is a Boolean, false if not. + */ +function _isBoolean(v) { + return (typeof v === 'boolean' || + Object.prototype.toString.call(v) === '[object Boolean]'); +} - /** - * Creates an array containing the numeric code points of each Unicode - * character in the string. While JavaScript uses UCS-2 internally, - * this function will convert a pair of surrogate halves (each of which - * UCS-2 exposes as separate characters) into a single code point, - * matching UTF-16. - * @see `punycode.ucs2.encode` - * @see - * @memberOf punycode.ucs2 - * @name decode - * @param {String} string The Unicode input string (UCS-2). - * @returns {Array} The new array of code points. - */ - function ucs2decode(string) { - var output = [], - counter = 0, - length = string.length, - value, - extra; - while (counter < length) { - value = string.charCodeAt(counter++); - if (value >= 0xD800 && value <= 0xDBFF && counter < length) { - // high surrogate, and there is a next character - extra = string.charCodeAt(counter++); - if ((extra & 0xFC00) == 0xDC00) { // low surrogate - output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); - } else { - // unmatched surrogate; only append this code unit, in case the next - // code unit is the high surrogate of a surrogate pair - output.push(value); - counter--; - } - } else { - output.push(value); - } - } - return output; - } +/** + * Returns true if the given value is undefined. + * + * @param v the value to check. + * + * @return true if the value is undefined, false if not. + */ +function _isUndefined(v) { + return (typeof v === 'undefined'); +} - /** - * Creates a string based on an array of numeric code points. - * @see `punycode.ucs2.decode` - * @memberOf punycode.ucs2 - * @name encode - * @param {Array} codePoints The array of numeric code points. - * @returns {String} The new Unicode string (UCS-2). - */ - function ucs2encode(array) { - return map(array, function(value) { - var output = ''; - if (value > 0xFFFF) { - value -= 0x10000; - output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); - value = 0xDC00 | value & 0x3FF; - } - output += stringFromCharCode(value); - return output; - }).join(''); - } +/** + * Returns true if the given value is a subject with properties. + * + * @param v the value to check. + * + * @return true if the value is a subject with properties, false if not. + */ +function _isSubject(v) { + // Note: A value is a subject if all of these hold true: + // 1. It is an Object. + // 2. It is not a @value, @set, or @list. + // 3. It has more than 1 key OR any existing key is not @id. + var rval = false; + if(_isObject(v) && + !(('@value' in v) || ('@set' in v) || ('@list' in v))) { + var keyCount = Object.keys(v).length; + rval = (keyCount > 1 || !('@id' in v)); + } + return rval; +} - /** - * Converts a basic code point into a digit/integer. - * @see `digitToBasic()` - * @private - * @param {Number} codePoint The basic numeric code point value. - * @returns {Number} The numeric value of a basic code point (for use in - * representing integers) in the range `0` to `base - 1`, or `base` if - * the code point does not represent a value. - */ - function basicToDigit(codePoint) { - if (codePoint - 48 < 10) { - return codePoint - 22; - } - if (codePoint - 65 < 26) { - return codePoint - 65; - } - if (codePoint - 97 < 26) { - return codePoint - 97; - } - return base; - } +/** + * Returns true if the given value is a subject reference. + * + * @param v the value to check. + * + * @return true if the value is a subject reference, false if not. + */ +function _isSubjectReference(v) { + // Note: A value is a subject reference if all of these hold true: + // 1. It is an Object. + // 2. It has a single key: @id. + return (_isObject(v) && Object.keys(v).length === 1 && ('@id' in v)); +} - /** - * Converts a digit/integer into a basic code point. - * @see `basicToDigit()` - * @private - * @param {Number} digit The numeric value of a basic code point. - * @returns {Number} The basic code point whose value (when used for - * representing integers) is `digit`, which needs to be in the range - * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is - * used; else, the lowercase form is used. The behavior is undefined - * if `flag` is non-zero and `digit` has no uppercase form. - */ - function digitToBasic(digit, flag) { - // 0..25 map to ASCII a..z or A..Z - // 26..35 map to ASCII 0..9 - return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); - } +/** + * Returns true if the given value is a @value. + * + * @param v the value to check. + * + * @return true if the value is a @value, false if not. + */ +function _isValue(v) { + // Note: A value is a @value if all of these hold true: + // 1. It is an Object. + // 2. It has the @value property. + return _isObject(v) && ('@value' in v); +} - /** - * Bias adaptation function as per section 3.4 of RFC 3492. - * https://tools.ietf.org/html/rfc3492#section-3.4 - * @private - */ - function adapt(delta, numPoints, firstTime) { - var k = 0; - delta = firstTime ? floor(delta / damp) : delta >> 1; - delta += floor(delta / numPoints); - for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { - delta = floor(delta / baseMinusTMin); - } - return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); - } +/** + * Returns true if the given value is a @list. + * + * @param v the value to check. + * + * @return true if the value is a @list, false if not. + */ +function _isList(v) { + // Note: A value is a @list if all of these hold true: + // 1. It is an Object. + // 2. It has the @list property. + return _isObject(v) && ('@list' in v); +} - /** - * Converts a Punycode string of ASCII-only symbols to a string of Unicode - * symbols. - * @memberOf punycode - * @param {String} input The Punycode string of ASCII-only symbols. - * @returns {String} The resulting string of Unicode symbols. - */ - function decode(input) { - // Don't use UCS-2 - var output = [], - inputLength = input.length, - out, - i = 0, - n = initialN, - bias = initialBias, - basic, - j, - index, - oldi, - w, - k, - digit, - t, - /** Cached calculation results */ - baseMinusT; +/** + * Returns true if the given value is a blank node. + * + * @param v the value to check. + * + * @return true if the value is a blank node, false if not. + */ +function _isBlankNode(v) { + // Note: A value is a blank node if all of these hold true: + // 1. It is an Object. + // 2. If it has an @id key its value begins with '_:'. + // 3. It has no keys OR is not a @value, @set, or @list. + var rval = false; + if(_isObject(v)) { + if('@id' in v) { + rval = (v['@id'].indexOf('_:') === 0); + } else { + rval = (Object.keys(v).length === 0 || + !(('@value' in v) || ('@set' in v) || ('@list' in v))); + } + } + return rval; +} - // Handle the basic code points: let `basic` be the number of input code - // points before the last delimiter, or `0` if there is none, then copy - // the first basic code points to the output. +/** + * Returns true if the given value is an absolute IRI, false if not. + * + * @param v the value to check. + * + * @return true if the value is an absolute IRI, false if not. + */ +function _isAbsoluteIri(v) { + return _isString(v) && v.indexOf(':') !== -1; +} - basic = input.lastIndexOf(delimiter); - if (basic < 0) { - basic = 0; - } +/** + * Clones an object, array, or string/number. If a typed JavaScript object + * is given, such as a Date, it will be converted to a string. + * + * @param value the value to clone. + * + * @return the cloned value. + */ +function _clone(value) { + if(value && typeof value === 'object') { + var rval; + if(_isArray(value)) { + rval = []; + for(var i = 0; i < value.length; ++i) { + rval[i] = _clone(value[i]); + } + } else if(_isObject(value)) { + rval = {}; + for(var key in value) { + rval[key] = _clone(value[key]); + } + } else { + rval = value.toString(); + } + return rval; + } + return value; +} - for (j = 0; j < basic; ++j) { - // if it's not a basic code point - if (input.charCodeAt(j) >= 0x80) { - error('not-basic'); - } - output.push(input.charCodeAt(j)); - } +/** + * Finds all @context URLs in the given JSON-LD input. + * + * @param input the JSON-LD input. + * @param urls a map of URLs (url => false/@contexts). + * @param replace true to replace the URLs in the given input with the + * @contexts from the urls map, false not to. + * @param base the base IRI to use to resolve relative IRIs. + * + * @return true if new URLs to retrieve were found, false if not. + */ +function _findContextUrls(input, urls, replace, base) { + var count = Object.keys(urls).length; + if(_isArray(input)) { + for(var i = 0; i < input.length; ++i) { + _findContextUrls(input[i], urls, replace, base); + } + return (count < Object.keys(urls).length); + } else if(_isObject(input)) { + for(var key in input) { + if(key !== '@context') { + _findContextUrls(input[key], urls, replace, base); + continue; + } - // Main decoding loop: start just after the last delimiter if any basic code - // points were copied; start at the beginning otherwise. + // get @context + var ctx = input[key]; - for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { + // array @context + if(_isArray(ctx)) { + var length = ctx.length; + for(var i = 0; i < length; ++i) { + var _ctx = ctx[i]; + if(_isString(_ctx)) { + _ctx = jsonld.prependBase(base, _ctx); + // replace w/@context if requested + if(replace) { + _ctx = urls[_ctx]; + if(_isArray(_ctx)) { + // add flattened context + Array.prototype.splice.apply(ctx, [i, 1].concat(_ctx)); + i += _ctx.length - 1; + length = ctx.length; + } else { + ctx[i] = _ctx; + } + } else if(!(_ctx in urls)) { + // @context URL found + urls[_ctx] = false; + } + } + } + } else if(_isString(ctx)) { + // string @context + ctx = jsonld.prependBase(base, ctx); + // replace w/@context if requested + if(replace) { + input[key] = urls[ctx]; + } else if(!(ctx in urls)) { + // @context URL found + urls[ctx] = false; + } + } + } + return (count < Object.keys(urls).length); + } + return false; +} - // `index` is the index of the next character to be consumed. - // Decode a generalized variable-length integer into `delta`, - // which gets added to `i`. The overflow checking is easier - // if we increase `i` as we go, then subtract off its starting - // value at the end to obtain `delta`. - for (oldi = i, w = 1, k = base; /* no condition */; k += base) { +/** + * Retrieves external @context URLs using the given document loader. Every + * instance of @context in the input that refers to a URL will be replaced + * with the JSON @context found at that URL. + * + * @param input the JSON-LD input with possible contexts. + * @param options the options to use: + * documentLoader(url, callback(err, remoteDoc)) the document loader. + * @param callback(err, input) called once the operation completes. + */ +function _retrieveContextUrls(input, options, callback) { + // if any error occurs during URL resolution, quit + var error = null; - if (index >= inputLength) { - error('invalid-input'); - } + // recursive document loader + var documentLoader = options.documentLoader; + var retrieve = function(input, cycles, documentLoader, base, callback) { + if(Object.keys(cycles).length > MAX_CONTEXT_URLS) { + error = new JsonLdError( + 'Maximum number of @context URLs exceeded.', + 'jsonld.ContextUrlError', + {code: 'loading remote context failed', max: MAX_CONTEXT_URLS}); + return callback(error); + } - digit = basicToDigit(input.charCodeAt(index++)); + // for tracking the URLs to retrieve + var urls = {}; - if (digit >= base || digit > floor((maxInt - i) / w)) { - error('overflow'); - } + // finished will be called once the URL queue is empty + var finished = function() { + // replace all URLs in the input + _findContextUrls(input, urls, true, base); + callback(null, input); + }; - i += digit * w; - t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); + // find all URLs in the given input + if(!_findContextUrls(input, urls, false, base)) { + // no new URLs in input + return finished(); + } - if (digit < t) { - break; - } + // queue all unretrieved URLs + var queue = []; + for(var url in urls) { + if(urls[url] === false) { + queue.push(url); + } + } - baseMinusT = base - t; - if (w > floor(maxInt / baseMinusT)) { - error('overflow'); - } + // retrieve URLs in queue + var count = queue.length; + for(var i = 0; i < queue.length; ++i) { + (function(url) { + // check for context URL cycle + if(url in cycles) { + error = new JsonLdError( + 'Cyclical @context URLs detected.', + 'jsonld.ContextUrlError', + {code: 'recursive context inclusion', url: url}); + return callback(error); + } + var _cycles = _clone(cycles); + _cycles[url] = true; + var done = function(err, remoteDoc) { + // short-circuit if there was an error with another URL + if(error) { + return; + } - w *= baseMinusT; + var ctx = remoteDoc ? remoteDoc.document : null; - } + // parse string context as JSON + if(!err && _isString(ctx)) { + try { + ctx = JSON.parse(ctx); + } catch(ex) { + err = ex; + } + } - out = output.length + 1; - bias = adapt(i - oldi, out, oldi == 0); + // ensure ctx is an object + if(err) { + err = new JsonLdError( + 'Dereferencing a URL did not result in a valid JSON-LD object. ' + + 'Possible causes are an inaccessible URL perhaps due to ' + + 'a same-origin policy (ensure the server uses CORS if you are ' + + 'using client-side JavaScript), too many redirects, a ' + + 'non-JSON response, or more than one HTTP Link Header was ' + + 'provided for a remote context.', + 'jsonld.InvalidUrl', + {code: 'loading remote context failed', url: url, cause: err}); + } else if(!_isObject(ctx)) { + err = new JsonLdError( + 'Dereferencing a URL did not result in a JSON object. The ' + + 'response was valid JSON, but it was not a JSON object.', + 'jsonld.InvalidUrl', + {code: 'invalid remote context', url: url, cause: err}); + } + if(err) { + error = err; + return callback(error); + } - // `i` was supposed to wrap around from `out` to `0`, - // incrementing `n` each time, so we'll fix that now: - if (floor(i / out) > maxInt - n) { - error('overflow'); - } + // use empty context if no @context key is present + if(!('@context' in ctx)) { + ctx = {'@context': {}}; + } else { + ctx = {'@context': ctx['@context']}; + } - n += floor(i / out); - i %= out; - - // Insert `n` at position `i` of the output - output.splice(i++, 0, n); - - } - - return ucs2encode(output); - } - - /** - * Converts a string of Unicode symbols (e.g. a domain name label) to a - * Punycode string of ASCII-only symbols. - * @memberOf punycode - * @param {String} input The string of Unicode symbols. - * @returns {String} The resulting Punycode string of ASCII-only symbols. - */ - function encode(input) { - var n, - delta, - handledCPCount, - basicLength, - bias, - j, - m, - q, - k, - t, - currentValue, - output = [], - /** `inputLength` will hold the number of code points in `input`. */ - inputLength, - /** Cached calculation results */ - handledCPCountPlusOne, - baseMinusT, - qMinusT; - - // Convert the input in UCS-2 to Unicode - input = ucs2decode(input); - - // Cache the length - inputLength = input.length; - - // Initialize the state - n = initialN; - delta = 0; - bias = initialBias; - - // Handle the basic code points - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; - if (currentValue < 0x80) { - output.push(stringFromCharCode(currentValue)); - } - } - - handledCPCount = basicLength = output.length; - - // `handledCPCount` is the number of code points that have been handled; - // `basicLength` is the number of basic code points. - - // Finish the basic string - if it is not empty - with a delimiter - if (basicLength) { - output.push(delimiter); - } - - // Main encoding loop: - while (handledCPCount < inputLength) { - - // All non-basic code points < n have been handled already. Find the next - // larger one: - for (m = maxInt, j = 0; j < inputLength; ++j) { - currentValue = input[j]; - if (currentValue >= n && currentValue < m) { - m = currentValue; - } - } + // append context URL to context if given + if(remoteDoc.contextUrl) { + if(!_isArray(ctx['@context'])) { + ctx['@context'] = [ctx['@context']]; + } + ctx['@context'].push(remoteDoc.contextUrl); + } - // Increase `delta` enough to advance the decoder's state to , - // but guard against overflow - handledCPCountPlusOne = handledCPCount + 1; - if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { - error('overflow'); - } + // recurse + retrieve(ctx, _cycles, documentLoader, url, function(err, ctx) { + if(err) { + return callback(err); + } + urls[url] = ctx['@context']; + count -= 1; + if(count === 0) { + finished(); + } + }); + }; + var promise = documentLoader(url, done); + if(promise && 'then' in promise) { + promise.then(done.bind(null, null), done); + } + }(queue[i])); + } + }; + retrieve(input, {}, documentLoader, options.base, callback); +} - delta += (m - n) * handledCPCountPlusOne; - n = m; +// define js 1.8.5 Object.keys method if not present +if(!Object.keys) { + Object.keys = function(o) { + if(o !== Object(o)) { + throw new TypeError('Object.keys called on non-object'); + } + var rval = []; + for(var p in o) { + if(Object.prototype.hasOwnProperty.call(o, p)) { + rval.push(p); + } + } + return rval; + }; +} - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; +/** + * Parses RDF in the form of N-Quads. + * + * @param input the N-Quads input to parse. + * + * @return an RDF dataset. + */ +function _parseNQuads(input) { + // define partial regexes + var iri = '(?:<([^:]+:[^>]*)>)'; + var bnode = '(_:(?:[A-Za-z0-9]+))'; + var plain = '"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"'; + var datatype = '(?:\\^\\^' + iri + ')'; + var language = '(?:@([a-z]+(?:-[a-z0-9]+)*))'; + var literal = '(?:' + plain + '(?:' + datatype + '|' + language + ')?)'; + var comment = '(?:#.*)?'; + var ws = '[ \\t]+'; + var wso = '[ \\t]*'; + var eoln = /(?:\r\n)|(?:\n)|(?:\r)/g; + var empty = new RegExp('^' + wso + comment + '$'); - if (currentValue < n && ++delta > maxInt) { - error('overflow'); - } + // define quad part regexes + var subject = '(?:' + iri + '|' + bnode + ')' + ws; + var property = iri + ws; + var object = '(?:' + iri + '|' + bnode + '|' + literal + ')' + wso; + var graphName = '(?:\\.|(?:(?:' + iri + '|' + bnode + ')' + wso + '\\.))'; - if (currentValue == n) { - // Represent delta as a generalized variable-length integer - for (q = delta, k = base; /* no condition */; k += base) { - t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); - if (q < t) { - break; - } - qMinusT = q - t; - baseMinusT = base - t; - output.push( - stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) - ); - q = floor(qMinusT / baseMinusT); - } + // full quad regex + var quad = new RegExp( + '^' + wso + subject + property + object + graphName + wso + comment + '$'); - output.push(stringFromCharCode(digitToBasic(q, 0))); - bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); - delta = 0; - ++handledCPCount; - } - } + // build RDF dataset + var dataset = {}; - ++delta; - ++n; + // split N-Quad input into lines + var lines = input.split(eoln); + var lineNumber = 0; + for(var li = 0; li < lines.length; ++li) { + var line = lines[li]; + lineNumber++; - } - return output.join(''); - } + // skip empty lines + if(empty.test(line)) { + continue; + } - /** - * Converts a Punycode string representing a domain name or an email address - * to Unicode. Only the Punycoded parts of the input will be converted, i.e. - * it doesn't matter if you call it on a string that has already been - * converted to Unicode. - * @memberOf punycode - * @param {String} input The Punycoded domain name or email address to - * convert to Unicode. - * @returns {String} The Unicode representation of the given Punycode - * string. - */ - function toUnicode(input) { - return mapDomain(input, function(string) { - return regexPunycode.test(string) - ? decode(string.slice(4).toLowerCase()) - : string; - }); - } + // parse quad + var match = line.match(quad); + if(match === null) { + throw new JsonLdError( + 'Error while parsing N-Quads; invalid quad.', + 'jsonld.ParseError', {line: lineNumber}); + } - /** - * Converts a Unicode string representing a domain name or an email address to - * Punycode. Only the non-ASCII parts of the domain name will be converted, - * i.e. it doesn't matter if you call it with a domain that's already in - * ASCII. - * @memberOf punycode - * @param {String} input The domain name or email address to convert, as a - * Unicode string. - * @returns {String} The Punycode representation of the given domain name or - * email address. - */ - function toASCII(input) { - return mapDomain(input, function(string) { - return regexNonASCII.test(string) - ? 'xn--' + encode(string) - : string; - }); - } + // create RDF triple + var triple = {}; - /*--------------------------------------------------------------------------*/ + // get subject + if(!_isUndefined(match[1])) { + triple.subject = {type: 'IRI', value: match[1]}; + } else { + triple.subject = {type: 'blank node', value: match[2]}; + } - /** Define the public API */ - punycode = { - /** - * A string representing the current Punycode.js version number. - * @memberOf punycode - * @type String - */ - 'version': '1.4.1', - /** - * An object of methods to convert from JavaScript's internal character - * representation (UCS-2) to Unicode code points, and back. - * @see - * @memberOf punycode - * @type Object - */ - 'ucs2': { - 'decode': ucs2decode, - 'encode': ucs2encode - }, - 'decode': decode, - 'encode': encode, - 'toASCII': toASCII, - 'toUnicode': toUnicode - }; + // get predicate + triple.predicate = {type: 'IRI', value: match[3]}; - /** Expose `punycode` */ - // Some AMD build optimizers, like r.js, check for specific condition patterns - // like the following: - if ( - typeof define == 'function' && - typeof define.amd == 'object' && - define.amd - ) { - define('punycode', function() { - return punycode; - }); - } else if (freeExports && freeModule) { - if (module.exports == freeExports) { - // in Node.js, io.js, or RingoJS v0.8.0+ - freeModule.exports = punycode; - } else { - // in Narwhal or RingoJS v0.7.0- - for (key in punycode) { - punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); - } - } - } else { - // in Rhino or a web browser - root.punycode = punycode; - } + // get object + if(!_isUndefined(match[4])) { + triple.object = {type: 'IRI', value: match[4]}; + } else if(!_isUndefined(match[5])) { + triple.object = {type: 'blank node', value: match[5]}; + } else { + triple.object = {type: 'literal'}; + if(!_isUndefined(match[7])) { + triple.object.datatype = match[7]; + } else if(!_isUndefined(match[8])) { + triple.object.datatype = RDF_LANGSTRING; + triple.object.language = match[8]; + } else { + triple.object.datatype = XSD_STRING; + } + var unescaped = match[6] + .replace(/\\"/g, '"') + .replace(/\\t/g, '\t') + .replace(/\\n/g, '\n') + .replace(/\\r/g, '\r') + .replace(/\\\\/g, '\\'); + triple.object.value = unescaped; + } -}(this)); + // get graph name ('@default' is used for the default graph) + var name = '@default'; + if(!_isUndefined(match[9])) { + name = match[9]; + } else if(!_isUndefined(match[10])) { + name = match[10]; + } -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + // initialize graph in dataset + if(!(name in dataset)) { + dataset[name] = [triple]; + } else { + // add triple if unique to its graph + var unique = true; + var triples = dataset[name]; + for(var ti = 0; unique && ti < triples.length; ++ti) { + if(_compareRDFTriples(triples[ti], triple)) { + unique = false; + } + } + if(unique) { + triples.push(triple); + } + } + } -},{}],39:[function(_dereq_,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. + return dataset; +} -'use strict'; +// register the N-Quads RDF parser +jsonld.registerRDFParser('application/nquads', _parseNQuads); -// If obj.hasOwnProperty has been overridden, then calling -// obj.hasOwnProperty(prop) will break. -// See: https://github.com/joyent/node/issues/1707 -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); +/** + * Converts an RDF dataset to N-Quads. + * + * @param dataset the RDF dataset to convert. + * + * @return the N-Quads string. + */ +function _toNQuads(dataset) { + var quads = []; + for(var graphName in dataset) { + var triples = dataset[graphName]; + for(var ti = 0; ti < triples.length; ++ti) { + var triple = triples[ti]; + if(graphName === '@default') { + graphName = null; + } + quads.push(_toNQuad(triple, graphName)); + } + } + return quads.sort().join(''); } -module.exports = function(qs, sep, eq, options) { - sep = sep || '&'; - eq = eq || '='; - var obj = {}; - - if (typeof qs !== 'string' || qs.length === 0) { - return obj; +/** + * Converts an RDF triple and graph name to an N-Quad string (a single quad). + * + * @param triple the RDF triple or quad to convert (a triple or quad may be + * passed, if a triple is passed then `graphName` should be given + * to specify the name of the graph the triple is in, `null` for + * the default graph). + * @param graphName the name of the graph containing the triple, null for + * the default graph. + * + * @return the N-Quad string. + */ +function _toNQuad(triple, graphName) { + var s = triple.subject; + var p = triple.predicate; + var o = triple.object; + var g = graphName || null; + if('name' in triple && triple.name) { + g = triple.name.value; } - var regexp = /\+/g; - qs = qs.split(sep); + var quad = ''; - var maxKeys = 1000; - if (options && typeof options.maxKeys === 'number') { - maxKeys = options.maxKeys; + // subject is an IRI + if(s.type === 'IRI') { + quad += '<' + s.value + '>'; + } else { + quad += s.value; } + quad += ' '; - var len = qs.length; - // maxKeys <= 0 means that we should not limit keys count - if (maxKeys > 0 && len > maxKeys) { - len = maxKeys; + // predicate is an IRI + if(p.type === 'IRI') { + quad += '<' + p.value + '>'; + } else { + quad += p.value; } + quad += ' '; - for (var i = 0; i < len; ++i) { - var x = qs[i].replace(regexp, '%20'), - idx = x.indexOf(eq), - kstr, vstr, k, v; - - if (idx >= 0) { - kstr = x.substr(0, idx); - vstr = x.substr(idx + 1); - } else { - kstr = x; - vstr = ''; + // object is IRI, bnode, or literal + if(o.type === 'IRI') { + quad += '<' + o.value + '>'; + } else if(o.type === 'blank node') { + quad += o.value; + } else { + var escaped = o.value + .replace(/\\/g, '\\\\') + .replace(/\t/g, '\\t') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/\"/g, '\\"'); + quad += '"' + escaped + '"'; + if(o.datatype === RDF_LANGSTRING) { + if(o.language) { + quad += '@' + o.language; + } + } else if(o.datatype !== XSD_STRING) { + quad += '^^<' + o.datatype + '>'; } + } - k = decodeURIComponent(kstr); - v = decodeURIComponent(vstr); - - if (!hasOwnProperty(obj, k)) { - obj[k] = v; - } else if (isArray(obj[k])) { - obj[k].push(v); + // graph + if(g !== null && g !== undefined) { + if(g.indexOf('_:') !== 0) { + quad += ' <' + g + '>'; } else { - obj[k] = [obj[k], v]; + quad += ' ' + g; } } - return obj; -}; + quad += ' .\n'; + return quad; +} -var isArray = Array.isArray || function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; -}; +/** + * Parses the RDF dataset found via the data object from the RDFa API. + * + * @param data the RDFa API data object. + * + * @return the RDF dataset. + */ +function _parseRdfaApiData(data) { + var dataset = {}; + dataset['@default'] = []; -},{}],40:[function(_dereq_,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. + var subjects = data.getSubjects(); + for(var si = 0; si < subjects.length; ++si) { + var subject = subjects[si]; + if(subject === null) { + continue; + } -'use strict'; + // get all related triples + var triples = data.getSubjectTriples(subject); + if(triples === null) { + continue; + } + var predicates = triples.predicates; + for(var predicate in predicates) { + // iterate over objects + var objects = predicates[predicate].objects; + for(var oi = 0; oi < objects.length; ++oi) { + var object = objects[oi]; -var stringifyPrimitive = function(v) { - switch (typeof v) { - case 'string': - return v; + // create RDF triple + var triple = {}; - case 'boolean': - return v ? 'true' : 'false'; + // add subject + if(subject.indexOf('_:') === 0) { + triple.subject = {type: 'blank node', value: subject}; + } else { + triple.subject = {type: 'IRI', value: subject}; + } - case 'number': - return isFinite(v) ? v : ''; + // add predicate + if(predicate.indexOf('_:') === 0) { + triple.predicate = {type: 'blank node', value: predicate}; + } else { + triple.predicate = {type: 'IRI', value: predicate}; + } - default: - return ''; + // serialize XML literal + var value = object.value; + if(object.type === RDF_XML_LITERAL) { + // initialize XMLSerializer + if(!XMLSerializer) { + _defineXMLSerializer(); + } + var serializer = new XMLSerializer(); + value = ''; + for(var x = 0; x < object.value.length; x++) { + if(object.value[x].nodeType === Node.ELEMENT_NODE) { + value += serializer.serializeToString(object.value[x]); + } else if(object.value[x].nodeType === Node.TEXT_NODE) { + value += object.value[x].nodeValue; + } + } + } + + // add object + triple.object = {}; + + // object is an IRI + if(object.type === RDF_OBJECT) { + if(object.value.indexOf('_:') === 0) { + triple.object.type = 'blank node'; + } else { + triple.object.type = 'IRI'; + } + } else { + // object is a literal + triple.object.type = 'literal'; + if(object.type === RDF_PLAIN_LITERAL) { + if(object.language) { + triple.object.datatype = RDF_LANGSTRING; + triple.object.language = object.language; + } else { + triple.object.datatype = XSD_STRING; + } + } else { + triple.object.datatype = object.type; + } + } + triple.object.value = value; + + // add triple to dataset in default graph + dataset['@default'].push(triple); + } + } } + + return dataset; +} + +// register the RDFa API RDF parser +jsonld.registerRDFParser('rdfa-api', _parseRdfaApiData); + +/** + * Creates a new IdentifierIssuer. A IdentifierIssuer issues unique + * identifiers, keeping track of any previously issued identifiers. + * + * @param prefix the prefix to use (''). + */ +function IdentifierIssuer(prefix) { + this.prefix = prefix; + this.counter = 0; + this.existing = {}; +} +jsonld.IdentifierIssuer = IdentifierIssuer; +// backwards-compability +jsonld.UniqueNamer = IdentifierIssuer; + +/** + * Copies this IdentifierIssuer. + * + * @return a copy of this IdentifierIssuer. + */ +IdentifierIssuer.prototype.clone = function() { + var copy = new IdentifierIssuer(this.prefix); + copy.counter = this.counter; + copy.existing = _clone(this.existing); + return copy; }; -module.exports = function(obj, sep, eq, name) { - sep = sep || '&'; - eq = eq || '='; - if (obj === null) { - obj = undefined; +/** + * Gets the new identifier for the given old identifier, where if no old + * identifier is given a new identifier will be generated. + * + * @param [old] the old identifier to get the new identifier for. + * + * @return the new identifier. + */ +IdentifierIssuer.prototype.getId = function(old) { + // return existing old identifier + if(old && old in this.existing) { + return this.existing[old]; } - if (typeof obj === 'object') { - return map(objectKeys(obj), function(k) { - var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; - if (isArray(obj[k])) { - return map(obj[k], function(v) { - return ks + encodeURIComponent(stringifyPrimitive(v)); - }).join(sep); - } else { - return ks + encodeURIComponent(stringifyPrimitive(obj[k])); - } - }).join(sep); + // get next identifier + var identifier = this.prefix + this.counter; + this.counter += 1; + // save mapping + if(old) { + this.existing[old] = identifier; } - if (!name) return ''; - return encodeURIComponent(stringifyPrimitive(name)) + eq + - encodeURIComponent(stringifyPrimitive(obj)); + return identifier; }; +// alias +IdentifierIssuer.prototype.getName = IdentifierIssuer.prototype.getName; -var isArray = Array.isArray || function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; +/** + * Returns true if the given old identifer has already been assigned a new + * identifier. + * + * @param old the old identifier to check. + * + * @return true if the old identifier has been assigned a new identifier, false + * if not. + */ +IdentifierIssuer.prototype.hasId = function(old) { + return (old in this.existing); }; +// alias +IdentifierIssuer.prototype.isNamed = IdentifierIssuer.prototype.hasId; -function map (xs, f) { - if (xs.map) return xs.map(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - res.push(f(xs[i], i)); +/** + * A Permutator iterates over all possible permutations of the given array + * of elements. + * + * @param list the array of elements to iterate over. + */ +var Permutator = function(list) { + // original array + this.list = list.sort(); + // indicates whether there are more permutations + this.done = false; + // directional info for permutation algorithm + this.left = {}; + for(var i = 0; i < list.length; ++i) { + this.left[list[i]] = true; } - return res; -} +}; -var objectKeys = Object.keys || function (obj) { - var res = []; - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); - } - return res; +/** + * Returns true if there is another permutation. + * + * @return true if there is another permutation, false if not. + */ +Permutator.prototype.hasNext = function() { + return !this.done; }; -},{}],41:[function(_dereq_,module,exports){ -'use strict'; +/** + * Gets the next permutation. Call hasNext() to ensure there is another one + * first. + * + * @return the next permutation. + */ +Permutator.prototype.next = function() { + // copy current permutation + var rval = this.list.slice(); -exports.decode = exports.parse = _dereq_('./decode'); -exports.encode = exports.stringify = _dereq_('./encode'); + /* Calculate the next permutation using the Steinhaus-Johnson-Trotter + permutation algorithm. */ -},{"./decode":39,"./encode":40}],42:[function(_dereq_,module,exports){ -'use strict'; + // get largest mobile element k + // (mobile: element is greater than the one it is looking at) + var k = null; + var pos = 0; + var length = this.list.length; + for(var i = 0; i < length; ++i) { + var element = this.list[i]; + var left = this.left[element]; + if((k === null || element > k) && + ((left && i > 0 && element > this.list[i - 1]) || + (!left && i < (length - 1) && element > this.list[i + 1]))) { + k = element; + pos = i; + } + } -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + // no more permutations + if(k === null) { + this.done = true; + } else { + // swap k and the element it is looking at + var swap = this.left[k] ? pos - 1 : pos + 1; + this.list[pos] = this.list[swap]; + this.list[swap] = k; -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + // reverse the direction of all elements larger than k + for(var i = 0; i < length; ++i) { + if(this.list[i] > k) { + this.left[this.list[i]] = !this.left[this.list[i]]; + } + } + } -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + return rval; +}; -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } +//////////////////////// DEFINE NORMALIZATION HASH API //////////////////////// -var ClassOrder = _dereq_('./class-order'); -var Node = _dereq_('./node'); +/** + * Creates a new NormalizeHash for use by the given normalization algorithm. + * + * @param algorithm the RDF Dataset Normalization algorithm to use: + * 'URDNA2015' or 'URGNA2012'. + */ +var NormalizeHash = function(algorithm) { + if(!(this instanceof NormalizeHash)) { + return new NormalizeHash(algorithm); + } + if(['URDNA2015', 'URGNA2012'].indexOf(algorithm) === -1) { + throw new Error( + 'Invalid RDF Dataset Normalization algorithm: ' + algorithm); + } + NormalizeHash._init.call(this, algorithm); +}; +NormalizeHash.hashNQuads = function(algorithm, nquads) { + var md = new NormalizeHash(algorithm); + for(var i = 0; i < nquads.length; ++i) { + md.update(nquads[i]); + } + return md.digest(); +}; -var BlankNode = function (_Node) { - _inherits(BlankNode, _Node); +// switch definition of NormalizeHash based on environment +(function(_nodejs) { - function BlankNode(id) { - _classCallCheck(this, BlankNode); +if(_nodejs) { + // define NormalizeHash using native crypto lib + var crypto = _dereq_('crypto'); + NormalizeHash._init = function(algorithm) { + if(algorithm === 'URDNA2015') { + algorithm = 'sha256'; + } else { + // assume URGNA2012 + algorithm = 'sha1'; + } + this.md = crypto.createHash(algorithm); + }; + NormalizeHash.prototype.update = function(msg) { + return this.md.update(msg, 'utf8'); + }; + NormalizeHash.prototype.digest = function() { + return this.md.digest('hex'); + }; + return; +} - var _this = _possibleConstructorReturn(this, (BlankNode.__proto__ || Object.getPrototypeOf(BlankNode)).call(this)); +// define NormalizeHash using JavaScript +NormalizeHash._init = function(algorithm) { + if(algorithm === 'URDNA2015') { + algorithm = new sha256.Algorithm(); + } else { + // assume URGNA2012 + algorithm = new sha1.Algorithm(); + } + this.md = new MessageDigest(algorithm); +}; +NormalizeHash.prototype.update = function(msg) { + return this.md.update(msg); +}; +NormalizeHash.prototype.digest = function() { + return this.md.digest().toHex(); +}; - _this.termType = BlankNode.termType; - _this.id = BlankNode.nextId++; - _this.value = id || _this.id.toString(); - return _this; +/////////////////////////// DEFINE MESSAGE DIGEST API ///////////////////////// + +/** + * Creates a new MessageDigest. + * + * @param algorithm the algorithm to use. + */ +var MessageDigest = function(algorithm) { + if(!(this instanceof MessageDigest)) { + return new MessageDigest(algorithm); } - _createClass(BlankNode, [{ - key: 'compareTerm', - value: function compareTerm(other) { - if (this.classOrder < other.classOrder) { - return -1; - } - if (this.classOrder > other.classOrder) { - return +1; - } - if (this.id < other.id) { - return -1; + this._algorithm = algorithm; + + // create shared padding as needed + if(!MessageDigest._padding || + MessageDigest._padding.length < this._algorithm.blockSize) { + MessageDigest._padding = String.fromCharCode(128); + var c = String.fromCharCode(0x00); + var n = 64; + while(n > 0) { + if(n & 1) { + MessageDigest._padding += c; } - if (this.id > other.id) { - return +1; + n >>>= 1; + if(n > 0) { + c += c; } - return 0; - } - }, { - key: 'copy', - value: function copy(formula) { - // depends on the formula - var bnodeNew = new BlankNode(); - formula.copyTo(this, bnodeNew); - return bnodeNew; - } - }, { - key: 'toCanonical', - value: function toCanonical() { - return '_:' + this.value; } - }, { - key: 'toString', - value: function toString() { - return BlankNode.NTAnonymousNodePrefix + this.id; - } - }]); - - return BlankNode; -}(Node); - -BlankNode.nextId = 0; -BlankNode.termType = 'BlankNode'; -BlankNode.NTAnonymousNodePrefix = '_:n'; -BlankNode.prototype.classOrder = ClassOrder['BlankNode']; -BlankNode.prototype.isBlank = 1; -BlankNode.prototype.isVar = 1; - -module.exports = BlankNode; -},{"./class-order":43,"./node":59}],43:[function(_dereq_,module,exports){ -'use strict'; + } -var ClassOrder = { - 'Literal': 1, - 'Collection': 3, - 'Graph': 4, - 'NamedNode': 5, - 'BlankNode': 6, - 'Variable': 7 + // start digest automatically for first time + this.start(); }; -module.exports = ClassOrder; -},{}],44:[function(_dereq_,module,exports){ -'use strict'; +/** + * Starts the digest. + * + * @return this digest object. + */ +MessageDigest.prototype.start = function() { + // up to 56-bit message length for convenience + this.messageLength = 0; -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + // full message length + this.fullMessageLength = []; + var int32s = this._algorithm.messageLengthSize / 4; + for(var i = 0; i < int32s; ++i) { + this.fullMessageLength.push(0); + } -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + // input buffer + this._input = new MessageDigest.ByteBuffer(); -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + // get starting state + this.state = this._algorithm.start(); -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + return this; +}; -var BlankNode = _dereq_('./blank-node'); -var ClassOrder = _dereq_('./class-order'); -var Node = _dereq_('./node'); +/** + * Updates the digest with the given message input. The input must be + * a string of characters. + * + * @param msg the message input to update with (ByteBuffer or string). + * + * @return this digest object. + */ +MessageDigest.prototype.update = function(msg) { + // encode message as a UTF-8 encoded binary string + msg = new MessageDigest.ByteBuffer(unescape(encodeURIComponent(msg))); -var Collection = function (_Node) { - _inherits(Collection, _Node); + // update message length + this.messageLength += msg.length(); + var len = msg.length(); + len = [(len / 0x100000000) >>> 0, len >>> 0]; + for(var i = this.fullMessageLength.length - 1; i >= 0; --i) { + this.fullMessageLength[i] += len[1]; + len[1] = len[0] + ((this.fullMessageLength[i] / 0x100000000) >>> 0); + this.fullMessageLength[i] = this.fullMessageLength[i] >>> 0; + len[0] = ((len[1] / 0x100000000) >>> 0); + } - function Collection(initial) { - _classCallCheck(this, Collection); + // add bytes to input buffer + this._input.putBytes(msg.bytes()); - var _this = _possibleConstructorReturn(this, (Collection.__proto__ || Object.getPrototypeOf(Collection)).call(this)); + // digest blocks + while(this._input.length() >= this._algorithm.blockSize) { + this.state = this._algorithm.digest(this.state, this._input); + } - _this.termType = Collection.termType; - _this.id = BlankNode.nextId++; - _this.elements = []; - _this.closed = false; - if (initial && initial.length > 0) { - initial.forEach(function (element) { - _this.elements.push(Node.fromValue(element)); - }); - } - return _this; + // compact input buffer every 2K or if empty + if(this._input.read > 2048 || this._input.length() === 0) { + this._input.compact(); } - _createClass(Collection, [{ - key: 'append', - value: function append(element) { - return this.elements.push(element); - } - }, { - key: 'close', - value: function close() { - this.closed = true; - return this.closed; - } - }, { - key: 'shift', - value: function shift() { - return this.elements.shift(); - } - }, { - key: 'substitute', - value: function substitute(bindings) { - var elementsCopy = this.elements.map(function (ea) { - ea.substitute(bindings); - }); - return new Collection(elementsCopy); - } - }, { - key: 'toNT', - value: function toNT() { - return BlankNode.NTAnonymousNodePrefix + this.id; - } - }, { - key: 'toString', - value: function toString() { - return '(' + this.elements.join(' ') + ')'; - } - }, { - key: 'unshift', - value: function unshift(element) { - return this.elements.unshift(element); - } - }]); - - return Collection; -}(Node); + return this; +}; -Collection.termType = 'Collection'; -Collection.prototype.classOrder = ClassOrder['Collection']; -Collection.prototype.compareTerm = BlankNode.prototype.compareTerm; -Collection.prototype.isVar = 0; +/** + * Produces the digest. + * + * @return a byte buffer containing the digest value. + */ +MessageDigest.prototype.digest = function() { + /* Note: Here we copy the remaining bytes in the input buffer and add the + appropriate padding. Then we do the final update on a copy of the state so + that if the user wants to get intermediate digests they can do so. */ -module.exports = Collection; -},{"./blank-node":42,"./class-order":43,"./node":59}],45:[function(_dereq_,module,exports){ -'use strict'; + /* Determine the number of bytes that must be added to the message to + ensure its length is appropriately congruent. In other words, the data to + be digested must be a multiple of `blockSize`. This data includes the + message, some padding, and the length of the message. Since the length of + the message will be encoded as `messageLengthSize` bytes, that means that + the last segment of the data must have `blockSize` - `messageLengthSize` + bytes of message and padding. Therefore, the length of the message plus the + padding must be congruent to X mod `blockSize` because + `blockSize` - `messageLengthSize` = X. -module.exports.convertToJson = convertToJson; -module.exports.convertToNQuads = convertToNQuads; + For example, SHA-1 is congruent to 448 mod 512 and SHA-512 is congruent to + 896 mod 1024. SHA-1 uses a `blockSize` of 64 bytes (512 bits) and a + `messageLengthSize` of 8 bytes (64 bits). SHA-512 uses a `blockSize` of + 128 bytes (1024 bits) and a `messageLengthSize` of 16 bytes (128 bits). -var asyncLib = _dereq_('async'); // @@ Goal: remove this dependency -var jsonld = _dereq_('jsonld'); -var N3 = _dereq_('n3'); // @@ Goal: remove this dependency + In order to fill up the message length it must be filled with padding that + begins with 1 bit followed by all 0 bits. Padding must *always* be present, + so if the message length is already congruent, then `blockSize` padding bits + must be added. */ -function convertToJson(n3String, jsonCallback) { - var jsonString; - var n3Parser = N3.Parser(); - var n3Writer = N3.Writer({ - format: 'N-Quads' - }); - asyncLib.waterfall([function (callback) { - n3Parser.parse(n3String, callback); - }, function (triple, prefix, callback) { - if (triple !== null) { - n3Writer.addTriple(triple); - } - if (typeof callback === 'function') { - n3Writer.end(callback); - } - }, function (result, callback) { - try { - jsonld.fromRDF(result, { - format: 'application/nquads' - }, callback); - } catch (err) { - callback(err); - } - }, function (json, callback) { - jsonString = JSON.stringify(json); - jsonCallback(null, jsonString); - }], function (err, result) { - jsonCallback(err, jsonString); - }); -} + // create final block + var finalBlock = new MessageDigest.ByteBuffer(); + finalBlock.putBytes(this._input.bytes()); -function convertToNQuads(n3String, nquadCallback) { - var nquadString; - var n3Parser = N3.Parser(); - var n3Writer = N3.Writer({ - format: 'N-Quads' - }); - asyncLib.waterfall([function (callback) { - n3Parser.parse(n3String, callback); - }, function (triple, prefix, callback) { - if (triple !== null) { - n3Writer.addTriple(triple); - } - if (typeof callback === 'function') { - n3Writer.end(callback); - } - }, function (result, callback) { - nquadString = result; - nquadCallback(null, nquadString); - }], function (err, result) { - nquadCallback(err, nquadString); - }); -} -},{"async":1,"jsonld":18,"n3":76}],46:[function(_dereq_,module,exports){ -'use strict'; + // compute remaining size to be digested (include message length size) + var remaining = ( + this.fullMessageLength[this.fullMessageLength.length - 1] + + this._algorithm.messageLengthSize); -var _indexedFormula = _dereq_('./indexed-formula'); + // add padding for overflow blockSize - overflow + // _padding starts with 1 byte with first bit is set (byte value 128), then + // there may be up to (blockSize - 1) other pad bytes + var overflow = remaining & (this._algorithm.blockSize - 1); + finalBlock.putBytes(MessageDigest._padding.substr( + 0, this._algorithm.blockSize - overflow)); -var _indexedFormula2 = _interopRequireDefault(_indexedFormula); + // serialize message length in bits in big-endian order; since length + // is stored in bytes we multiply by 8 (left shift by 3 and merge in + // remainder from ) + var messageLength = new MessageDigest.ByteBuffer(); + for(var i = 0; i < this.fullMessageLength.length; ++i) { + messageLength.putInt32((this.fullMessageLength[i] << 3) | + (this.fullMessageLength[i + 1] >>> 28)); + } -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + // write the length of the message (algorithm-specific) + this._algorithm.writeMessageLength(finalBlock, messageLength); -var BlankNode = _dereq_('./blank-node'); -var Collection = _dereq_('./collection'); -var DefaultGraph = _dereq_('./default-graph'); -var Fetcher = _dereq_('./fetcher'); + // digest final block + var state = this._algorithm.digest(this.state.copy(), finalBlock); -var Literal = _dereq_('./literal'); -var NamedNode = _dereq_('./named-node'); -var Statement = _dereq_('./statement'); -var Variable = _dereq_('./variable'); + // write state to buffer + var rval = new MessageDigest.ByteBuffer(); + state.write(rval); + return rval; +}; -function blankNode(value) { - return new BlankNode(value); -} -function collection(elements) { - return new Collection(elements); -} -function defaultGraph() { - return new DefaultGraph(); -} -function fetcher(store, timeout, async) { - return new Fetcher(store, timeout, async); -} -function graph() { - return new _indexedFormula2.default(); -} -function lit(val, lang, dt) { - return new Literal('' + val, lang, dt); -} -function literal(value, languageOrDatatype) { - if (typeof languageOrDatatype === 'string') { - if (languageOrDatatype.indexOf(':') === -1) { - return new Literal(value, languageOrDatatype); - } else { - return new Literal(value, null, namedNode(languageOrDatatype)); - } +/** + * Creates a simple byte buffer for message digest operations. + * + * @param data the data to put in the buffer. + */ +MessageDigest.ByteBuffer = function(data) { + if(typeof data === 'string') { + this.data = data; } else { - return new Literal(value, null, languageOrDatatype); + this.data = ''; } -} -function namedNode(value) { - return new NamedNode(value); -} -function quad(subject, predicate, object, graph) { - graph = graph || new DefaultGraph(); - return new Statement(subject, predicate, object, graph); -} -function st(subject, predicate, object, graph) { - return new Statement(subject, predicate, object, graph); -} -function triple(subject, predicate, object) { - return quad(subject, predicate, object); -} -function variable(name) { - return new Variable(name); -} + this.read = 0; +}; -// rdfjs spec factory methods -module.exports.blankNode = blankNode; -module.exports.defaultGraph = defaultGraph; -module.exports.graph = graph; -module.exports.literal = literal; -module.exports.namedNode = namedNode; -module.exports.quad = quad; -module.exports.triple = triple; -module.exports.variable = variable; +/** + * Puts a 32-bit integer into this buffer in big-endian order. + * + * @param i the 32-bit integer. + */ +MessageDigest.ByteBuffer.prototype.putInt32 = function(i) { + this.data += ( + String.fromCharCode(i >> 24 & 0xFF) + + String.fromCharCode(i >> 16 & 0xFF) + + String.fromCharCode(i >> 8 & 0xFF) + + String.fromCharCode(i & 0xFF)); +}; -// rdflib only -module.exports.collection = collection; -module.exports.fetcher = fetcher; -module.exports.lit = lit; -module.exports.st = st; -},{"./blank-node":42,"./collection":44,"./default-graph":47,"./fetcher":49,"./indexed-formula":52,"./literal":54,"./named-node":57,"./statement":69,"./variable":74}],47:[function(_dereq_,module,exports){ -'use strict'; +/** + * Gets a 32-bit integer from this buffer in big-endian order and + * advances the read pointer by 4. + * + * @return the word. + */ +MessageDigest.ByteBuffer.prototype.getInt32 = function() { + var rval = ( + this.data.charCodeAt(this.read) << 24 ^ + this.data.charCodeAt(this.read + 1) << 16 ^ + this.data.charCodeAt(this.read + 2) << 8 ^ + this.data.charCodeAt(this.read + 3)); + this.read += 4; + return rval; +}; -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); +/** + * Puts the given bytes into this buffer. + * + * @param bytes the bytes as a binary-encoded string. + */ +MessageDigest.ByteBuffer.prototype.putBytes = function(bytes) { + this.data += bytes; +}; -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +/** + * Gets the bytes in this buffer. + * + * @return a string full of UTF-8 encoded characters. + */ +MessageDigest.ByteBuffer.prototype.bytes = function() { + return this.data.slice(this.read); +}; -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } +/** + * Gets the number of bytes in this buffer. + * + * @return the number of bytes in this buffer. + */ +MessageDigest.ByteBuffer.prototype.length = function() { + return this.data.length - this.read; +}; -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } +/** + * Compacts this buffer. + */ +MessageDigest.ByteBuffer.prototype.compact = function() { + this.data = this.data.slice(this.read); + this.read = 0; +}; -var Node = _dereq_('./node'); +/** + * Converts this buffer to a hexadecimal string. + * + * @return a hexadecimal string. + */ +MessageDigest.ByteBuffer.prototype.toHex = function() { + var rval = ''; + for(var i = this.read; i < this.data.length; ++i) { + var b = this.data.charCodeAt(i); + if(b < 16) { + rval += '0'; + } + rval += b.toString(16); + } + return rval; +}; -var DefaultGraph = function (_Node) { - _inherits(DefaultGraph, _Node); +///////////////////////////// DEFINE SHA-1 ALGORITHM ////////////////////////// - function DefaultGraph() { - _classCallCheck(this, DefaultGraph); +var sha1 = { + // used for word storage + _w: null +}; - var _this = _possibleConstructorReturn(this, (DefaultGraph.__proto__ || Object.getPrototypeOf(DefaultGraph)).call(this)); +sha1.Algorithm = function() { + this.name = 'sha1', + this.blockSize = 64; + this.digestLength = 20; + this.messageLengthSize = 8; +}; - _this.termType = 'DefaultGraph'; - _this.value = ''; - return _this; +sha1.Algorithm.prototype.start = function() { + if(!sha1._w) { + sha1._w = new Array(80); } + return sha1._createState(); +}; - _createClass(DefaultGraph, [{ - key: 'toCanonical', - value: function toCanonical() { - return this.value; - } - }]); - - return DefaultGraph; -}(Node); - -module.exports = DefaultGraph; -},{"./node":59}],48:[function(_dereq_,module,exports){ -'use strict'; +sha1.Algorithm.prototype.writeMessageLength = function( + finalBlock, messageLength) { + // message length is in bits and in big-endian order; simply append + finalBlock.putBytes(messageLength.bytes()); +}; -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); +sha1.Algorithm.prototype.digest = function(s, input) { + // consume 512 bit (64 byte) chunks + var t, a, b, c, d, e, f, i; + var len = input.length(); + var _w = sha1._w; + while(len >= 64) { + // initialize hash value for this chunk + a = s.h0; + b = s.h1; + c = s.h2; + d = s.h3; + e = s.h4; -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + // the _w array will be populated with sixteen 32-bit big-endian words + // and then extended into 80 32-bit words according to SHA-1 algorithm + // and for 32-79 using Max Locktyukhin's optimization -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + // round 1 + for(i = 0; i < 16; ++i) { + t = input.getInt32(); + _w[i] = t; + f = d ^ (b & (c ^ d)); + t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t; + e = d; + d = c; + c = (b << 30) | (b >>> 2); + b = a; + a = t; + } + for(; i < 20; ++i) { + t = (_w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16]); + t = (t << 1) | (t >>> 31); + _w[i] = t; + f = d ^ (b & (c ^ d)); + t = ((a << 5) | (a >>> 27)) + f + e + 0x5A827999 + t; + e = d; + d = c; + c = (b << 30) | (b >>> 2); + b = a; + a = t; + } + // round 2 + for(; i < 32; ++i) { + t = (_w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16]); + t = (t << 1) | (t >>> 31); + _w[i] = t; + f = b ^ c ^ d; + t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t; + e = d; + d = c; + c = (b << 30) | (b >>> 2); + b = a; + a = t; + } + for(; i < 40; ++i) { + t = (_w[i - 6] ^ _w[i - 16] ^ _w[i - 28] ^ _w[i - 32]); + t = (t << 2) | (t >>> 30); + _w[i] = t; + f = b ^ c ^ d; + t = ((a << 5) | (a >>> 27)) + f + e + 0x6ED9EBA1 + t; + e = d; + d = c; + c = (b << 30) | (b >>> 2); + b = a; + a = t; + } + // round 3 + for(; i < 60; ++i) { + t = (_w[i - 6] ^ _w[i - 16] ^ _w[i - 28] ^ _w[i - 32]); + t = (t << 2) | (t >>> 30); + _w[i] = t; + f = (b & c) | (d & (b ^ c)); + t = ((a << 5) | (a >>> 27)) + f + e + 0x8F1BBCDC + t; + e = d; + d = c; + c = (b << 30) | (b >>> 2); + b = a; + a = t; + } + // round 4 + for(; i < 80; ++i) { + t = (_w[i - 6] ^ _w[i - 16] ^ _w[i - 28] ^ _w[i - 32]); + t = (t << 2) | (t >>> 30); + _w[i] = t; + f = b ^ c ^ d; + t = ((a << 5) | (a >>> 27)) + f + e + 0xCA62C1D6 + t; + e = d; + d = c; + c = (b << 30) | (b >>> 2); + b = a; + a = t; + } -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + // update hash state + s.h0 = (s.h0 + a) | 0; + s.h1 = (s.h1 + b) | 0; + s.h2 = (s.h2 + c) | 0; + s.h3 = (s.h3 + d) | 0; + s.h4 = (s.h4 + e) | 0; -var Node = _dereq_('./node'); + len -= 64; + } -/** - * Singleton subclass of an empty Collection. - */ + return s; +}; -var Empty = function (_Node) { - _inherits(Empty, _Node); +sha1._createState = function() { + var state = { + h0: 0x67452301, + h1: 0xEFCDAB89, + h2: 0x98BADCFE, + h3: 0x10325476, + h4: 0xC3D2E1F0 + }; + state.copy = function() { + var rval = sha1._createState(); + rval.h0 = state.h0; + rval.h1 = state.h1; + rval.h2 = state.h2; + rval.h3 = state.h3; + rval.h4 = state.h4; + return rval; + }; + state.write = function(buffer) { + buffer.putInt32(state.h0); + buffer.putInt32(state.h1); + buffer.putInt32(state.h2); + buffer.putInt32(state.h3); + buffer.putInt32(state.h4); + }; + return state; +}; - function Empty() { - _classCallCheck(this, Empty); +//////////////////////////// DEFINE SHA-256 ALGORITHM ///////////////////////// - var _this = _possibleConstructorReturn(this, (Empty.__proto__ || Object.getPrototypeOf(Empty)).call(this)); +var sha256 = { + // shared state + _k: null, + _w: null +}; - _this.termType = Empty.termType; - return _this; +sha256.Algorithm = function() { + this.name = 'sha256', + this.blockSize = 64; + this.digestLength = 32; + this.messageLengthSize = 8; +}; + +sha256.Algorithm.prototype.start = function() { + if(!sha256._k) { + sha256._init(); } + return sha256._createState(); +}; - _createClass(Empty, [{ - key: 'toString', - value: function toString() { - return '()'; +sha256.Algorithm.prototype.writeMessageLength = function( + finalBlock, messageLength) { + // message length is in bits and in big-endian order; simply append + finalBlock.putBytes(messageLength.bytes()); +}; + +sha256.Algorithm.prototype.digest = function(s, input) { + // consume 512 bit (64 byte) chunks + var t1, t2, s0, s1, ch, maj, i, a, b, c, d, e, f, g, h; + var len = input.length(); + var _k = sha256._k; + var _w = sha256._w; + while(len >= 64) { + // the w array will be populated with sixteen 32-bit big-endian words + // and then extended into 64 32-bit words according to SHA-256 + for(i = 0; i < 16; ++i) { + _w[i] = input.getInt32(); + } + for(; i < 64; ++i) { + // XOR word 2 words ago rot right 17, rot right 19, shft right 10 + t1 = _w[i - 2]; + t1 = + ((t1 >>> 17) | (t1 << 15)) ^ + ((t1 >>> 19) | (t1 << 13)) ^ + (t1 >>> 10); + // XOR word 15 words ago rot right 7, rot right 18, shft right 3 + t2 = _w[i - 15]; + t2 = + ((t2 >>> 7) | (t2 << 25)) ^ + ((t2 >>> 18) | (t2 << 14)) ^ + (t2 >>> 3); + // sum(t1, word 7 ago, t2, word 16 ago) modulo 2^32 + _w[i] = (t1 + _w[i - 7] + t2 + _w[i - 16]) | 0; } - }]); - return Empty; -}(Node); + // initialize hash value for this chunk + a = s.h0; + b = s.h1; + c = s.h2; + d = s.h3; + e = s.h4; + f = s.h5; + g = s.h6; + h = s.h7; -Empty.termType = 'empty'; + // round function + for(i = 0; i < 64; ++i) { + // Sum1(e) + s1 = + ((e >>> 6) | (e << 26)) ^ + ((e >>> 11) | (e << 21)) ^ + ((e >>> 25) | (e << 7)); + // Ch(e, f, g) (optimized the same way as SHA-1) + ch = g ^ (e & (f ^ g)); + // Sum0(a) + s0 = + ((a >>> 2) | (a << 30)) ^ + ((a >>> 13) | (a << 19)) ^ + ((a >>> 22) | (a << 10)); + // Maj(a, b, c) (optimized the same way as SHA-1) + maj = (a & b) | (c & (a ^ b)); -module.exports = Empty; -},{"./node":59}],49:[function(_dereq_,module,exports){ -'use strict'; + // main algorithm + t1 = h + s1 + ch + _k[i] + _w[i]; + t2 = s0 + maj; + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; + } -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + // update hash state + s.h0 = (s.h0 + a) | 0; + s.h1 = (s.h1 + b) | 0; + s.h2 = (s.h2 + c) | 0; + s.h3 = (s.h3 + d) | 0; + s.h4 = (s.h4 + e) | 0; + s.h5 = (s.h5 + f) | 0; + s.h6 = (s.h6 + g) | 0; + s.h7 = (s.h7 + h) | 0; + len -= 64; + } -/* global $SolidTestEnvironment */ -/** - * - * Project: rdflib.js - * - * File: fetcher.js - * - * Description: contains functions for requesting/fetching/retracting - * This implements quite a lot of the web architecture. - * A fetcher is bound to a specific knowledge base graph, into which - * it loads stuff and into which it writes its metadata - * @@ The metadata should be optionally a separate graph - * - * - implements semantics of HTTP headers, Internet Content Types - * - selects parsers for rdf/xml, n3, rdfa, grddl - * - * Dependencies: - * - * needs: util.js uri.js term.js rdfparser.js rdfa.js n3parser.js - * identity.js sparql.js jsonparser.js - * - * Independent of jQuery - */ + return s; +}; -/** - * Things to test: callbacks on request, refresh, retract - * loading from HTTP, HTTPS, FTP, FILE, others? - * To do: - * Firing up a mail client for mid: (message:) URLs - */ -var log = _dereq_('./log'); -var N3Parser = _dereq_('./n3parser'); -var NamedNode = _dereq_('./named-node'); -var Namespace = _dereq_('./namespace'); -var rdfParse = _dereq_('./parse'); -var parseRDFaDOM = _dereq_('./rdfaparser').parseRDFaDOM; -var RDFParser = _dereq_('./rdfxmlparser'); -var Uri = _dereq_('./uri'); -var Util = _dereq_('./util'); -var serialize = _dereq_('./serialize'); +sha256._createState = function() { + var state = { + h0: 0x6A09E667, + h1: 0xBB67AE85, + h2: 0x3C6EF372, + h3: 0xA54FF53A, + h4: 0x510E527F, + h5: 0x9B05688C, + h6: 0x1F83D9AB, + h7: 0x5BE0CD19 + }; + state.copy = function() { + var rval = sha256._createState(); + rval.h0 = state.h0; + rval.h1 = state.h1; + rval.h2 = state.h2; + rval.h3 = state.h3; + rval.h4 = state.h4; + rval.h5 = state.h5; + rval.h6 = state.h6; + rval.h7 = state.h7; + return rval; + }; + state.write = function(buffer) { + buffer.putInt32(state.h0); + buffer.putInt32(state.h1); + buffer.putInt32(state.h2); + buffer.putInt32(state.h3); + buffer.putInt32(state.h4); + buffer.putInt32(state.h5); + buffer.putInt32(state.h6); + buffer.putInt32(state.h7); + }; + return state; +}; -var Parsable = { - 'text/n3': true, - 'text/turtle': true, - 'application/rdf+xml': true, - 'application/xhtml+xml': true, - 'text/html': true, - 'application/ld+json': true +sha256._init = function() { + // create K table for SHA-256 + sha256._k = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]; + + // used for word storage + sha256._w = new Array(64); }; -var Fetcher = function Fetcher(store, timeout, async) { - this.store = store; - this.thisURI = 'http://dig.csail.mit.edu/2005/ajar/ajaw/rdf/sources.js' + '#SourceFetcher'; // -- Kenny - this.timeout = timeout || 30000; - this.async = async != null ? async : true; - this.appNode = this.store.bnode(); // Denoting this session - this.store.fetcher = this; // Bi-linked - this.requested = {}; - // this.requested[uri] states: - // undefined no record of web access or records reset - // true has been requested, XHR in progress - // 'done' received, Ok - // 403 HTTP status unauthorized - // 404 Ressource does not exist. Can be created etc. - // 'redirected' In attempt to counter CORS problems retried. - // other strings mean various other erros, such as parse errros. - // - this.redirectedTo = {}; // Wehn 'redireced' - this.fetchCallbacks = {}; // fetchCallbacks[uri].push(callback) +})(_nodejs); // end definition of NormalizeHash - this.nonexistant = {}; // keep track of explict 404s -> we can overwrite etc - this.lookedUp = {}; - this.handlers = []; - this.mediatypes = {}; - var sf = this; - var kb = this.store; - var ns = {}; // Convenience namespaces needed in this module: - // These are delibertely not exported as the user application should - // make its own list and not rely on the prefixes used here, - // and not be tempted to add to them, and them clash with those of another - // application. - ns.link = Namespace('http://www.w3.org/2007/ont/link#'); - ns.http = Namespace('http://www.w3.org/2007/ont/http#'); - ns.httph = Namespace('http://www.w3.org/2007/ont/httph#'); - ns.rdf = Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#'); - ns.rdfs = Namespace('http://www.w3.org/2000/01/rdf-schema#'); - ns.dc = Namespace('http://purl.org/dc/elements/1.1/'); +if(!XMLSerializer) { - sf.mediatypes['image/*'] = { - 'q': 0.9 - }; +var _defineXMLSerializer = function() { + XMLSerializer = _dereq_('xmldom').XMLSerializer; +}; - sf.mediatypes['*/*'] = { // Must allow access to random content - 'q': 0.1 - }; +} // end _defineXMLSerializer - Fetcher.crossSiteProxy = function (uri) { - if (Fetcher.crossSiteProxyTemplate) { - return Fetcher.crossSiteProxyTemplate.replace('{uri}', encodeURIComponent(uri)); - } else { - return undefined; +// define URL parser +// parseUri 1.2.2 +// (c) Steven Levithan +// MIT License +// with local jsonld.js modifications +jsonld.url = {}; +jsonld.url.parsers = { + simple: { + // RFC 3986 basic parts + keys: ['href','scheme','authority','path','query','fragment'], + regex: /^(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/ + }, + full: { + keys: ['href','protocol','scheme','authority','auth','user','password','hostname','port','path','directory','file','query','fragment'], + regex: /^(([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?(?:(((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ + } +}; +jsonld.url.parse = function(str, parser) { + var parsed = {}; + var o = jsonld.url.parsers[parser || 'full']; + var m = o.regex.exec(str); + var i = o.keys.length; + while(i--) { + parsed[o.keys[i]] = (m[i] === undefined) ? null : m[i]; + } + parsed.normalizedPath = _removeDotSegments(parsed.path, !!parsed.authority); + return parsed; +}; + +/** + * Removes dot segments from a URL path. + * + * @param path the path to remove dot segments from. + * @param hasAuthority true if the URL has an authority, false if not. + */ +function _removeDotSegments(path, hasAuthority) { + var rval = ''; + + if(path.indexOf('/') === 0) { + rval = '/'; + } + + // RFC 3986 5.2.4 (reworked) + var input = path.split('/'); + var output = []; + while(input.length > 0) { + if(input[0] === '.' || (input[0] === '' && input.length > 1)) { + input.shift(); + continue; } - }; + if(input[0] === '..') { + input.shift(); + if(hasAuthority || + (output.length > 0 && output[output.length - 1] !== '..')) { + output.pop(); + } else { + // leading relative URL '..' + output.push('..'); + } + continue; + } + output.push(input.shift()); + } - Fetcher.RDFXMLHandler = function (args) { - if (args) { - this.dom = args[0]; + return rval + output.join('/'); +} + +if(_nodejs) { + // use node document loader by default + jsonld.useDocumentLoader('node'); +} else if(typeof XMLHttpRequest !== 'undefined') { + // use xhr document loader by default + jsonld.useDocumentLoader('xhr'); +} + +if(_nodejs) { + jsonld.use = function(extension) { + switch(extension) { + // TODO: Deprecated as of 0.4.0. Remove at some point. + case 'request': + // use node JSON-LD request extension + jsonld.request = _dereq_('jsonld-request'); + break; + default: + throw new JsonLdError( + 'Unknown extension.', + 'jsonld.UnknownExtension', {extension: extension}); } - this.handlerFactory = function (xhr) { - xhr.handle = function (cb) { - // sf.addStatus(xhr.req, 'parsing soon as RDF/XML...') - var kb = sf.store; - if (!this.dom) this.dom = Util.parseXML(xhr.responseText); - var root = this.dom.documentElement; - if (root.nodeName === 'parsererror') { - // @@ Mozilla only See issue/issue110 - sf.failFetch(xhr, 'Badly formed XML in ' + xhr.resource.uri); // have to fail the request - throw new Error('Badly formed XML in ' + xhr.resource.uri); // @@ Add details - } - var parser = new RDFParser(kb); - try { - parser.parse(this.dom, xhr.original.uri, xhr.original); - } catch (e) { - sf.addStatus(xhr.req, 'Syntax error parsing RDF/XML! ' + e); - console.log('Syntax error parsing RDF/XML! ' + e); - } - if (!xhr.options.noMeta) { - kb.add(xhr.original, ns.rdf('type'), ns.link('RDFDocument'), sf.appNode); - } - cb(); - }; - }; - }; - Fetcher.RDFXMLHandler.toString = function () { - return 'RDFXMLHandler'; - }; - Fetcher.RDFXMLHandler.register = function (sf) { - sf.mediatypes['application/rdf+xml'] = { - 'q': 0.9 - }; }; - Fetcher.RDFXMLHandler.pattern = new RegExp('application/rdf\\+xml'); - // This would much better use on-board XSLT engine. @@ - /* deprocated 2016-02-17 timbl - Fetcher.doGRDDL = function(kb, doc, xslturi, xmluri) { - sf.requestURI('http://www.w3.org/2005/08/' + 'online_xslt/xslt?' + 'xslfile=' + escape(xslturi) + '&xmlfile=' + escape(xmluri), doc) + // expose version + var _module = {exports: {}, filename: __dirname}; + _dereq_('pkginfo')(_module, 'version'); + jsonld.version = _module.exports.version; +} + +// end of jsonld API factory +return jsonld; +}; + +// external APIs: + +// used to generate a new jsonld API instance +var factory = function() { + return wrapper(function() { + return factory(); + }); +}; + +if(!_nodejs && (typeof define === 'function' && define.amd)) { + // export AMD API + define([], function() { + // now that module is defined, wrap main jsonld API instance + wrapper(factory); + return factory; + }); +} else { + // wrap the main jsonld API instance + wrapper(factory); + + if(typeof _dereq_ === 'function' && + typeof module !== 'undefined' && module.exports) { + // export CommonJS/nodejs API + module.exports = factory; } - */ - Fetcher.XHTMLHandler = function (args) { - if (args) { - this.dom = args[0]; + + if(_browser) { + // export simple browser API + if(typeof jsonld === 'undefined') { + jsonld = jsonldjs = factory; + } else { + jsonldjs = factory; } - this.handlerFactory = function (xhr) { - xhr.handle = function (cb) { - var relation, reverse; - if (!this.dom) { - this.dom = Util.parseXML(xhr.responseText); - } - var kb = sf.store; + } +} - // dc:title - var title = this.dom.getElementsByTagName('title'); - if (title.length > 0) { - kb.add(xhr.resource, ns.dc('title'), kb.literal(title[0].textContent), xhr.resource); - // log.info("Inferring title of " + xhr.resource) - } +return factory; - // link rel - var links = this.dom.getElementsByTagName('link'); - for (var x = links.length - 1; x >= 0; x--) { - // @@ rev - relation = links[x].getAttribute('rel'); - reverse = false; - if (!relation) { - relation = links[x].getAttribute('rev'); - reverse = true; - } - if (relation) { - sf.linkData(xhr, relation, links[x].getAttribute('href'), xhr.resource, reverse); - } - } +})(); - // Data Islands +}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},"/node_modules/jsonld/js") - var scripts = this.dom.getElementsByTagName('script'); - for (var i = 0; i < scripts.length; i++) { - var contentType = scripts[i].getAttribute('type'); - if (Parsable[contentType]) { - rdfParse(scripts[i].textContent, kb, xhr.original.uri, contentType); - } - } +},{"_process":12,"crypto":54,"es6-promise":53,"http":54,"jsonld-request":54,"pkginfo":54,"request":54,"util":54,"xmldom":54}],56:[function(_dereq_,module,exports){ +var pkg = _dereq_('./src/libsbgn'); - if (!xhr.options.noMeta) { - kb.add(xhr.resource, ns.rdf('type'), ns.link('WebPage'), sf.appNode); - } +module.exports = pkg; - if (!xhr.options.noRDFa && parseRDFaDOM) { - // enable by default - try { - parseRDFaDOM(this.dom, kb, xhr.original.uri); - } catch (e) { - var msg = 'Error trying to parse ' + xhr.resource + ' as RDFa:\n' + e + ':\n' + e.stack; - // dump(msg+"\n") - sf.failFetch(xhr, msg); - return; - } - } - cb(); // Fire done callbacks - }; - }; - }; - Fetcher.XHTMLHandler.toString = function () { - return 'XHTMLHandler'; - }; - Fetcher.XHTMLHandler.register = function (sf) { - sf.mediatypes['application/xhtml+xml'] = {}; +},{"./src/libsbgn":88}],57:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(function() { + "use strict"; + exports.stripBOM = function(str) { + if (str[0] === '\uFEFF') { + return str.substring(1); + } else { + return str; + } }; - Fetcher.XHTMLHandler.pattern = new RegExp('application/xhtml'); - Fetcher.XMLHandler = function () { - this.handlerFactory = function (xhr) { - xhr.handle = function (cb) { - var dom = Util.parseXML(xhr.responseText); - - // XML Semantics defined by root element namespace - // figure out the root element - for (var c = 0; c < dom.childNodes.length; c++) { - // is this node an element? - if (dom.childNodes[c].nodeType === 1) { - // We've found the first element, it's the root - var ns = dom.childNodes[c].namespaceURI; +}).call(this); - // Is it RDF/XML? - if (ns && ns === ns['rdf']) { - sf.addStatus(xhr.req, 'Has XML root element in the RDF namespace, so assume RDF/XML.'); - sf.switchHandler('RDFXMLHandler', xhr, cb, [dom]); - return; - } - // it isn't RDF/XML or we can't tell - // Are there any GRDDL transforms for this namespace? - // @@ assumes ns documents have already been loaded - /* - var xforms = kb.each(kb.sym(ns), kb.sym("http://www.w3.org/2003/g/data-view#namespaceTransformation")) - for (var i = 0; i < xforms.length; i++) { - var xform = xforms[i] - // log.info(xhr.resource.uri + " namespace " + ns + " has GRDDL ns transform" + xform.uri) - Fetcher.doGRDDL(kb, xhr.resource, xform.uri, xhr.resource.uri) - } - */ - break; - } - } +},{}],58:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(function() { + "use strict"; + var builder, defaults, escapeCDATA, requiresCDATA, wrapCDATA, + hasProp = {}.hasOwnProperty; - // Or it could be XHTML? - // Maybe it has an XHTML DOCTYPE? - if (dom.doctype) { - // log.info("We found a DOCTYPE in " + xhr.resource) - if (dom.doctype.name === 'html' && dom.doctype.publicId.match(/^-\/\/W3C\/\/DTD XHTML/) && dom.doctype.systemId.match(/http:\/\/www.w3.org\/TR\/xhtml/)) { - sf.addStatus(xhr.req, 'Has XHTML DOCTYPE. Switching to XHTML Handler.\n'); - sf.switchHandler('XHTMLHandler', xhr, cb); - return; - } - } + builder = _dereq_('xmlbuilder'); - // Or what about an XHTML namespace? - var html = dom.getElementsByTagName('html')[0]; - if (html) { - var xmlns = html.getAttribute('xmlns'); - if (xmlns && xmlns.match(/^http:\/\/www.w3.org\/1999\/xhtml/)) { - sf.addStatus(xhr.req, 'Has a default namespace for ' + 'XHTML. Switching to XHTMLHandler.\n'); - sf.switchHandler('XHTMLHandler', xhr, cb); - return; - } - } + defaults = _dereq_('./defaults').defaults; - // At this point we should check the namespace document (cache it!) and - // look for a GRDDL transform - // @@ Get namespace document , parse it, look for grddl:namespaceTransform ?y - // Apply ?y to dom - // We give up. What dialect is this? - sf.failFetch(xhr, 'Unsupported dialect of XML: not RDF or XHTML namespace, etc.\n' + xhr.responseText.slice(0, 80)); - }; - }; + requiresCDATA = function(entry) { + return typeof entry === "string" && (entry.indexOf('&') >= 0 || entry.indexOf('>') >= 0 || entry.indexOf('<') >= 0); }; - Fetcher.XMLHandler.toString = function () { - return 'XMLHandler'; - }; - Fetcher.XMLHandler.register = function (sf) { - sf.mediatypes['text/xml'] = { - 'q': 0.5 - }; - sf.mediatypes['application/xml'] = { - 'q': 0.5 - }; + wrapCDATA = function(entry) { + return ""; }; - Fetcher.XMLHandler.pattern = new RegExp('(text|application)/(.*)xml'); - - Fetcher.HTMLHandler = function () { - this.handlerFactory = function (xhr) { - xhr.handle = function (cb) { - var rt = xhr.responseText; - // We only handle XHTML so we have to figure out if this is XML - // log.info("Sniffing HTML " + xhr.resource + " for XHTML.") - - if (rt.match(/\s*<\?xml\s+version\s*=[^<>]+\?>/)) { - sf.addStatus(xhr.req, "Has an XML declaration. We'll assume " + "it's XHTML as the content-type was text/html.\n"); - sf.switchHandler('XHTMLHandler', xhr, cb); - return; - } - - // DOCTYPE - // There is probably a smarter way to do this - if (rt.match(/.*/)) { - sf.addStatus(xhr.req, 'Has XHTML DOCTYPE. Switching to XHTMLHandler.\n'); - sf.switchHandler('XHTMLHandler', xhr, cb); - return; - } - - // xmlns - if (rt.match(/[^(/)) { - sf.addStatus(xhr.req, 'Has default namespace for XHTML, so switching to XHTMLHandler.\n'); - sf.switchHandler('XHTMLHandler', xhr, cb); - return; - } - // dc:title //no need to escape '/' here - var titleMatch = new RegExp('([\\s\\S]+?)', 'im').exec(rt); - if (titleMatch) { - var kb = sf.store; - kb.add(xhr.resource, ns.dc('title'), kb.literal(titleMatch[1]), xhr.resource); // think about xml:lang later - kb.add(xhr.resource, ns.rdf('type'), ns.link('WebPage'), sf.appNode); - cb(); // doneFetch, not failed - return; - } - sf.addStatus(xhr.req, 'non-XML HTML document, not parsed for data.'); - sf.doneFetch(xhr); - // sf.failFetch(xhr, "Sorry, can't yet parse non-XML HTML") - }; - }; + escapeCDATA = function(entry) { + return entry.replace(']]>', ']]]]>'); }; - Fetcher.HTMLHandler.toString = function () { - return 'HTMLHandler'; - }; - Fetcher.HTMLHandler.register = function (sf) { - sf.mediatypes['text/html'] = { - 'q': 0.9 - }; - }; - Fetcher.HTMLHandler.pattern = new RegExp('text/html'); + exports.Builder = (function() { + function Builder(opts) { + var key, ref, value; + this.options = {}; + ref = defaults["0.2"]; + for (key in ref) { + if (!hasProp.call(ref, key)) continue; + value = ref[key]; + this.options[key] = value; + } + for (key in opts) { + if (!hasProp.call(opts, key)) continue; + value = opts[key]; + this.options[key] = value; + } + } - Fetcher.TextHandler = function () { - this.handlerFactory = function (xhr) { - xhr.handle = function (cb) { - // We only speak dialects of XML right now. Is this XML? - var rt = xhr.responseText; + Builder.prototype.buildObject = function(rootObj) { + var attrkey, charkey, render, rootElement, rootName; + attrkey = this.options.attrkey; + charkey = this.options.charkey; + if ((Object.keys(rootObj).length === 1) && (this.options.rootName === defaults['0.2'].rootName)) { + rootName = Object.keys(rootObj)[0]; + rootObj = rootObj[rootName]; + } else { + rootName = this.options.rootName; + } + render = (function(_this) { + return function(element, obj) { + var attr, child, entry, index, key, value; + if (typeof obj !== 'object') { + if (_this.options.cdata && requiresCDATA(obj)) { + element.raw(wrapCDATA(obj)); + } else { + element.txt(obj); + } + } else if (Array.isArray(obj)) { + for (index in obj) { + if (!hasProp.call(obj, index)) continue; + child = obj[index]; + for (key in child) { + entry = child[key]; + element = render(element.ele(key), entry).up(); + } + } + } else { + for (key in obj) { + if (!hasProp.call(obj, key)) continue; + child = obj[key]; + if (key === attrkey) { + if (typeof child === "object") { + for (attr in child) { + value = child[attr]; + element = element.att(attr, value); + } + } + } else if (key === charkey) { + if (_this.options.cdata && requiresCDATA(child)) { + element = element.raw(wrapCDATA(child)); + } else { + element = element.txt(child); + } + } else if (Array.isArray(child)) { + for (index in child) { + if (!hasProp.call(child, index)) continue; + entry = child[index]; + if (typeof entry === 'string') { + if (_this.options.cdata && requiresCDATA(entry)) { + element = element.ele(key).raw(wrapCDATA(entry)).up(); + } else { + element = element.ele(key, entry).up(); + } + } else { + element = render(element.ele(key), entry).up(); + } + } + } else if (typeof child === "object") { + element = render(element.ele(key), child).up(); + } else { + if (typeof child === 'string' && _this.options.cdata && requiresCDATA(child)) { + element = element.ele(key).raw(wrapCDATA(child)).up(); + } else { + if (child == null) { + child = ''; + } + element = element.ele(key, child.toString()).up(); + } + } + } + } + return element; + }; + })(this); + rootElement = builder.create(rootName, this.options.xmldec, this.options.doctype, { + headless: this.options.headless, + allowSurrogateChars: this.options.allowSurrogateChars + }); + return render(rootElement, rootObj).end(this.options.renderOpts); + }; - // Look for an XML declaration - if (rt.match(/\s*<\?xml\s+version\s*=[^<>]+\?>/)) { - sf.addStatus(xhr.req, 'Warning: ' + xhr.resource + " has an XML declaration. We'll assume " + "it's XML but its content-type wasn't XML.\n"); - sf.switchHandler('XMLHandler', xhr, cb); - return; - } + return Builder; - // Look for an XML declaration - if (rt.slice(0, 500).match(/xmlns:/)) { - sf.addStatus(xhr.req, "May have an XML namespace. We'll assume " + "it's XML but its content-type wasn't XML.\n"); - sf.switchHandler('XMLHandler', xhr, cb); - return; - } + })(); - // We give up finding semantics - this is not an error, just no data - sf.addStatus(xhr.req, 'Plain text document, no known RDF semantics.'); - sf.doneFetch(xhr); - // sf.failFetch(xhr, "unparseable - text/plain not visibly XML") - // dump(xhr.resource + " unparseable - text/plain not visibly XML, starts:\n" + rt.slice(0, 500)+"\n") - }; - }; - }; +}).call(this); - Fetcher.TextHandler.toString = function () { - return 'TextHandler'; - }; - Fetcher.TextHandler.register = function (sf) { - sf.mediatypes['text/plain'] = { - 'q': 0.5 - }; +},{"./defaults":59,"xmlbuilder":84}],59:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(function() { + exports.defaults = { + "0.1": { + explicitCharkey: false, + trim: true, + normalize: true, + normalizeTags: false, + attrkey: "@", + charkey: "#", + explicitArray: false, + ignoreAttrs: false, + mergeAttrs: false, + explicitRoot: false, + validator: null, + xmlns: false, + explicitChildren: false, + childkey: '@@', + charsAsChildren: false, + includeWhiteChars: false, + async: false, + strict: true, + attrNameProcessors: null, + attrValueProcessors: null, + tagNameProcessors: null, + valueProcessors: null, + emptyTag: '' + }, + "0.2": { + explicitCharkey: false, + trim: false, + normalize: false, + normalizeTags: false, + attrkey: "$", + charkey: "_", + explicitArray: true, + ignoreAttrs: false, + mergeAttrs: false, + explicitRoot: true, + validator: null, + xmlns: false, + explicitChildren: false, + preserveChildrenOrder: false, + childkey: '$$', + charsAsChildren: false, + includeWhiteChars: false, + async: false, + strict: true, + attrNameProcessors: null, + attrValueProcessors: null, + tagNameProcessors: null, + valueProcessors: null, + rootName: 'root', + xmldec: { + 'version': '1.0', + 'encoding': 'UTF-8', + 'standalone': true + }, + doctype: null, + renderOpts: { + 'pretty': true, + 'indent': ' ', + 'newline': '\n' + }, + headless: false, + chunkSize: 10000, + emptyTag: '', + cdata: false + } }; - Fetcher.TextHandler.pattern = new RegExp('text/plain'); - Fetcher.N3Handler = function () { - this.handlerFactory = function (xhr) { - xhr.handle = function (cb) { - // Parse the text of this non-XML file +}).call(this); - // console.log('web.js: Parsing as N3 ' + xhr.resource.uri + ' base: ' + xhr.original.uri) // @@@@ comment me out - // sf.addStatus(xhr.req, "N3 not parsed yet...") - var p = N3Parser(kb, kb, xhr.original.uri, xhr.original.uri, null, null, '', null); - // p.loadBuf(xhr.responseText) - try { - p.loadBuf(xhr.responseText); - } catch (e) { - var msg = 'Error trying to parse ' + xhr.resource + ' as Notation3:\n' + e + ':\n' + e.stack; - // dump(msg+"\n") - sf.failFetch(xhr, msg); - return; - } +},{}],60:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(function() { + "use strict"; + var bom, defaults, events, isEmpty, processItem, processors, sax, setImmediate, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; - sf.addStatus(xhr.req, 'N3 parsed: ' + p.statementCount + ' triples in ' + p.lines + ' lines.'); - sf.store.add(xhr.original, ns.rdf('type'), ns.link('RDFDocument'), sf.appNode); - // var args = [xhr.original.uri] // Other args needed ever? - sf.doneFetch(xhr); - }; - }; - }; + sax = _dereq_('sax'); - Fetcher.N3Handler.toString = function () { - return 'N3Handler'; - }; - Fetcher.N3Handler.register = function (sf) { - sf.mediatypes['text/n3'] = { - 'q': '1.0' - }; // as per 2008 spec - /* - sf.mediatypes['application/x-turtle'] = { - 'q': 1.0 - } // pre 2008 - */ - sf.mediatypes['text/turtle'] = { - 'q': 1.0 - }; // post 2008 - }; - Fetcher.N3Handler.pattern = new RegExp('(application|text)/(x-)?(rdf\\+)?(n3|turtle)'); + events = _dereq_('events'); - Util.callbackify(this, ['request', 'recv', 'headers', 'load', 'fail', 'refresh', 'retract', 'done']); + bom = _dereq_('./bom'); - this.addHandler = function (handler) { - sf.handlers.push(handler); - handler.register(sf); - }; + processors = _dereq_('./processors'); - this.switchHandler = function (name, xhr, cb, args) { - var Handler = null; - for (var i = 0; i < this.handlers.length; i++) { - if ('' + this.handlers[i] === name) { - Handler = this.handlers[i]; - } - } - if (!Handler) { - throw new Error('web.js: switchHandler: name=' + name + ' , this.handlers =' + this.handlers + '\n' + 'switchHandler: switching to ' + Handler + '; sf=' + sf + '; typeof Fetcher=' + (typeof Fetcher === 'undefined' ? 'undefined' : _typeof(Fetcher)) + ';\n\t Fetcher.HTMLHandler=' + Fetcher.HTMLHandler + '\n' + '\n\tsf.handlers=' + sf.handlers + '\n'); - } - new Handler(args).handlerFactory(xhr); - xhr.handle(cb); - }; + setImmediate = _dereq_('timers').setImmediate; - this.addStatus = function (req, status) { - // - var now = new Date(); - status = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '.' + now.getMilliseconds() + '] ' + status; - // - var kb = this.store; - var s = kb.the(req, ns.link('status')); - if (s && s.append) { - s.append(kb.literal(status)); - } else { - log.warn('web.js: No list to add to: ' + s + ',' + status); // @@@ - } - }; + defaults = _dereq_('./defaults').defaults; - // Record errors in the system on failure - // Returns xhr so can just do return this.failfetch(...) - this.failFetch = function (xhr, status) { - this.addStatus(xhr.req, status); - if (!xhr.options.noMeta) { - kb.add(xhr.original, ns.link('error'), status); - } - if (!xhr.resource.sameTerm(xhr.original)) { - console.log('@@ Recording failure original ' + xhr.original + '( as ' + xhr.resource + ') : ' + xhr.status); - } else { - console.log('@@ Recording failure for ' + xhr.original + ': ' + xhr.status); - } - this.requested[Uri.docpart(xhr.original.uri)] = xhr.status; // changed 2015 was false - while (this.fetchCallbacks[xhr.original.uri] && this.fetchCallbacks[xhr.original.uri].length) { - this.fetchCallbacks[xhr.original.uri].shift()(false, 'Fetch of <' + xhr.original.uri + '> failed: ' + status, xhr); - } - delete this.fetchCallbacks[xhr.original.uri]; - this.fireCallbacks('fail', [xhr.original.uri, status]); - xhr.abort(); - return xhr; + isEmpty = function(thing) { + return typeof thing === "object" && (thing != null) && Object.keys(thing).length === 0; }; - // in the why part of the quad distinguish between HTML and HTTP header - // Reverse is set iif the link was rev= as opposed to rel= - this.linkData = function (xhr, rel, uri, why, reverse) { - if (!uri) return; - var predicate; - // See http://www.w3.org/TR/powder-dr/#httplink for describedby 2008-12-10 - var obj = kb.sym(Uri.join(uri, xhr.original.uri)); - if (rel === 'alternate' || rel === 'seeAlso' || rel === 'meta' || rel === 'describedby') { - if (obj.uri === xhr.original.uri) return; - predicate = ns.rdfs('seeAlso'); - } else if (rel === 'type') { - predicate = kb.sym('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); - } else { - // See https://www.iana.org/assignments/link-relations/link-relations.xml - // Alas not yet in RDF yet for each predicate - /// encode space in e.g. rel="shortcut icon" - predicate = kb.sym(Uri.join(encodeURIComponent(rel), 'http://www.iana.org/assignments/link-relations/')); - } - if (reverse) { - kb.add(obj, predicate, xhr.original, why); - } else { - kb.add(xhr.original, predicate, obj, why); + processItem = function(processors, item, key) { + var i, len, process; + for (i = 0, len = processors.length; i < len; i++) { + process = processors[i]; + item = process(item, key); } + return item; }; - this.parseLinkHeader = function (xhr, thisReq) { - var link; - try { - link = xhr.getResponseHeader('link'); // May crash from CORS error - } catch (e) {} - if (link) { - var linkexp = /<[^>]*>\s*(\s*;\s*[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*")))*(,|$)/g; - var paramexp = /[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*"))/g; + exports.Parser = (function(superClass) { + extend(Parser, superClass); - var matches = link.match(linkexp); - for (var i = 0; i < matches.length; i++) { - var split = matches[i].split('>'); - var href = split[0].substring(1); - var ps = split[1]; - var s = ps.match(paramexp); - for (var j = 0; j < s.length; j++) { - var p = s[j]; - var paramsplit = p.split('='); - // var name = paramsplit[0] - var rel = paramsplit[1].replace(/["']/g, ''); // '" - this.linkData(xhr, rel, href, thisReq); - } + function Parser(opts) { + this.parseString = bind(this.parseString, this); + this.reset = bind(this.reset, this); + this.assignOrPush = bind(this.assignOrPush, this); + this.processAsync = bind(this.processAsync, this); + var key, ref, value; + if (!(this instanceof exports.Parser)) { + return new exports.Parser(opts); } + this.options = {}; + ref = defaults["0.2"]; + for (key in ref) { + if (!hasProp.call(ref, key)) continue; + value = ref[key]; + this.options[key] = value; + } + for (key in opts) { + if (!hasProp.call(opts, key)) continue; + value = opts[key]; + this.options[key] = value; + } + if (this.options.xmlns) { + this.options.xmlnskey = this.options.attrkey + "ns"; + } + if (this.options.normalizeTags) { + if (!this.options.tagNameProcessors) { + this.options.tagNameProcessors = []; + } + this.options.tagNameProcessors.unshift(processors.normalize); + } + this.reset(); } - }; - - this.doneFetch = function (xhr) { - this.addStatus(xhr.req, 'Done.'); - this.requested[xhr.original.uri] = 'done'; // Kenny - while (this.fetchCallbacks[xhr.original.uri] && this.fetchCallbacks[xhr.original.uri].length) { - this.fetchCallbacks[xhr.original.uri].shift()(true, undefined, xhr); - } - delete this.fetchCallbacks[xhr.original.uri]; - this.fireCallbacks('done', [xhr.original.uri]); - }; - var handlerList = [Fetcher.RDFXMLHandler, Fetcher.XHTMLHandler, Fetcher.XMLHandler, Fetcher.HTMLHandler, Fetcher.TextHandler, Fetcher.N3Handler]; - handlerList.map(this.addHandler); - - /** Note two nodes are now smushed - ** - ** If only one was flagged as looked up, then - ** the new node is looked up again, which - ** will make sure all the URIs are dereferenced - */ - this.nowKnownAs = function (was, now) { - if (this.lookedUp[was.uri]) { - if (!this.lookedUp[now.uri]) this.lookUpThing(now, was); // @@@@ Transfer userCallback - } else if (this.lookedUp[now.uri]) { - if (!this.lookedUp[was.uri]) this.lookUpThing(was, now); - } - }; - - // Returns promise of XHR - // - // Writes back to the web what we have in the store for this uri - this.putBack = function (uri) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - - uri = uri.uri || uri; // Accept object or string - var doc = new NamedNode(uri).doc(); // strip off # - options.data = serialize(doc, this.store, doc.uri, options.contentType || 'text/turtle'); - return this.webOperation('PUT', uri, options); - }; - // Returns promise of XHR - // - this.webOperation = function (method, uri) { - var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + Parser.prototype.processAsync = function() { + var chunk, err; + try { + if (this.remaining.length <= this.options.chunkSize) { + chunk = this.remaining; + this.remaining = ''; + this.saxParser = this.saxParser.write(chunk); + return this.saxParser.close(); + } else { + chunk = this.remaining.substr(0, this.options.chunkSize); + this.remaining = this.remaining.substr(this.options.chunkSize, this.remaining.length); + this.saxParser = this.saxParser.write(chunk); + return setImmediate(this.processAsync); + } + } catch (error1) { + err = error1; + if (!this.saxParser.errThrown) { + this.saxParser.errThrown = true; + return this.emit(err); + } + } + }; - uri = uri.uri || uri; - uri = this.proxyIfNecessary(uri); - var fetcher = this; - return new Promise(function (resolve, reject) { - var xhr = Util.XMLHTTPFactory(); - xhr.options = options; - xhr.original = fetcher.store.sym(uri); - if (!options.noMeta && typeof tabulator !== 'undefined') { - fetcher.saveRequestMetadata(xhr, fetcher.store, uri); + Parser.prototype.assignOrPush = function(obj, key, newValue) { + if (!(key in obj)) { + if (!this.options.explicitArray) { + return obj[key] = newValue; + } else { + return obj[key] = [newValue]; + } + } else { + if (!(obj[key] instanceof Array)) { + obj[key] = [obj[key]]; + } + return obj[key].push(newValue); } - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - // NOte a 404 can be not afailure - var ok = !xhr.status || xhr.status >= 200 && xhr.status < 300; - if (!options.noMeta && typeof tabulator !== 'undefined') { - fetcher.saveResponseMetadata(xhr, fetcher.store); + }; + + Parser.prototype.reset = function() { + var attrkey, charkey, ontext, stack; + this.removeAllListeners(); + this.saxParser = sax.parser(this.options.strict, { + trim: false, + normalize: false, + xmlns: this.options.xmlns + }); + this.saxParser.errThrown = false; + this.saxParser.onerror = (function(_this) { + return function(error) { + _this.saxParser.resume(); + if (!_this.saxParser.errThrown) { + _this.saxParser.errThrown = true; + return _this.emit("error", error); } - if (ok) { - resolve(xhr); + }; + })(this); + this.saxParser.onend = (function(_this) { + return function() { + if (!_this.saxParser.ended) { + _this.saxParser.ended = true; + return _this.emit("end", _this.resultObject); + } + }; + })(this); + this.saxParser.ended = false; + this.EXPLICIT_CHARKEY = this.options.explicitCharkey; + this.resultObject = null; + stack = []; + attrkey = this.options.attrkey; + charkey = this.options.charkey; + this.saxParser.onopentag = (function(_this) { + return function(node) { + var key, newValue, obj, processedKey, ref; + obj = {}; + obj[charkey] = ""; + if (!_this.options.ignoreAttrs) { + ref = node.attributes; + for (key in ref) { + if (!hasProp.call(ref, key)) continue; + if (!(attrkey in obj) && !_this.options.mergeAttrs) { + obj[attrkey] = {}; + } + newValue = _this.options.attrValueProcessors ? processItem(_this.options.attrValueProcessors, node.attributes[key], key) : node.attributes[key]; + processedKey = _this.options.attrNameProcessors ? processItem(_this.options.attrNameProcessors, key) : key; + if (_this.options.mergeAttrs) { + _this.assignOrPush(obj, processedKey, newValue); + } else { + obj[attrkey][processedKey] = newValue; + } + } + } + obj["#name"] = _this.options.tagNameProcessors ? processItem(_this.options.tagNameProcessors, node.name) : node.name; + if (_this.options.xmlns) { + obj[_this.options.xmlnskey] = { + uri: node.uri, + local: node.local + }; + } + return stack.push(obj); + }; + })(this); + this.saxParser.onclosetag = (function(_this) { + return function() { + var cdata, emptyStr, key, node, nodeName, obj, objClone, old, s, xpath; + obj = stack.pop(); + nodeName = obj["#name"]; + if (!_this.options.explicitChildren || !_this.options.preserveChildrenOrder) { + delete obj["#name"]; + } + if (obj.cdata === true) { + cdata = obj.cdata; + delete obj.cdata; + } + s = stack[stack.length - 1]; + if (obj[charkey].match(/^\s*$/) && !cdata) { + emptyStr = obj[charkey]; + delete obj[charkey]; } else { - reject(xhr.status + ' ' + xhr.statusText); + if (_this.options.trim) { + obj[charkey] = obj[charkey].trim(); + } + if (_this.options.normalize) { + obj[charkey] = obj[charkey].replace(/\s{2,}/g, " ").trim(); + } + obj[charkey] = _this.options.valueProcessors ? processItem(_this.options.valueProcessors, obj[charkey], nodeName) : obj[charkey]; + if (Object.keys(obj).length === 1 && charkey in obj && !_this.EXPLICIT_CHARKEY) { + obj = obj[charkey]; + } } - } - }; - xhr.open(method, uri, true); - xhr.setRequestHeader('Content-type', options.contentType || 'text/turtle'); - xhr.send(options.data ? options.data : undefined); - }); - }; + if (isEmpty(obj)) { + obj = _this.options.emptyTag !== '' ? _this.options.emptyTag : emptyStr; + } + if (_this.options.validator != null) { + xpath = "/" + ((function() { + var i, len, results; + results = []; + for (i = 0, len = stack.length; i < len; i++) { + node = stack[i]; + results.push(node["#name"]); + } + return results; + })()).concat(nodeName).join("/"); + (function() { + var err; + try { + return obj = _this.options.validator(xpath, s && s[nodeName], obj); + } catch (error1) { + err = error1; + return _this.emit("error", err); + } + })(); + } + if (_this.options.explicitChildren && !_this.options.mergeAttrs && typeof obj === 'object') { + if (!_this.options.preserveChildrenOrder) { + node = {}; + if (_this.options.attrkey in obj) { + node[_this.options.attrkey] = obj[_this.options.attrkey]; + delete obj[_this.options.attrkey]; + } + if (!_this.options.charsAsChildren && _this.options.charkey in obj) { + node[_this.options.charkey] = obj[_this.options.charkey]; + delete obj[_this.options.charkey]; + } + if (Object.getOwnPropertyNames(obj).length > 0) { + node[_this.options.childkey] = obj; + } + obj = node; + } else if (s) { + s[_this.options.childkey] = s[_this.options.childkey] || []; + objClone = {}; + for (key in obj) { + if (!hasProp.call(obj, key)) continue; + objClone[key] = obj[key]; + } + s[_this.options.childkey].push(objClone); + delete obj["#name"]; + if (Object.keys(obj).length === 1 && charkey in obj && !_this.EXPLICIT_CHARKEY) { + obj = obj[charkey]; + } + } + } + if (stack.length > 0) { + return _this.assignOrPush(s, nodeName, obj); + } else { + if (_this.options.explicitRoot) { + old = obj; + obj = {}; + obj[nodeName] = old; + } + _this.resultObject = obj; + _this.saxParser.ended = true; + return _this.emit("end", _this.resultObject); + } + }; + })(this); + ontext = (function(_this) { + return function(text) { + var charChild, s; + s = stack[stack.length - 1]; + if (s) { + s[charkey] += text; + if (_this.options.explicitChildren && _this.options.preserveChildrenOrder && _this.options.charsAsChildren && (_this.options.includeWhiteChars || text.replace(/\\n/g, '').trim() !== '')) { + s[_this.options.childkey] = s[_this.options.childkey] || []; + charChild = { + '#name': '__text__' + }; + charChild[charkey] = text; + if (_this.options.normalize) { + charChild[charkey] = charChild[charkey].replace(/\s{2,}/g, " ").trim(); + } + s[_this.options.childkey].push(charChild); + } + return s; + } + }; + })(this); + this.saxParser.ontext = ontext; + return this.saxParser.oncdata = (function(_this) { + return function(text) { + var s; + s = ontext(text); + if (s) { + return s.cdata = true; + } + }; + })(this); + }; - this.webCopy = function (here, there, content_type) { - var fetcher = this; - here = here.uri || here; - return new Promise(function (resolve, reject) { - fetcher.webOperation('GET', here).then(function (xhr) { - fetcher.webOperation('PUT', // @@@ change to binary from text - there, { data: xhr.responseText, contentType: content_type }).then(function (xhr) { - resolve(xhr); - }).catch(function (e) { - reject(e); + Parser.prototype.parseString = function(str, cb) { + var err; + if ((cb != null) && typeof cb === "function") { + this.on("end", function(result) { + this.reset(); + return cb(null, result); }); - }).catch(function (e) { - reject(e); - }); - }); - }; + this.on("error", function(err) { + this.reset(); + return cb(err); + }); + } + try { + str = str.toString(); + if (str.trim() === '') { + this.emit('error', new Error("Empty string is not valid XML")); + return; + } + str = bom.stripBOM(str); + if (this.options.async) { + this.remaining = str; + setImmediate(this.processAsync); + return this.saxParser; + } + return this.saxParser.write(str).close(); + } catch (error1) { + err = error1; + if (!(this.saxParser.errThrown || this.saxParser.ended)) { + this.emit('error', err); + return this.saxParser.errThrown = true; + } else if (this.saxParser.ended) { + throw err; + } + } + }; - // Looks up something. - // - // Looks up all the URIs a things has. - // - // Parameters: - // - // term: canonical term for the thing whose URI is to be dereferenced - // rterm: the resource which refered to this (for tracking bad links) - // options: (old: force paraemter) or dictionary of options: - // force: Load the data even if loaded before - // oneDone: is called as callback(ok, errorbody, xhr) for each one - // allDone: is called as callback(ok, errorbody) for all of them - // Returns the number of URIs fetched - // - this.lookUpThing = function (term, rterm, options, oneDone, allDone) { - var uris = kb.uris(term); // Get all URIs - var success = true; - var errors = ''; - var outstanding = {}; - var force; - if (options === false || options === true) { - // Old signature - force = options; - options = { force: force }; - } else { - if (options === undefined) options = {}; - force = !!options.force; - } + return Parser; - if (typeof uris !== 'undefined') { - for (var i = 0; i < uris.length; i++) { - var u = uris[i]; - outstanding[u] = true; - this.lookedUp[u] = true; - var sf = this; + })(events.EventEmitter); - var requestOne = function requestOne(u1) { - sf.requestURI(Uri.docpart(u1), rterm, options, function (ok, body, xhr) { - if (ok) { - if (oneDone) oneDone(true, u1); - } else { - if (oneDone) oneDone(false, body); - success = false; - errors += body + '\n'; - } - delete outstanding[u]; - if (Object.keys(outstanding).length > 0) { - return; - } - if (allDone) { - allDone(success, errors); - } - }); - }; - requestOne(u); + exports.parseString = function(str, a, b) { + var cb, options, parser; + if (b != null) { + if (typeof b === 'function') { + cb = b; + } + if (typeof a === 'object') { + options = a; + } + } else { + if (typeof a === 'function') { + cb = a; } + options = {}; } - return uris.length; + parser = new exports.Parser(options); + return parser.parseString(str, cb); }; - /* Promise-based load function - ** - ** NamedNode -> Promise of xhr - ** uri string -> Promise of xhr - ** Array of the above -> Promise of array of xhr - ** - ** @@ todo: If p1 is array then sequence or parallel fetch of all - */ - this.load = function (uri, options) { - var fetcher = this; - if (uri instanceof Array) { - var ps = uri.map(function (x) { - return fetcher.load(x); - }); - return Promise.all(ps); - } - uri = uri.uri || uri; // NamedNode or URI string - return new Promise(function (resolve, reject) { - fetcher.nowOrWhenFetched(uri, options, function (ok, message, xhr) { - if (ok) { - resolve(xhr); - } else { - reject(message); - } - }); - }); +}).call(this); + +},{"./bom":57,"./defaults":59,"./processors":61,"events":8,"sax":281,"timers":47}],61:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(function() { + "use strict"; + var prefixMatch; + + prefixMatch = new RegExp(/(?!xmlns)^.*:/); + + exports.normalize = function(str) { + return str.toLowerCase(); }; - /* Ask for a doc to be loaded if necessary then call back - ** - ** Changed 2013-08-20: Added (ok, errormessage) params to callback - ** - ** Calling methods: - ** nowOrWhenFetched (uri, userCallback) - ** nowOrWhenFetched (uri, options, userCallback) - ** nowOrWhenFetched (uri, referringTerm, userCallback, options) <-- old - ** nowOrWhenFetched (uri, referringTerm, userCallback) <-- old - ** - ** Options include: - ** referringTerm The docuemnt in which this link was found. - ** this is valuable when finding the source of bad URIs - ** force boolean. Never mind whether you have tried before, - ** load this from scratch. - ** forceContentType Override the incoming header to force the data to be - ** treaed as this content-type. - **/ - this.nowOrWhenFetched = function (uri, p2, userCallback, options) { - uri = uri.uri || uri; // allow symbol object or string to be passed - if (typeof p2 === 'function') { - options = {}; - userCallback = p2; - } else if (typeof p2 === 'undefined') {// original calling signature - // referingTerm = undefined - } else if (p2 instanceof NamedNode) { - // referingTerm = p2 - options = { referingTerm: p2 }; - } else { - options = p2; + exports.firstCharLowerCase = function(str) { + return str.charAt(0).toLowerCase() + str.slice(1); + }; + + exports.stripPrefix = function(str) { + return str.replace(prefixMatch, ''); + }; + + exports.parseNumbers = function(str) { + if (!isNaN(str)) { + str = str % 1 === 0 ? parseInt(str, 10) : parseFloat(str); } + return str; + }; - this.requestURI(uri, p2, options || {}, userCallback); + exports.parseBooleans = function(str) { + if (/^(?:true|false)$/i.test(str)) { + str = str.toLowerCase() === 'true'; + } + return str; }; - this.get = this.nowOrWhenFetched; +}).call(this); - // Look up response header - // - // Returns: a list of header values found in a stored HTTP response - // or [] if response was found but no header found - // or undefined if no response is available. - // - this.getHeader = function (doc, header) { - var kb = this.store; - var requests = kb.each(undefined, ns.link('requestedURI'), doc.uri); - for (var r = 0; r < requests.length; r++) { - var request = requests[r]; - if (request !== undefined) { - var response = kb.any(request, ns.link('response')); - if (request !== undefined) { - var results = kb.each(response, ns.httph(header.toLowerCase())); - if (results.length) { - return results.map(function (v) { - return v.value; - }); +},{}],62:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(function() { + "use strict"; + var builder, defaults, parser, processors, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + defaults = _dereq_('./defaults'); + + builder = _dereq_('./builder'); + + parser = _dereq_('./parser'); + + processors = _dereq_('./processors'); + + exports.defaults = defaults.defaults; + + exports.processors = processors; + + exports.ValidationError = (function(superClass) { + extend(ValidationError, superClass); + + function ValidationError(message) { + this.message = message; + } + + return ValidationError; + + })(Error); + + exports.Builder = builder.Builder; + + exports.Parser = parser.Parser; + + exports.parseString = parser.parseString; + +}).call(this); + +},{"./builder":58,"./defaults":59,"./parser":60,"./processors":61}],63:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var assign, isArray, isEmpty, isFunction, isObject, isPlainObject, + slice = [].slice, + hasProp = {}.hasOwnProperty; + + assign = function() { + var i, key, len, source, sources, target; + target = arguments[0], sources = 2 <= arguments.length ? slice.call(arguments, 1) : []; + if (isFunction(Object.assign)) { + Object.assign.apply(null, arguments); + } else { + for (i = 0, len = sources.length; i < len; i++) { + source = sources[i]; + if (source != null) { + for (key in source) { + if (!hasProp.call(source, key)) continue; + target[key] = source[key]; } - return []; } } } - return undefined; + return target; }; - this.proxyIfNecessary = function (uri) { - if (typeof tabulator !== 'undefined' && tabulator.isExtension) return uri; // Extenstion does not need proxy + isFunction = function(val) { + return !!val && Object.prototype.toString.call(val) === '[object Function]'; + }; - if (typeof $SolidTestEnvironment !== 'undefined' && $SolidTestEnvironment.localSiteMap) { - // nested dictionaries of URI parts from origin down - var hostpath = uri.split('/').slice(2); // the bit after the // - var lookup = function lookup(parts, index) { - var z = index[parts.shift()]; - if (!z) return null; - if (typeof z === 'string') { - return z + parts.join('/'); - } - if (!parts) return null; - return lookup(parts, z); - }; - var y = lookup(hostpath, $SolidTestEnvironment.localSiteMap); - if (y) { - return y; - } - } - // browser does 2014 on as https browser script not trusted - // If the web app origin is https: then the mixed content rules - // prevent it loading insecure http: stuff so we need proxy. - if (Fetcher.crossSiteProxyTemplate && typeof document !== 'undefined' && document.location && ('' + document.location).slice(0, 6) === 'https:' && // origin is secure - uri.slice(0, 5) === 'http:') { - // requested data is not - return Fetcher.crossSiteProxyTemplate.replace('{uri}', encodeURIComponent(uri)); - } - return uri; + isObject = function(val) { + var ref; + return !!val && ((ref = typeof val) === 'function' || ref === 'object'); }; - this.saveRequestMetadata = function (xhr, kb, docuri) { - var request = kb.bnode(); - xhr.resource = kb.sym(docuri); + isArray = function(val) { + if (isFunction(Array.isArray)) { + return Array.isArray(val); + } else { + return Object.prototype.toString.call(val) === '[object Array]'; + } + }; - xhr.req = request; - if (!xhr.options.noMeta) { - // Store no triples but do mind the bnode for req - var now = new Date(); - var timeNow = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '] '; - kb.add(request, ns.rdfs('label'), kb.literal(timeNow + ' Request for ' + docuri), this.appNode); - kb.add(request, ns.link('requestedURI'), kb.literal(docuri), this.appNode); - if (xhr.original && xhr.original.uri !== docuri) { - kb.add(request, ns.link('orginalURI'), kb.literal(xhr.original.uri), this.appNode); + isEmpty = function(val) { + var key; + if (isArray(val)) { + return !val.length; + } else { + for (key in val) { + if (!hasProp.call(val, key)) continue; + return false; } - kb.add(request, ns.link('status'), kb.collection(), this.appNode); + return true; } - return request; }; - this.saveResponseMetadata = function (xhr, kb) { - var response = kb.bnode(); + isPlainObject = function(val) { + var ctor, proto; + return isObject(val) && (proto = Object.getPrototypeOf(val)) && (ctor = proto.constructor) && (typeof ctor === 'function') && (ctor instanceof ctor) && (Function.prototype.toString.call(ctor) === Function.prototype.toString.call(Object)); + }; - if (xhr.req) kb.add(xhr.req, ns.link('response'), response); - kb.add(response, ns.http('status'), kb.literal(xhr.status), response); - kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response); + module.exports.assign = assign; - xhr.headers = {}; - if (Uri.protocol(xhr.resource.uri) === 'http' || Uri.protocol(xhr.resource.uri) === 'https') { - xhr.headers = Util.getHTTPHeaders(xhr); - for (var h in xhr.headers) { - // trim below for Safari - adds a CR! - var value = xhr.headers[h].trim(); - var h2 = h.toLowerCase(); - kb.add(response, ns.httph(h2), value, response); - if (h2 === 'content-type') { - // Convert to RDF type - kb.add(xhr.resource, ns.rdf('type'), Util.mediaTypeClass(value), response); - } - } - } - return response; - }; + module.exports.isFunction = isFunction; - /** Requests a document URI and arranges to load the document. - ** Parameters: - ** term: term for the thing whose URI is to be dereferenced - ** rterm: the resource which refered to this (for tracking bad links) - ** options: - ** force: Load the data even if loaded before - ** withCredentials: flag for XHR/CORS etc - ** userCallback: Called with (true) or (false, errorbody, {status: 400}) after load is done or failed - ** Return value: - ** The xhr object for the HTTP access - ** null if the protocol is not a look-up protocol, - ** or URI has already been loaded - */ - this.requestURI = function (docuri, rterm, options, userCallback) { - // sources_request_new - // Various calling conventions - docuri = docuri.uri || docuri; // NamedNode or string - docuri = docuri.split('#')[0]; - if (typeof options === 'boolean') { - options = { 'force': options }; // Ols dignature - } - if (typeof options === 'undefined') options = {}; + module.exports.isObject = isObject; - var force = !!options.force; - var kb = this.store; - var args = arguments; - var baseURI = options.baseURI || docuri; // Preseve though proxying etc - options.userCallback = userCallback; + module.exports.isArray = isArray; - var pcol = Uri.protocol(docuri); - if (pcol === 'tel' || pcol === 'mailto' || pcol === 'urn') { - // "No look-up operation on these, but they are not errors?" - console.log('Unsupported protocol in: ' + docuri); - return userCallback(false, 'Unsupported protocol', { 'status': 900 }) || undefined; - } - var docterm = kb.sym(docuri); + module.exports.isEmpty = isEmpty; - var sta = this.getState(docuri); - if (!force) { - if (sta === 'fetched') { - return userCallback ? userCallback(true) : undefined; + module.exports.isPlainObject = isPlainObject; + +}).call(this); + +},{}],64:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLAttribute; + + module.exports = XMLAttribute = (function() { + function XMLAttribute(parent, name, value) { + this.options = parent.options; + this.stringify = parent.stringify; + if (name == null) { + throw new Error("Missing attribute name of element " + parent.name); } - if (sta === 'failed') { - return userCallback ? userCallback(false, 'Previously failed. ' + this.requested[docuri], { 'status': this.requested[docuri] }) : undefined; // An xhr standin + if (value == null) { + throw new Error("Missing attribute value for attribute " + name + " of element " + parent.name); } - // if (sta === 'requested') return userCallback? userCallback(false, "Sorry already requested - pending already.", {'status': 999 }) : undefined - } else { - delete this.nonexistant[docuri]; + this.name = this.stringify.attName(name); + this.value = this.stringify.attValue(value); } - // @@ Should allow concurrent requests - // If it is 'failed', then shoulkd we try again? I think so so an old error doens't get stuck - // if (sta === 'unrequested') + XMLAttribute.prototype.clone = function() { + return Object.create(this); + }; - this.fireCallbacks('request', args); // Kenny: fire 'request' callbacks here - // dump( "web.js: Requesting uri: " + docuri + "\n" ) + XMLAttribute.prototype.toString = function(options) { + return this.options.writer.set(options).attribute(this); + }; - if (userCallback) { - if (!this.fetchCallbacks[docuri]) { - this.fetchCallbacks[docuri] = [userCallback]; - } else { - this.fetchCallbacks[docuri].push(userCallback); + return XMLAttribute; + + })(); + +}).call(this); + +},{}],65:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLCData, XMLNode, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + XMLNode = _dereq_('./XMLNode'); + + module.exports = XMLCData = (function(superClass) { + extend(XMLCData, superClass); + + function XMLCData(parent, text) { + XMLCData.__super__.constructor.call(this, parent); + if (text == null) { + throw new Error("Missing CDATA text"); } + this.text = this.stringify.cdata(text); } - if (this.requested[docuri] === true) { - return; // Don't ask again - wait for existing call - } else { - this.requested[docuri] = true; - } + XMLCData.prototype.clone = function() { + return Object.create(this); + }; - if (!options.noMeta && rterm && rterm.uri) { - kb.add(docterm.uri, ns.link('requestedBy'), rterm.uri, this.appNode); + XMLCData.prototype.toString = function(options) { + return this.options.writer.set(options).cdata(this); + }; + + return XMLCData; + + })(XMLNode); + +}).call(this); + +},{"./XMLNode":76}],66:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLComment, XMLNode, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + XMLNode = _dereq_('./XMLNode'); + + module.exports = XMLComment = (function(superClass) { + extend(XMLComment, superClass); + + function XMLComment(parent, text) { + XMLComment.__super__.constructor.call(this, parent); + if (text == null) { + throw new Error("Missing comment text"); + } + this.text = this.stringify.comment(text); } - var xhr = Util.XMLHTTPFactory(); - var req = xhr.req = kb.bnode(); - xhr.original = kb.sym(baseURI); - // console.log('XHR original: ' + xhr.original) - xhr.options = options; - xhr.resource = docterm; // This might be proxified - var sf = this; + XMLComment.prototype.clone = function() { + return Object.create(this); + }; - var now = new Date(); - var timeNow = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '] '; - if (!options.noMeta) { - kb.add(req, ns.rdfs('label'), kb.literal(timeNow + ' Request for ' + docuri), this.appNode); - kb.add(req, ns.link('requestedURI'), kb.literal(docuri), this.appNode); - kb.add(req, ns.link('status'), kb.collection(), this.appNode); + XMLComment.prototype.toString = function(options) { + return this.options.writer.set(options).comment(this); + }; + + return XMLComment; + + })(XMLNode); + +}).call(this); + +},{"./XMLNode":76}],67:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLDTDAttList, XMLNode, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + XMLNode = _dereq_('./XMLNode'); + + module.exports = XMLDTDAttList = (function(superClass) { + extend(XMLDTDAttList, superClass); + + function XMLDTDAttList(parent, elementName, attributeName, attributeType, defaultValueType, defaultValue) { + XMLDTDAttList.__super__.constructor.call(this, parent); + if (elementName == null) { + throw new Error("Missing DTD element name"); + } + if (attributeName == null) { + throw new Error("Missing DTD attribute name"); + } + if (!attributeType) { + throw new Error("Missing DTD attribute type"); + } + if (!defaultValueType) { + throw new Error("Missing DTD attribute default"); + } + if (defaultValueType.indexOf('#') !== 0) { + defaultValueType = '#' + defaultValueType; + } + if (!defaultValueType.match(/^(#REQUIRED|#IMPLIED|#FIXED|#DEFAULT)$/)) { + throw new Error("Invalid default value type; expected: #REQUIRED, #IMPLIED, #FIXED or #DEFAULT"); + } + if (defaultValue && !defaultValueType.match(/^(#FIXED|#DEFAULT)$/)) { + throw new Error("Default value only applies to #FIXED or #DEFAULT"); + } + this.elementName = this.stringify.eleName(elementName); + this.attributeName = this.stringify.attName(attributeName); + this.attributeType = this.stringify.dtdAttType(attributeType); + this.defaultValue = this.stringify.dtdAttDefault(defaultValue); + this.defaultValueType = defaultValueType; } - var checkCredentialsRetry = function checkCredentialsRetry() { - if (!xhr.withCredentials) return false; // not dealt with + XMLDTDAttList.prototype.toString = function(options) { + return this.options.writer.set(options).dtdAttList(this); + }; - if (xhr.retriedWithCredentials) { - return true; + return XMLDTDAttList; + + })(XMLNode); + +}).call(this); + +},{"./XMLNode":76}],68:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLDTDElement, XMLNode, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + XMLNode = _dereq_('./XMLNode'); + + module.exports = XMLDTDElement = (function(superClass) { + extend(XMLDTDElement, superClass); + + function XMLDTDElement(parent, name, value) { + XMLDTDElement.__super__.constructor.call(this, parent); + if (name == null) { + throw new Error("Missing DTD element name"); } - xhr.retriedWithCredentials = true; // protect against called twice - console.log('web: Retrying with no credentials for ' + xhr.resource); - xhr.abort(); - delete sf.requested[docuri]; // forget the original request happened - var newopt = {}; - for (var opt in options) { - // transfer baseURI etc - if (options.hasOwnProperty(opt)) { - newopt[opt] = options[opt]; - } + if (!value) { + value = '(#PCDATA)'; } - newopt.withCredentials = false; - sf.addStatus(xhr.req, 'Abort: Will retry with credentials SUPPRESSED to see if that helps'); - sf.requestURI(docuri, rterm, newopt, xhr.userCallback); // userCallback already registered (with where?) - return true; + if (Array.isArray(value)) { + value = '(' + value.join(',') + ')'; + } + this.name = this.stringify.eleName(name); + this.value = this.stringify.dtdElementValue(value); + } + + XMLDTDElement.prototype.toString = function(options) { + return this.options.writer.set(options).dtdElement(this); }; - var onerrorFactory = function onerrorFactory(xhr) { - return function (event) { - xhr.onErrorWasCalled = true; // debugging and may need it - if (typeof document !== 'undefined') { - // Mashup situation, not node etc - if (Fetcher.crossSiteProxyTemplate && document.location && !xhr.proxyUsed) { - var hostpart = Uri.hostpart; - var here = '' + document.location; - var uri = xhr.resource.uri; - if (hostpart(here) && hostpart(uri) && hostpart(here) !== hostpart(uri)) { - // If cross-site - if (xhr.status === 401 || xhr.status === 403 || xhr.status === 404) { - onreadystatechangeFactory(xhr)(); - } else { - // IT IS A PAIN THAT NO PROPER ERROR REPORTING - if (checkCredentialsRetry(xhr)) { - // If credentials flag set, retry without, - return; - } - // If it wasn't, or we already tried that - var newURI = Fetcher.crossSiteProxy(uri); - console.log('web: Direct failed so trying proxy ' + newURI); - sf.addStatus(xhr.req, 'BLOCKED -> Cross-site Proxy to <' + newURI + '>'); - if (xhr.aborted) return; + return XMLDTDElement; - var kb = sf.store; - var oldreq = xhr.req; - if (!xhr.options.noMeta) { - kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), oldreq); - } - xhr.abort(); - xhr.aborted = true; + })(XMLNode); - sf.addStatus(oldreq, 'redirected to new request'); // why - // the callback throws an exception when called from xhr.onerror (so removed) - // sf.fireCallbacks('done', args) // Are these args right? @@@ Not done yet! done means success - sf.requested[xhr.resource.uri] = 'redirected'; - sf.redirectedTo[xhr.resource.uri] = newURI; +}).call(this); - if (sf.fetchCallbacks[xhr.resource.uri]) { - if (!sf.fetchCallbacks[newURI]) { - sf.fetchCallbacks[newURI] = []; - } - sf.fetchCallbacks[newURI] === sf.fetchCallbacks[newURI].concat(sf.fetchCallbacks[xhr.resource.uri]); - delete sf.fetchCallbacks[xhr.resource.uri]; - } +},{"./XMLNode":76}],69:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLDTDEntity, XMLNode, isObject, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; - var xhr2 = sf.requestURI(newURI, xhr.resource, xhr.options, xhr.userCallback); - if (xhr2) { - xhr2.proxyUsed = true; // only try the proxy once - xhr2.original = xhr.original; - console.log('Proxying but original still ' + xhr2.original); - } - if (xhr2 && xhr2.req) { - if (!xhr.options.noMeta) { - kb.add(xhr.req, kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), xhr2.req, sf.appNode); - } - return; - } - } - } - xhr.CORS_status = 999; - // xhr.status = 999 forbidden - read-only - } - } // mashu - }; // function of event - }; // onerrorFactory + isObject = _dereq_('./Utility').isObject; - // Set up callbacks - var onreadystatechangeFactory = function onreadystatechangeFactory(xhr) { - return function () { - var handleResponse = function handleResponse() { - if (xhr.handleResponseDone) return; - xhr.handleResponseDone = true; - var handler = null; - var thisReq = xhr.req; // Might have changes by redirect - sf.fireCallbacks('recv', args); - var kb = sf.store; - sf.saveResponseMetadata(xhr, kb); - sf.fireCallbacks('headers', [{ uri: docuri, headers: xhr.headers }]); + XMLNode = _dereq_('./XMLNode'); - // Check for masked errors. - // For "security reasons" theboraser hides errors such as CORS errors from - // the calling code (2015). oneror() used to be called but is not now. - // - if (xhr.status === 0) { - console.log('Masked error - status 0 for ' + xhr.resource.uri); - if (checkCredentialsRetry(xhr)) { - // retry is could be credentials flag CORS issue - return; - } - xhr.CORS_status = 900; // unknown masked error - return; - } - if (xhr.status >= 400) { - // For extra dignostics, keep the reply - // @@@ 401 should cause a retry with credential son - // @@@ cache the credentials flag by host ???? - if (xhr.status === 404) { - kb.fetcher.nonexistant[xhr.resource.uri] = true; - } - if (xhr.responseText.length > 10) { - var response2 = kb.bnode(); - kb.add(response2, ns.http('content'), kb.literal(xhr.responseText), response2); - if (xhr.statusText) { - kb.add(response2, ns.http('statusText'), kb.literal(xhr.statusText), response2); - } - // dump("HTTP >= 400 responseText:\n"+xhr.responseText+"\n"); // @@@@ - } - sf.failFetch(xhr, 'HTTP error for ' + xhr.resource + ': ' + xhr.status + ' ' + xhr.statusText); - return; - } + module.exports = XMLDTDEntity = (function(superClass) { + extend(XMLDTDEntity, superClass); - var loc = xhr.headers['content-location']; + function XMLDTDEntity(parent, pe, name, value) { + XMLDTDEntity.__super__.constructor.call(this, parent); + if (name == null) { + throw new Error("Missing entity name"); + } + if (value == null) { + throw new Error("Missing entity value"); + } + this.pe = !!pe; + this.name = this.stringify.eleName(name); + if (!isObject(value)) { + this.value = this.stringify.dtdEntityValue(value); + } else { + if (!value.pubID && !value.sysID) { + throw new Error("Public and/or system identifiers are required for an external entity"); + } + if (value.pubID && !value.sysID) { + throw new Error("System identifier is required for a public external entity"); + } + if (value.pubID != null) { + this.pubID = this.stringify.dtdPubID(value.pubID); + } + if (value.sysID != null) { + this.sysID = this.stringify.dtdSysID(value.sysID); + } + if (value.nData != null) { + this.nData = this.stringify.dtdNData(value.nData); + } + if (this.pe && this.nData) { + throw new Error("Notation declaration is not allowed in a parameter entity"); + } + } + } - // deduce some things from the HTTP transaction - var addType = function addType(cla) { - // add type to all redirected resources too - var prev = thisReq; - if (loc) { - var docURI = kb.any(prev, ns.link('requestedURI')); - if (docURI !== loc) { - kb.add(kb.sym(loc), ns.rdf('type'), cla, sf.appNode); - } - } - for (;;) { - var doc = kb.any(prev, ns.link('requestedURI')); - if (doc && doc.value) { - kb.add(kb.sym(doc.value), ns.rdf('type'), cla, sf.appNode); - } // convert Literal - prev = kb.any(undefined, kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), prev); - if (!prev) break; - var response = kb.any(prev, kb.sym('http://www.w3.org/2007/ont/link#response')); - if (!response) break; - var redirection = kb.any(response, kb.sym('http://www.w3.org/2007/ont/http#status')); - if (!redirection) break; - if (redirection !== '301' && redirection !== '302') break; - } - }; - // This is a minimal set to allow the use of damaged servers if necessary - var extensionToContentType = { - 'rdf': 'application/rdf+xml', 'owl': 'application/rdf+xml', - 'n3': 'text/n3', 'ttl': 'text/turtle', 'nt': 'text/n3', 'acl': 'text/n3', - 'html': 'text/html', - 'xml': 'text/xml' - }; - var guess; - if (xhr.status === 200) { - addType(ns.link('Document')); - var ct = xhr.headers['content-type']; - if (options.forceContentType) { - xhr.headers['content-type'] = options.forceContentType; - } - if (!ct || ct.indexOf('application/octet-stream') >= 0) { - guess = extensionToContentType[xhr.resource.uri.split('.').pop()]; - if (guess) { - xhr.headers['content-type'] = guess; - } - } - if (ct) { - if (ct.indexOf('image/') === 0 || ct.indexOf('application/pdf') === 0) addType(kb.sym('http://purl.org/dc/terms/Image')); - } - if (options.clearPreviousData) { - // Before we parse new data clear old but only on 200 - kb.removeDocument(xhr.resource); - } - } - // application/octet-stream; charset=utf-8 + XMLDTDEntity.prototype.toString = function(options) { + return this.options.writer.set(options).dtdEntity(this); + }; - if (Uri.protocol(xhr.resource.uri) === 'file' || Uri.protocol(xhr.resource.uri) === 'chrome') { - if (options.forceContentType) { - xhr.headers['content-type'] = options.forceContentType; - } else { - guess = extensionToContentType[xhr.resource.uri.split('.').pop()]; - if (guess) { - xhr.headers['content-type'] = guess; - } else { - xhr.headers['content-type'] = 'text/xml'; - } - } - } + return XMLDTDEntity; - // If we have alread got the thing at this location, abort - if (loc) { - var udoc = Uri.join(xhr.resource.uri, loc); - if (!force && udoc !== xhr.resource.uri && sf.requested[udoc] && sf.requested[udoc] === 'done') { - // we have already fetched this in fact. - // should we smush too? - // log.info("HTTP headers indicate we have already" + " retrieved " + xhr.resource + " as " + udoc + ". Aborting.") - sf.doneFetch(xhr); - xhr.abort(); - return; - } - sf.requested[udoc] = true; - } + })(XMLNode); - for (var x = 0; x < sf.handlers.length; x++) { - if (xhr.headers['content-type'] && xhr.headers['content-type'].match(sf.handlers[x].pattern)) { - handler = new sf.handlers[x](); - break; - } - } +}).call(this); - sf.parseLinkHeader(xhr, thisReq); +},{"./Utility":63,"./XMLNode":76}],70:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLDTDNotation, XMLNode, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; - if (handler) { - try { - handler.handlerFactory(xhr); - } catch (e) { - // Try to avoid silent errors - sf.failFetch(xhr, 'Exception handling content-type ' + xhr.headers['content-type'] + ' was: ' + e); - } - } else { - sf.doneFetch(xhr); // Not a problem, we just don't extract data. - /* - // sf.failFetch(xhr, "Unhandled content type: " + xhr.headers['content-type']+ - // ", readyState = "+xhr.readyState) - */ - return; - } - }; + XMLNode = _dereq_('./XMLNode'); - // DONE: 4 - // HEADERS_RECEIVED: 2 - // LOADING: 3 - // OPENED: 1 - // UNSENT: 0 + module.exports = XMLDTDNotation = (function(superClass) { + extend(XMLDTDNotation, superClass); - // log.debug("web.js: XHR " + xhr.resource.uri + ' readyState='+xhr.readyState); // @@@@ comment me out + function XMLDTDNotation(parent, name, value) { + XMLDTDNotation.__super__.constructor.call(this, parent); + if (name == null) { + throw new Error("Missing notation name"); + } + if (!value.pubID && !value.sysID) { + throw new Error("Public or system identifiers are required for an external entity"); + } + this.name = this.stringify.eleName(name); + if (value.pubID != null) { + this.pubID = this.stringify.dtdPubID(value.pubID); + } + if (value.sysID != null) { + this.sysID = this.stringify.dtdSysID(value.sysID); + } + } - switch (xhr.readyState) { - case 0: - var uri = xhr.resource.uri; - var newURI; - if (this.crossSiteProxyTemplate && typeof document !== 'undefined' && document.location) { - // In mashup situation - var hostpart = Uri.hostpart; - var here = '' + document.location; - if (hostpart(here) && hostpart(uri) && hostpart(here) !== hostpart(uri)) { - newURI = this.crossSiteProxyTemplate.replace('{uri}', encodeURIComponent(uri)); - sf.addStatus(xhr.req, 'BLOCKED -> Cross-site Proxy to <' + newURI + '>'); - if (xhr.aborted) return; + XMLDTDNotation.prototype.toString = function(options) { + return this.options.writer.set(options).dtdNotation(this); + }; - var kb = sf.store; - var oldreq = xhr.req; - kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), oldreq); + return XMLDTDNotation; - // //////////// Change the request node to a new one: @@@@@@@@@@@@ Duplicate? - var newreq = xhr.req = kb.bnode(); // Make NEW reqest for everything else - kb.add(oldreq, ns.http('redirectedRequest'), newreq, xhr.req); + })(XMLNode); - var now = new Date(); - var timeNow = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '] '; - kb.add(newreq, ns.rdfs('label'), kb.literal(timeNow + ' Request for ' + newURI), this.appNode); - kb.add(newreq, ns.link('status'), kb.collection(), this.appNode); - kb.add(newreq, ns.link('requestedURI'), kb.literal(newURI), this.appNode); +}).call(this); - var response = kb.bnode(); - kb.add(oldreq, ns.link('response'), response); - // kb.add(response, ns.http('status'), kb.literal(xhr.status), response) - // if (xhr.statusText) kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response) +},{"./XMLNode":76}],71:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLDeclaration, XMLNode, isObject, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; - xhr.abort(); - xhr.aborted = true; - xhr.redirected = true; + isObject = _dereq_('./Utility').isObject; - sf.addStatus(oldreq, 'redirected XHR'); // why + XMLNode = _dereq_('./XMLNode'); - if (sf.fetchCallbacks[xhr.resource.uri]) { - if (!sf.fetchCallbacks[newURI]) { - sf.fetchCallbacks[newURI] = []; - } - sf.fetchCallbacks[newURI] === sf.fetchCallbacks[newURI].concat(sf.fetchCallbacks[xhr.resource.uri]); - delete sf.fetchCallbacks[xhr.resource.uri]; - } + module.exports = XMLDeclaration = (function(superClass) { + extend(XMLDeclaration, superClass); - sf.fireCallbacks('redirected', args); // Are these args right? @@@ - sf.requested[xhr.resource.uri] = 'redirected'; + function XMLDeclaration(parent, version, encoding, standalone) { + var ref; + XMLDeclaration.__super__.constructor.call(this, parent); + if (isObject(version)) { + ref = version, version = ref.version, encoding = ref.encoding, standalone = ref.standalone; + } + if (!version) { + version = '1.0'; + } + this.version = this.stringify.xmlVersion(version); + if (encoding != null) { + this.encoding = this.stringify.xmlEncoding(encoding); + } + if (standalone != null) { + this.standalone = this.stringify.xmlStandalone(standalone); + } + } - var xhr2 = sf.requestURI(newURI, xhr.resource, xhr.options || {}, xhr.userCallback); - if (xhr2 && xhr2.req) { - kb.add(xhr.req, kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), xhr2.req, sf.appNode); - return; - } - } - } - sf.failFetch(xhr, 'HTTP Blocked. (ReadyState 0) Cross-site violation for <' + docuri + '>'); + XMLDeclaration.prototype.toString = function(options) { + return this.options.writer.set(options).declaration(this); + }; - break; + return XMLDeclaration; - case 3: - // Intermediate state -- 3 may OR MAY NOT be called, selon browser. - // handleResponse(); // In general it you can't do it yet as the headers are in but not the data - break; - case 4: - // Final state for this XHR but may be redirected - handleResponse(); - // Now handle - if (xhr.handle && xhr.responseText !== undefined) { - // can be validly zero length - if (sf.requested[xhr.resource.uri] === 'redirected') { - break; - } - sf.fireCallbacks('load', args); - xhr.handle(function () { - sf.doneFetch(xhr); - }); - } else { - if (xhr.redirected) { - sf.addStatus(xhr.req, 'Aborted and redirected to new request.'); - } else { - sf.addStatus(xhr.req, 'Fetch over. No data handled. Aborted = ' + xhr.aborted); - } - // sf.failFetch(xhr, "HTTP failed unusually. (no handler set) (x-site violation? no net?) for <"+ - // docuri+">") - } - break; - } // switch - }; - }; + })(XMLNode); - // Map the URI to a localhost proxy if we are running on localhost - // This is used for working offline, e.g. on planes. - // Is the script istelf is running in localhost, then access all data in a localhost mirror. - // Do not remove without checking with TimBL - var uri2 = docuri; - if (typeof tabulator !== 'undefined' && tabulator.preferences.get('offlineModeUsingLocalhost')) { - if (uri2.slice(0, 7) === 'http://' && uri2.slice(7, 17) !== 'localhost/') { - uri2 = 'http://localhost/' + uri2.slice(7); - log.warn('Localhost kludge for offline use: actually getting <' + uri2 + '>'); - } else { - // log.warn("Localhost kludge NOT USED <" + uri2 + ">") - } - } else {} - // log.warn("Localhost kludge OFF offline use: actually getting <" + uri2 + ">") +}).call(this); - // 2014 probelm: - // XMLHttpRequest cannot load http://www.w3.org/People/Berners-Lee/card. - // A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. - // @ Many ontology files under http: and need CORS wildcard -> can't have withCredentials +},{"./Utility":63,"./XMLNode":76}],72:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLDTDAttList, XMLDTDElement, XMLDTDEntity, XMLDTDNotation, XMLDocType, XMLNode, isObject, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; - var withCredentials = uri2.slice(0, 6) === 'https:'; // @@ Kludge -- need for webid which typically is served from https - if (options.withCredentials !== undefined) { - withCredentials = options.withCredentials; - } - var actualProxyURI = this.proxyIfNecessary(uri2); + isObject = _dereq_('./Utility').isObject; - // Setup the request - // var xhr - // xhr = Util.XMLHTTPFactory() - xhr.onerror = onerrorFactory(xhr); - xhr.onreadystatechange = onreadystatechangeFactory(xhr); - xhr.timeout = sf.timeout; - xhr.withCredentials = withCredentials; - xhr.actualProxyURI = actualProxyURI; + XMLNode = _dereq_('./XMLNode'); - xhr.req = req; - xhr.options = options; - xhr.options = options; - xhr.resource = docterm; - xhr.requestedURI = uri2; + XMLDTDAttList = _dereq_('./XMLDTDAttList'); - xhr.ontimeout = function () { - sf.failFetch(xhr, 'requestTimeout'); - }; - try { - xhr.open('GET', actualProxyURI, this.async); - } catch (er) { - return this.failFetch(xhr, 'XHR open for GET failed for <' + uri2 + '>:\n\t' + er); - } - if (force) { - // must happen after open - xhr.setRequestHeader('Cache-control', 'no-cache'); - } + XMLDTDEntity = _dereq_('./XMLDTDEntity'); - // Set redirect callback and request headers -- alas Firefox Extension Only - if (typeof tabulator !== 'undefined' && tabulator.isExtension && xhr.channel && (Uri.protocol(xhr.resource.uri) === 'http' || Uri.protocol(xhr.resource.uri) === 'https')) { - try { - xhr.channel.notificationCallbacks = { - getInterface: function getInterface(iid) { - if (iid.equals(Components.interfaces.nsIChannelEventSink)) { - return { - onChannelRedirect: function onChannelRedirect(oldC, newC, flags) { - if (xhr.aborted) return; - var kb = sf.store; - var newURI = newC.URI.spec; - var oldreq = xhr.req; - if (!xhr.options.noMeta) { - sf.addStatus(xhr.req, 'Redirected: ' + xhr.status + ' to <' + newURI + '>'); - kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), xhr.req); + XMLDTDElement = _dereq_('./XMLDTDElement'); - // //////////// Change the request node to a new one: @@@@@@@@@@@@ Duplicate code? - var newreq = xhr.req = kb.bnode(); // Make NEW reqest for everything else - kb.add(oldreq, ns.http('redirectedRequest'), newreq, this.appNode); + XMLDTDNotation = _dereq_('./XMLDTDNotation'); - var now = new Date(); - var timeNow = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '] '; - kb.add(newreq, ns.rdfs('label'), kb.literal(timeNow + ' Request for ' + newURI), this.appNode); - kb.add(newreq, ns.link('status'), kb.collection(), this.appNode); - kb.add(newreq, ns.link('requestedURI'), kb.literal(newURI), this.appNode); - // ///////////// + module.exports = XMLDocType = (function(superClass) { + extend(XMLDocType, superClass); - // // log.info('@@ sources onChannelRedirect'+ - // "Redirected: "+ - // xhr.status + " to <" + newURI + ">"); //@@ - var response = kb.bnode(); - // kb.add(response, ns.http('location'), newURI, response); Not on this response - kb.add(oldreq, ns.link('response'), response); - kb.add(response, ns.http('status'), kb.literal(xhr.status), response); - if (xhr.statusText) kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response); - } - if (xhr.status - 0 !== 303) kb.HTTPRedirects[xhr.resource.uri] = newURI; // same document as - if (xhr.status - 0 === 301 && rterm) { - // 301 Moved - var badDoc = Uri.docpart(rterm.uri); - var msg = 'Warning: ' + xhr.resource + ' has moved to <' + newURI + '>.'; - if (rterm) { - msg += ' Link in <' + badDoc + ' >should be changed'; - kb.add(badDoc, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg, sf.appNode); - } - // dump(msg+"\n") - } - xhr.abort(); - xhr.aborted = true; + function XMLDocType(parent, pubID, sysID) { + var ref, ref1; + XMLDocType.__super__.constructor.call(this, parent); + this.documentObject = parent; + if (isObject(pubID)) { + ref = pubID, pubID = ref.pubID, sysID = ref.sysID; + } + if (sysID == null) { + ref1 = [pubID, sysID], sysID = ref1[0], pubID = ref1[1]; + } + if (pubID != null) { + this.pubID = this.stringify.dtdPubID(pubID); + } + if (sysID != null) { + this.sysID = this.stringify.dtdSysID(sysID); + } + } - if (sf.fetchCallbacks[xhr.resource.uri]) { - if (!sf.fetchCallbacks[newURI]) { - sf.fetchCallbacks[newURI] = []; - } - sf.fetchCallbacks[newURI] === sf.fetchCallbacks[newURI].concat(sf.fetchCallbacks[xhr.resource.uri]); - delete sf.fetchCallbacks[xhr.resource.uri]; - } + XMLDocType.prototype.element = function(name, value) { + var child; + child = new XMLDTDElement(this, name, value); + this.children.push(child); + return this; + }; - sf.addStatus(oldreq, 'redirected'); // why - sf.fireCallbacks('redirected', args); // Are these args right? @@@ - sf.requested[xhr.resource.uri] = 'redirected'; - sf.redirectedTo[xhr.resource.uri] = newURI; + XMLDocType.prototype.attList = function(elementName, attributeName, attributeType, defaultValueType, defaultValue) { + var child; + child = new XMLDTDAttList(this, elementName, attributeName, attributeType, defaultValueType, defaultValue); + this.children.push(child); + return this; + }; - var hash = newURI.indexOf('#'); - if (hash >= 0) { - if (!xhr.options.noMeta) { - kb.add(xhr.resource, kb.sym('http://www.w3.org/2007/ont/link#warning'), 'Warning: ' + xhr.resource + ' HTTP redirects to' + newURI + ' which should not contain a "#" sign'); - } - newURI = newURI.slice(0, hash); - } - var xhr2 = sf.requestURI(newURI, xhr.resource, xhr.options, xhr.userCallback); - if (xhr2 && xhr2.req && !options.noMeta) { - kb.add(xhr.req, kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), xhr2.req, sf.appNode); - } - // else dump("No xhr.req available for redirect from "+xhr.resource+" to "+newURI+"\n") - }, + XMLDocType.prototype.entity = function(name, value) { + var child; + child = new XMLDTDEntity(this, false, name, value); + this.children.push(child); + return this; + }; - // See https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIChannelEventSink - asyncOnChannelRedirect: function asyncOnChannelRedirect(oldC, newC, flags, callback) { - if (xhr.aborted) return; - var kb = sf.store; - var newURI = newC.URI.spec; - var oldreq = xhr.req; - sf.addStatus(xhr.req, 'Redirected: ' + xhr.status + ' to <' + newURI + '>'); - kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), xhr.req); + XMLDocType.prototype.pEntity = function(name, value) { + var child; + child = new XMLDTDEntity(this, true, name, value); + this.children.push(child); + return this; + }; - // //////////// Change the request node to a new one: @@@@@@@@@@@@ Duplicate? - var newreq = xhr.req = kb.bnode(); // Make NEW reqest for everything else - // xhr.resource = docterm - // xhr.requestedURI = args[0] + XMLDocType.prototype.notation = function(name, value) { + var child; + child = new XMLDTDNotation(this, name, value); + this.children.push(child); + return this; + }; - // kb.add(kb.sym(newURI), ns.link("request"), req, this.appNode) - kb.add(oldreq, ns.http('redirectedRequest'), newreq, xhr.req); + XMLDocType.prototype.toString = function(options) { + return this.options.writer.set(options).docType(this); + }; - var now = new Date(); - var timeNow = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '] '; - kb.add(newreq, ns.rdfs('label'), kb.literal(timeNow + ' Request for ' + newURI), this.appNode); - kb.add(newreq, ns.link('status'), kb.collection(), this.appNode); - kb.add(newreq, ns.link('requestedURI'), kb.literal(newURI), this.appNode); - // ///////////// + XMLDocType.prototype.ele = function(name, value) { + return this.element(name, value); + }; - // // log.info('@@ sources onChannelRedirect'+ - // "Redirected: "+ - // xhr.status + " to <" + newURI + ">"); //@@ - var response = kb.bnode(); - // kb.add(response, ns.http('location'), newURI, response); Not on this response - kb.add(oldreq, ns.link('response'), response); - kb.add(response, ns.http('status'), kb.literal(xhr.status), response); - if (xhr.statusText) kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response); + XMLDocType.prototype.att = function(elementName, attributeName, attributeType, defaultValueType, defaultValue) { + return this.attList(elementName, attributeName, attributeType, defaultValueType, defaultValue); + }; - if (xhr.status - 0 !== 303) kb.HTTPRedirects[xhr.resource.uri] = newURI; // same document as - if (xhr.status - 0 === 301 && rterm) { - // 301 Moved - var badDoc = Uri.docpart(rterm.uri); - var msg = 'Warning: ' + xhr.resource + ' has moved to <' + newURI + '>.'; - if (rterm) { - msg += ' Link in <' + badDoc + ' >should be changed'; - kb.add(badDoc, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg, sf.appNode); - } - // dump(msg+"\n") - } - xhr.abort(); - xhr.aborted = true; + XMLDocType.prototype.ent = function(name, value) { + return this.entity(name, value); + }; - var hash = newURI.indexOf('#'); - if (hash >= 0) { - var msg2 = 'Warning: ' + xhr.resource + ' HTTP redirects to' + newURI + ' which do not normally contain a "#" sign'; - // dump(msg+"\n") - kb.add(xhr.resource, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg2); - newURI = newURI.slice(0, hash); - } - /* - if (sf.fetchCallbacks[xhr.resource.uri]) { - if (!sf.fetchCallbacks[newURI]) { - sf.fetchCallbacks[newURI] = [] - } - sf.fetchCallbacks[newURI] = sf.fetchCallbacks[newURI].concat(sf.fetchCallbacks[xhr.resource.uri]) - delete sf.fetchCallbacks[xhr.resource.uri] - } - */ - sf.requested[xhr.resource.uri] = 'redirected'; - sf.redirectedTo[xhr.resource.uri] = newURI; + XMLDocType.prototype.pent = function(name, value) { + return this.pEntity(name, value); + }; - var xhr2 = sf.requestURI(newURI, xhr.resource, xhr.options, xhr.userCallback); - if (xhr2) { - // may be no XHR is other URI already loaded - xhr2.original = xhr.original; // use this for finding base - if (xhr2.req) { - kb.add(xhr.req, kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), xhr2.req, sf.appNode); - } - } - // else dump("No xhr.req available for redirect from "+xhr.resource+" to "+newURI+"\n") - } // asyncOnChannelRedirect - }; - } - return Components.results.NS_NOINTERFACE; - } - }; - } catch (err) { - return sf.failFetch(xhr, "@@ Couldn't set callback for redirects: " + err); - } // try - } // if Firefox extension + XMLDocType.prototype.not = function(name, value) { + return this.notation(name, value); + }; - try { - var acceptstring = ''; - for (var type in this.mediatypes) { - // var attrstring = '' - if (acceptstring !== '') { - acceptstring += ', '; - } - acceptstring += type; - for (var attr in this.mediatypes[type]) { - acceptstring += ';' + attr + '=' + this.mediatypes[type][attr]; - } - } - xhr.setRequestHeader('Accept', acceptstring); - this.addStatus(xhr.req, 'Accept: ' + acceptstring); + XMLDocType.prototype.up = function() { + return this.root() || this.documentObject; + }; - // if (requester) { xhr.setRequestHeader('Referer',requester) } - } catch (err) { - throw new Error("Can't set Accept header: " + err); - } + return XMLDocType; - // Fire - try { - xhr.send(null); - } catch (er) { - return this.failFetch(xhr, 'XHR send failed:' + er); - } - setTimeout(function () { - if (xhr.readyState !== 4 && sf.isPending(xhr.resource.uri)) { - sf.failFetch(xhr, 'requestTimeout'); - } - }, this.timeout); - this.addStatus(xhr.req, 'HTTP Request sent.'); - return xhr; - }; // this.requestURI() + })(XMLNode); - this.objectRefresh = function (term) { - var uris = kb.uris(term); // Get all URIs - if (typeof uris !== 'undefined') { - for (var i = 0; i < uris.length; i++) { - this.refresh(this.store.sym(Uri.docpart(uris[i]))); - // what about rterm? +}).call(this); + +},{"./Utility":63,"./XMLDTDAttList":67,"./XMLDTDElement":68,"./XMLDTDEntity":69,"./XMLDTDNotation":70,"./XMLNode":76}],73:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLDocument, XMLNode, XMLStringWriter, XMLStringifier, isPlainObject, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + isPlainObject = _dereq_('./Utility').isPlainObject; + + XMLNode = _dereq_('./XMLNode'); + + XMLStringifier = _dereq_('./XMLStringifier'); + + XMLStringWriter = _dereq_('./XMLStringWriter'); + + module.exports = XMLDocument = (function(superClass) { + extend(XMLDocument, superClass); + + function XMLDocument(options) { + XMLDocument.__super__.constructor.call(this, null); + options || (options = {}); + if (!options.writer) { + options.writer = new XMLStringWriter(); } + this.options = options; + this.stringify = new XMLStringifier(options); + this.isDocument = true; } - }; - // deprecated -- use IndexedFormula.removeDocument(doc) - this.unload = function (term) { - this.store.removeMany(undefined, undefined, undefined, term); - delete this.requested[term.uri]; // So it can be loaded again - }; + XMLDocument.prototype.end = function(writer) { + var writerOptions; + if (!writer) { + writer = this.options.writer; + } else if (isPlainObject(writer)) { + writerOptions = writer; + writer = this.options.writer.set(writerOptions); + } + return writer.document(this); + }; - this.refresh = function (term, userCallback) { - // sources_refresh - this.fireCallbacks('refresh', arguments); - this.requestURI(term.uri, undefined, { force: true, clearPreviousData: true }, userCallback); - }; + XMLDocument.prototype.toString = function(options) { + return this.options.writer.set(options).document(this); + }; - this.retract = function (term) { - // sources_retract - this.store.removeMany(undefined, undefined, undefined, term); - if (term.uri) { - delete this.requested[Uri.docpart(term.uri)]; - } - this.fireCallbacks('retract', arguments); - }; + return XMLDocument; - this.getState = function (docuri) { - if (typeof this.requested[docuri] === 'undefined') { - return 'unrequested'; - } else if (this.requested[docuri] === true) { - return 'requested'; - } else if (this.requested[docuri] === 'done') { - return 'fetched'; - } else if (this.requested[docuri] === 'redirected') { - return this.getState(this.redirectedTo[docuri]); - } else { - // An non-200 HTTP error status - return 'failed'; - } - }; + })(XMLNode); - // doing anyStatementMatching is wasting time - this.isPending = function (docuri) { - // sources_pending - // if it's not pending: false -> flailed 'done' -> done 'redirected' -> redirected - return this.requested[docuri] === true; - }; - // var updatesVia = new $rdf.UpdatesVia(this) // Subscribe to headers - // @@@@@@@@ This is turned off because it causes a websocket to be set up for ANY fetch - // whether we want to track it ot not. including ontologies loaed though the XSSproxy -}; // End of fetcher +}).call(this); -module.exports = Fetcher; -},{"./log":55,"./n3parser":56,"./named-node":57,"./namespace":58,"./parse":60,"./rdfaparser":64,"./rdfxmlparser":65,"./serialize":66,"./uri":72,"./util":73}],50:[function(_dereq_,module,exports){ -'use strict'; +},{"./Utility":63,"./XMLNode":76,"./XMLStringWriter":80,"./XMLStringifier":81}],74:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLAttribute, XMLCData, XMLComment, XMLDTDAttList, XMLDTDElement, XMLDTDEntity, XMLDTDNotation, XMLDeclaration, XMLDocType, XMLDocumentCB, XMLElement, XMLProcessingInstruction, XMLRaw, XMLStringWriter, XMLStringifier, XMLText, isFunction, isObject, isPlainObject, ref, + hasProp = {}.hasOwnProperty; -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + ref = _dereq_('./Utility'), isObject = ref.isObject, isFunction = ref.isFunction, isPlainObject = ref.isPlainObject; -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + XMLElement = _dereq_('./XMLElement'); -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + XMLCData = _dereq_('./XMLCData'); -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + XMLComment = _dereq_('./XMLComment'); -var BlankNode = _dereq_('./blank-node'); -var ClassOrder = _dereq_('./class-order'); -var Collection = _dereq_('./collection'); -var Literal = _dereq_('./literal'); -var log = _dereq_('./log'); -var NamedNode = _dereq_('./named-node'); -var Node = _dereq_('./node'); -var Serializer = _dereq_('./serialize'); -var Statement = _dereq_('./statement'); -var Variable = _dereq_('./variable'); + XMLRaw = _dereq_('./XMLRaw'); -var Formula = function (_Node) { - _inherits(Formula, _Node); + XMLText = _dereq_('./XMLText'); - function Formula(statements, constraints, initBindings, optional) { - _classCallCheck(this, Formula); + XMLProcessingInstruction = _dereq_('./XMLProcessingInstruction'); - var _this = _possibleConstructorReturn(this, (Formula.__proto__ || Object.getPrototypeOf(Formula)).call(this)); + XMLDeclaration = _dereq_('./XMLDeclaration'); - _this.termType = Formula.termType; - _this.statements = statements || []; - _this.constraints = constraints || []; - _this.initBindings = initBindings || []; - _this.optional = optional || []; - return _this; - } + XMLDocType = _dereq_('./XMLDocType'); - _createClass(Formula, [{ - key: 'add', - value: function add(s, p, o, g) { - return this.statements.push(new Statement(s, p, o, g)); - } - }, { - key: 'addStatement', - value: function addStatement(st) { - return this.statements.push(st); - } - }, { - key: 'bnode', - value: function bnode(id) { - return new BlankNode(id); - } - /** - * Finds the types in the list which have no *stored* subtypes - * These are a set of classes which provide by themselves complete - * information -- the other classes are redundant for those who - * know the class DAG. - */ + XMLDTDAttList = _dereq_('./XMLDTDAttList'); - }, { - key: 'bottomTypeURIs', - value: function bottomTypeURIs(types) { - var bots; - var bottom; - var elt; - var i; - var k; - var len; - var ref; - var subs; - var v; - bots = []; - for (k in types) { - if (!types.hasOwnProperty(k)) continue; - v = types[k]; - subs = this.each(void 0, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), this.sym(k)); - bottom = true; - i = 0; - for (len = subs.length; i < len; i++) { - elt = subs[i]; - ref = elt.uri; - if (ref in types) { - // the subclass is one we know - bottom = false; - break; - } - } - if (bottom) { - bots[k] = v; - } + XMLDTDEntity = _dereq_('./XMLDTDEntity'); + + XMLDTDElement = _dereq_('./XMLDTDElement'); + + XMLDTDNotation = _dereq_('./XMLDTDNotation'); + + XMLAttribute = _dereq_('./XMLAttribute'); + + XMLStringifier = _dereq_('./XMLStringifier'); + + XMLStringWriter = _dereq_('./XMLStringWriter'); + + module.exports = XMLDocumentCB = (function() { + function XMLDocumentCB(options, onData, onEnd) { + var writerOptions; + options || (options = {}); + if (!options.writer) { + options.writer = new XMLStringWriter(options); + } else if (isPlainObject(options.writer)) { + writerOptions = options.writer; + options.writer = new XMLStringWriter(writerOptions); } - return bots; - } - }, { - key: 'collection', - value: function collection() { - return new Collection(); + this.options = options; + this.writer = options.writer; + this.stringify = new XMLStringifier(options); + this.onDataCallback = onData || function() {}; + this.onEndCallback = onEnd || function() {}; + this.currentNode = null; + this.currentLevel = -1; + this.openTags = {}; + this.documentStarted = false; + this.documentCompleted = false; + this.root = null; } - }, { - key: 'each', - value: function each(s, p, o, g) { - var elt, i, l, m, q; - var len, len1, len2, len3; - var results = []; - var sts = this.statementsMatching(s, p, o, g, false); - if (s == null) { - for (i = 0, len = sts.length; i < len; i++) { - elt = sts[i]; - results.push(elt.subject); - } - } else if (p == null) { - for (l = 0, len1 = sts.length; l < len1; l++) { - elt = sts[l]; - results.push(elt.predicate); - } - } else if (o == null) { - for (m = 0, len2 = sts.length; m < len2; m++) { - elt = sts[m]; - results.push(elt.object); - } - } else if (g == null) { - for (q = 0, len3 = sts.length; q < len3; q++) { - elt = sts[q]; - results.push(elt.why); - } + + XMLDocumentCB.prototype.node = function(name, attributes, text) { + var ref1; + if (name == null) { + throw new Error("Missing node name"); } - return results; - } - }, { - key: 'equals', - value: function equals(other) { - if (!other) { - return false; + if (this.root && this.currentLevel === -1) { + throw new Error("Document can only have one root node"); } - return this.hashString() === other.hashString(); - } - /* - For thisClass or any subclass, anything which has it is its type - or is the object of something which has the type as its range, or subject - of something which has the type as its domain - We don't bother doing subproperty (yet?)as it doesn't seeem to be used much. - Get all the Classes of which we can RDFS-infer the subject is a member - @returns a hash of URIs - */ + this.openCurrent(); + name = name.valueOf(); + if (attributes == null) { + attributes = {}; + } + attributes = attributes.valueOf(); + if (!isObject(attributes)) { + ref1 = [attributes, text], text = ref1[0], attributes = ref1[1]; + } + this.currentNode = new XMLElement(this, name, attributes); + this.currentNode.children = false; + this.currentLevel++; + this.openTags[this.currentLevel] = this.currentNode; + if (text != null) { + this.text(text); + } + return this; + }; - /** - * For thisClass or any subclass, anything which has it is its type - * or is the object of something which has the type as its range, or subject - * of something which has the type as its domain - * We don't bother doing subproperty (yet?)as it doesn't seeem to be used - * much. - * Get all the Classes of which we can RDFS-infer the subject is a member - * @return a hash of URIs - */ + XMLDocumentCB.prototype.element = function(name, attributes, text) { + if (this.currentNode && this.currentNode instanceof XMLDocType) { + return this.dtdElement.apply(this, arguments); + } else { + return this.node(name, attributes, text); + } + }; - }, { - key: 'findMembersNT', - value: function findMembersNT(thisClass) { - var i; - var l; - var len; - var len1; - var len2; - var len3; - var len4; - var m; - var members; - var pred; - var q; - var ref; - var ref1; - var ref2; - var ref3; - var ref4; - var ref5; - var seeds; - var st; - var t; - var u; - seeds = {}; - seeds[thisClass.toNT()] = true; - members = {}; - ref = this.transitiveClosure(seeds, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), true); - for (t in ref) { - if (!ref.hasOwnProperty(t)) continue; - ref1 = this.statementsMatching(void 0, this.sym('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), this.fromNT(t)); - for (i = 0, len = ref1.length; i < len; i++) { - st = ref1[i]; - members[st.subject.toNT()] = st; + XMLDocumentCB.prototype.attribute = function(name, value) { + var attName, attValue; + if (!this.currentNode || this.currentNode.children) { + throw new Error("att() can only be used immediately after an ele() call in callback mode"); + } + if (name != null) { + name = name.valueOf(); + } + if (isObject(name)) { + for (attName in name) { + if (!hasProp.call(name, attName)) continue; + attValue = name[attName]; + this.attribute(attName, attValue); } - ref2 = this.each(void 0, this.sym('http://www.w3.org/2000/01/rdf-schema#domain'), this.fromNT(t)); - for (l = 0, len1 = ref2.length; l < len1; l++) { - pred = ref2[l]; - ref3 = this.statementsMatching(void 0, pred); - for (m = 0, len2 = ref3.length; m < len2; m++) { - st = ref3[m]; - members[st.subject.toNT()] = st; - } + } else { + if (isFunction(value)) { + value = value.apply(); } - ref4 = this.each(void 0, this.sym('http://www.w3.org/2000/01/rdf-schema#range'), this.fromNT(t)); - for (q = 0, len3 = ref4.length; q < len3; q++) { - pred = ref4[q]; - ref5 = this.statementsMatching(void 0, pred); - for (u = 0, len4 = ref5.length; u < len4; u++) { - st = ref5[u]; - members[st.object.toNT()] = st; - } + if (!this.options.skipNullAttributes || (value != null)) { + this.currentNode.attributes[name] = new XMLAttribute(this, name, value); } } - return members; - } - }, { - key: 'findMemberURIs', - value: function findMemberURIs(subject) { - return this.NTtoURI(this.findMembersNT(subject)); - } - /** - * Get all the Classes of which we can RDFS-infer the subject is a superclass - * Returns a hash table where key is NT of type and value is statement why we - * think so. - * Does NOT return terms, returns URI strings. - * We use NT representations in this version because they handle blank nodes. - */ + return this; + }; - }, { - key: 'findSubClassesNT', - value: function findSubClassesNT(subject) { - var types = {}; - types[subject.toNT()] = true; - return this.transitiveClosure(types, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), true); - } - /** - * Get all the Classes of which we can RDFS-infer the subject is a subclass - * Returns a hash table where key is NT of type and value is statement why we - * think so. - * Does NOT return terms, returns URI strings. - * We use NT representations in this version because they handle blank nodes. - */ + XMLDocumentCB.prototype.text = function(value) { + var node; + this.openCurrent(); + node = new XMLText(this, value); + this.onData(this.writer.text(node, this.currentLevel + 1)); + return this; + }; - }, { - key: 'findSuperClassesNT', - value: function findSuperClassesNT(subject) { - var types = {}; - types[subject.toNT()] = true; - return this.transitiveClosure(types, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), false); - } - /** - * Get all the Classes of which we can RDFS-infer the subject is a member - * todo: This will loop is there is a class subclass loop (Sublass loops are - * not illegal) - * Returns a hash table where key is NT of type and value is statement why we - * think so. - * Does NOT return terms, returns URI strings. - * We use NT representations in this version because they handle blank nodes. - */ + XMLDocumentCB.prototype.cdata = function(value) { + var node; + this.openCurrent(); + node = new XMLCData(this, value); + this.onData(this.writer.cdata(node, this.currentLevel + 1)); + return this; + }; - }, { - key: 'findTypesNT', - value: function findTypesNT(subject) { - var domain; - var i; - var l; - var len; - var len1; - var len2; - var len3; - var m; - var q; - var range; - var rdftype; - var ref; - var ref1; - var ref2; - var ref3; - var st; - var types; - rdftype = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; - types = []; - ref = this.statementsMatching(subject, void 0, void 0); - for (i = 0, len = ref.length; i < len; i++) { - st = ref[i]; - if (st.predicate.uri === rdftype) { - types[st.object.toNT()] = st; - } else { - ref1 = this.each(st.predicate, this.sym('http://www.w3.org/2000/01/rdf-schema#domain')); - for (l = 0, len1 = ref1.length; l < len1; l++) { - range = ref1[l]; - types[range.toNT()] = st; - } - } + XMLDocumentCB.prototype.comment = function(value) { + var node; + this.openCurrent(); + node = new XMLComment(this, value); + this.onData(this.writer.comment(node, this.currentLevel + 1)); + return this; + }; + + XMLDocumentCB.prototype.raw = function(value) { + var node; + this.openCurrent(); + node = new XMLRaw(this, value); + this.onData(this.writer.raw(node, this.currentLevel + 1)); + return this; + }; + + XMLDocumentCB.prototype.instruction = function(target, value) { + var i, insTarget, insValue, len, node; + this.openCurrent(); + if (target != null) { + target = target.valueOf(); } - ref2 = this.statementsMatching(void 0, void 0, subject); - for (m = 0, len2 = ref2.length; m < len2; m++) { - st = ref2[m]; - ref3 = this.each(st.predicate, this.sym('http://www.w3.org/2000/01/rdf-schema#range')); - for (q = 0, len3 = ref3.length; q < len3; q++) { - domain = ref3[q]; - types[domain.toNT()] = st; + if (value != null) { + value = value.valueOf(); + } + if (Array.isArray(target)) { + for (i = 0, len = target.length; i < len; i++) { + insTarget = target[i]; + this.instruction(insTarget); + } + } else if (isObject(target)) { + for (insTarget in target) { + if (!hasProp.call(target, insTarget)) continue; + insValue = target[insTarget]; + this.instruction(insTarget, insValue); + } + } else { + if (isFunction(value)) { + value = value.apply(); } + node = new XMLProcessingInstruction(this, target, value); + this.onData(this.writer.processingInstruction(node, this.currentLevel + 1)); } - return this.transitiveClosure(types, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), false); - } - }, { - key: 'findTypeURIs', - value: function findTypeURIs(subject) { - return this.NTtoURI(this.findTypesNT(subject)); - } - // Trace the statements which connect directly, or through bnodes - // Returns an array of statements - // doc param may be null to search all documents in store + return this; + }; - }, { - key: 'connectedStatements', - value: function connectedStatements(subject, doc, excludePredicateURIs) { - excludePredicateURIs = excludePredicateURIs || []; - var todo = [subject]; - var done = []; - var doneArcs = []; - var result = []; - var self = this; - var follow = function follow(x) { - var queue = function queue(x) { - if (x.termType === 'BlankNode' && !done[x.value]) { - done[x.value] = true; - todo.push(x); - } - }; - var sts = self.statementsMatching(null, null, x, doc).concat(self.statementsMatching(x, null, null, doc)); - sts = sts.filter(function (st) { - if (excludePredicateURIs[st.predicate.uri]) return false; - var hash = st.toNT(); - if (doneArcs[hash]) return false; - doneArcs[hash] = true; - return true; - }); - sts.forEach(function (st, i) { - queue(st.subject); - queue(st.object); - }); - result = result.concat(sts); - }; - while (todo.length) { - follow(todo.shift()); + XMLDocumentCB.prototype.declaration = function(version, encoding, standalone) { + var node; + this.openCurrent(); + if (this.documentStarted) { + throw new Error("declaration() must be the first node"); } - // console.log('' + result.length + ' statements about ' + subject) - return result; - } - }, { - key: 'formula', - value: function formula() { - return new Formula(); - } - /** - * Transforms an NTriples string format into a Node. - * The bnode bit should not be used on program-external values; designed - * for internal work such as storing a bnode id in an HTML attribute. - * This will only parse the strings generated by the vaious toNT() methods. - */ + node = new XMLDeclaration(this, version, encoding, standalone); + this.onData(this.writer.declaration(node, this.currentLevel + 1)); + return this; + }; - }, { - key: 'fromNT', - value: function fromNT(str) { - var dt, k, lang, x; - switch (str[0]) { - case '<': - return this.sym(str.slice(1, -1)); - case '"': - lang = void 0; - dt = void 0; - k = str.lastIndexOf('"'); - if (k < str.length - 1) { - if (str[k + 1] === '@') { - lang = str.slice(k + 2); - } else if (str.slice(k + 1, k + 3) === '^^') { - dt = this.fromNT(str.slice(k + 3)); - } else { - throw new Error("Can't convert string from NT: " + str); - } - } - str = str.slice(1, k); - str = str.replace(/\\"/g, '"'); - str = str.replace(/\\n/g, '\n'); - str = str.replace(/\\\\/g, '\\'); - return this.literal(str, lang, dt); - case '_': - x = new BlankNode(); - x.id = parseInt(str.slice(3), 10); - BlankNode.nextId--; - return x; - case '?': - return new Variable(str.slice(1)); + XMLDocumentCB.prototype.doctype = function(root, pubID, sysID) { + this.openCurrent(); + if (root == null) { + throw new Error("Missing root node name"); } - throw new Error("Can't convert from NT: " + str); - } - }, { - key: 'holds', - value: function holds(s, p, o, g) { - var i; - if (arguments.length === 1) { - if (!s) { - return true; - } - if (s instanceof Array) { - for (i = 0; i < s.length; i++) { - if (!this.holds(s[i])) { - return false; - } - } - return true; - } else if (s instanceof Statement) { - return this.holds(s.subject, s.predicate, s.object, s.why); - } else if (s.statements) { - return this.holds(s.statements); - } + if (this.root) { + throw new Error("dtd() must come before the root node"); } + this.currentNode = new XMLDocType(this, pubID, sysID); + this.currentNode.rootNodeName = root; + this.currentNode.children = false; + this.currentLevel++; + this.openTags[this.currentLevel] = this.currentNode; + return this; + }; - var st = this.anyStatementMatching(s, p, o, g); - return st != null; - } - }, { - key: 'holdsStatement', - value: function holdsStatement(st) { - return this.holds(st.subject, st.predicate, st.object, st.why); - } - }, { - key: 'list', - value: function list(values) { - var collection = new Collection(); - values.forEach(function (val) { - collection.append(val); - }); - return collection; - } - }, { - key: 'literal', - value: function literal(val, lang, dt) { - return new Literal('' + val, lang, dt); - } - /** - * transform a collection of NTriple URIs into their URI strings - * @param t some iterable colletion of NTriple URI strings - * @return a collection of the URIs as strings - * todo: explain why it is important to go through NT - */ + XMLDocumentCB.prototype.dtdElement = function(name, value) { + var node; + this.openCurrent(); + node = new XMLDTDElement(this, name, value); + this.onData(this.writer.dtdElement(node, this.currentLevel + 1)); + return this; + }; - }, { - key: 'NTtoURI', - value: function NTtoURI(t) { - var k, v; - var uris = {}; - for (k in t) { - if (!t.hasOwnProperty(k)) continue; - v = t[k]; - if (k[0] === '<') { - uris[k.slice(1, -1)] = v; - } + XMLDocumentCB.prototype.attList = function(elementName, attributeName, attributeType, defaultValueType, defaultValue) { + var node; + this.openCurrent(); + node = new XMLDTDAttList(this, elementName, attributeName, attributeType, defaultValueType, defaultValue); + this.onData(this.writer.dtdAttList(node, this.currentLevel + 1)); + return this; + }; + + XMLDocumentCB.prototype.entity = function(name, value) { + var node; + this.openCurrent(); + node = new XMLDTDEntity(this, false, name, value); + this.onData(this.writer.dtdEntity(node, this.currentLevel + 1)); + return this; + }; + + XMLDocumentCB.prototype.pEntity = function(name, value) { + var node; + this.openCurrent(); + node = new XMLDTDEntity(this, true, name, value); + this.onData(this.writer.dtdEntity(node, this.currentLevel + 1)); + return this; + }; + + XMLDocumentCB.prototype.notation = function(name, value) { + var node; + this.openCurrent(); + node = new XMLDTDNotation(this, name, value); + this.onData(this.writer.dtdNotation(node, this.currentLevel + 1)); + return this; + }; + + XMLDocumentCB.prototype.up = function() { + if (this.currentLevel < 0) { + throw new Error("The document node has no parent"); } - return uris; - } - }, { - key: 'serialize', - value: function serialize(base, contentType, provenance) { - var documentString; - var sts; - var sz; - sz = Serializer(this); - sz.suggestNamespaces(this.namespaces); - sz.setBase(base); - if (provenance) { - sts = this.statementsMatching(void 0, void 0, void 0, provenance); + if (this.currentNode) { + if (this.currentNode.children) { + this.closeNode(this.currentNode); + } else { + this.openNode(this.currentNode); + } + this.currentNode = null; } else { - sts = this.statements; - } - switch (contentType != null ? contentType : 'text/n3') { - case 'application/rdf+xml': - documentString = sz.statementsToXML(sts); - break; - case 'text/n3': - case 'text/turtle': - documentString = sz.statementsToN3(sts); - break; - default: - throw new Error('serialize: Content-type ' + contentType + ' not supported.'); - } - return documentString; - } - }, { - key: 'substitute', - value: function substitute(bindings) { - var statementsCopy = this.statements.map(function (ea) { - return ea.substitute(bindings); - }); - console.log('Formula subs statmnts:' + statementsCopy); - var y = new Formula(); - y.add(statementsCopy); - console.log('indexed-form subs formula:' + y); - return y; - } - }, { - key: 'sym', - value: function sym(uri, name) { - if (name) { - throw new Error('This feature (kb.sym with 2 args) is removed. Do not assume prefix mappings.'); + this.closeNode(this.openTags[this.currentLevel]); } - return new NamedNode(uri); - } - }, { - key: 'the', - value: function the(s, p, o, g) { - var x = this.any(s, p, o, g); - if (x == null) { - log.error('No value found for the() {' + s + ' ' + p + ' ' + o + '}.'); + delete this.openTags[this.currentLevel]; + this.currentLevel--; + return this; + }; + + XMLDocumentCB.prototype.end = function() { + while (this.currentLevel >= 0) { + this.up(); } - return x; - } - /** - * RDFS Inference - * These are hand-written implementations of a backward-chaining reasoner - * over the RDFS axioms. - * @param seeds {Object} a hash of NTs of classes to start with - * @param predicate The property to trace though - * @param inverse trace inverse direction - */ + return this.onEnd(); + }; - }, { - key: 'transitiveClosure', - value: function transitiveClosure(seeds, predicate, inverse) { - var elt, i, len, s, sups, t; - var agenda = {}; - Object.assign(agenda, seeds); // make a copy - var done = {}; // classes we have looked up - while (true) { - t = function () { - for (var p in agenda) { - if (!agenda.hasOwnProperty(p)) continue; - return p; - } - }(); - if (t == null) { - return done; - } - sups = inverse ? this.each(void 0, predicate, this.fromNT(t)) : this.each(this.fromNT(t), predicate); - for (i = 0, len = sups.length; i < len; i++) { - elt = sups[i]; - s = elt.toNT(); - if (s in done) { - continue; - } - if (s in agenda) { - continue; - } - agenda[s] = agenda[t]; - } - done[t] = agenda[t]; - delete agenda[t]; + XMLDocumentCB.prototype.openCurrent = function() { + if (this.currentNode) { + this.currentNode.children = true; + return this.openNode(this.currentNode); } - } - /** - * Finds the types in the list which have no *stored* supertypes - * We exclude the universal class, owl:Things and rdf:Resource, as it is - * information-free. - */ + }; - }, { - key: 'topTypeURIs', - value: function topTypeURIs(types) { - var i; - var j; - var k; - var len; - var n; - var ref; - var tops; - var v; - tops = []; - for (k in types) { - if (!types.hasOwnProperty(k)) continue; - v = types[k]; - n = 0; - ref = this.each(this.sym(k), this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf')); - for (i = 0, len = ref.length; i < len; i++) { - j = ref[i]; - if (j.uri !== 'http://www.w3.org/2000/01/rdf-schema#Resource') { - n++; - break; - } - } - if (!n) { - tops[k] = v; + XMLDocumentCB.prototype.openNode = function(node) { + if (!node.isOpen) { + if (!this.root && this.currentLevel === 0 && node instanceof XMLElement) { + this.root = node; } + this.onData(this.writer.openNode(node, this.currentLevel)); + return node.isOpen = true; } - if (tops['http://www.w3.org/2000/01/rdf-schema#Resource']) { - delete tops['http://www.w3.org/2000/01/rdf-schema#Resource']; - } - if (tops['http://www.w3.org/2002/07/owl#Thing']) { - delete tops['http://www.w3.org/2002/07/owl#Thing']; - } - return tops; - } - }, { - key: 'toString', - value: function toString() { - return '{' + this.statements.join('\n') + '}'; - } - }, { - key: 'whether', - value: function whether(s, p, o, g) { - return this.statementsMatching(s, p, o, g, false).length; - } - }]); + }; - return Formula; -}(Node); - -Formula.termType = 'Graph'; - -Formula.prototype.classOrder = ClassOrder['Graph']; -Formula.prototype.isVar = 0; + XMLDocumentCB.prototype.closeNode = function(node) { + if (!node.isClosed) { + this.onData(this.writer.closeNode(node, this.currentLevel)); + return node.isClosed = true; + } + }; -Formula.prototype.ns = _dereq_('./namespace'); -Formula.prototype.variable = function (name) { - return new Variable(name); -}; + XMLDocumentCB.prototype.onData = function(chunk) { + this.documentStarted = true; + return this.onDataCallback(chunk); + }; -module.exports = Formula; -},{"./blank-node":42,"./class-order":43,"./collection":44,"./literal":54,"./log":55,"./named-node":57,"./namespace":58,"./node":59,"./serialize":66,"./statement":69,"./variable":74}],51:[function(_dereq_,module,exports){ -'use strict'; + XMLDocumentCB.prototype.onEnd = function() { + this.documentCompleted = true; + return this.onEndCallback(); + }; -var _indexedFormula = _dereq_('./indexed-formula'); + XMLDocumentCB.prototype.ele = function() { + return this.element.apply(this, arguments); + }; -var _indexedFormula2 = _interopRequireDefault(_indexedFormula); + XMLDocumentCB.prototype.nod = function(name, attributes, text) { + return this.node(name, attributes, text); + }; -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + XMLDocumentCB.prototype.txt = function(value) { + return this.text(value); + }; -var $rdf = { - BlankNode: _dereq_('./blank-node'), - Collection: _dereq_('./collection'), - convert: _dereq_('./convert'), - DataFactory: _dereq_('./data-factory'), - Empty: _dereq_('./empty'), - Fetcher: _dereq_('./fetcher'), - Formula: _dereq_('./formula'), - IndexedFormula: _indexedFormula2.default, - jsonParser: _dereq_('./jsonparser'), - Literal: _dereq_('./literal'), - log: _dereq_('./log'), - N3Parser: _dereq_('./n3parser'), - NamedNode: _dereq_('./named-node'), - Namespace: _dereq_('./namespace'), - Node: _dereq_('./node'), - parse: _dereq_('./parse'), - Query: _dereq_('./query').Query, - queryToSPARQL: _dereq_('./query-to-sparql'), - RDFaProcessor: _dereq_('./rdfaparser'), - RDFParser: _dereq_('./rdfxmlparser'), - serialize: _dereq_('./serialize'), - Serializer: _dereq_('./serializer'), - SPARQLToQuery: _dereq_('./sparql-to-query'), - sparqlUpdateParser: _dereq_('./patch-parser'), - Statement: _dereq_('./statement'), - term: _dereq_('./node').fromValue, - UpdateManager: _dereq_('./update-manager'), - UpdatesSocket: _dereq_('./updates-via').UpdatesSocket, - UpdatesVia: _dereq_('./updates-via').UpdatesVia, - uri: _dereq_('./uri'), - Util: _dereq_('./util'), - Variable: _dereq_('./variable') -}; + XMLDocumentCB.prototype.dat = function(value) { + return this.cdata(value); + }; -$rdf.NextId = $rdf.BlankNode.nextId; + XMLDocumentCB.prototype.com = function(value) { + return this.comment(value); + }; -$rdf.fromNT = $rdf.Formula.prototype.fromNT; -$rdf.fetcher = $rdf.DataFactory.fetcher; -$rdf.graph = $rdf.DataFactory.graph; -$rdf.lit = $rdf.DataFactory.lit; -$rdf.st = $rdf.DataFactory.st; -$rdf.sym = $rdf.DataFactory.namedNode; -$rdf.variable = $rdf.DataFactory.variable; + XMLDocumentCB.prototype.ins = function(target, value) { + return this.instruction(target, value); + }; -// RDFJS DataFactory interface -$rdf.blankNode = $rdf.DataFactory.blankNode; -$rdf.defaultGraph = $rdf.DataFactory.defaultGraph; -$rdf.literal = $rdf.DataFactory.literal; -$rdf.namedNode = $rdf.DataFactory.namedNode; -$rdf.quad = $rdf.DataFactory.quad; -$rdf.triple = $rdf.DataFactory.triple; + XMLDocumentCB.prototype.dec = function(version, encoding, standalone) { + return this.declaration(version, encoding, standalone); + }; -module.exports = $rdf; -},{"./blank-node":42,"./collection":44,"./convert":45,"./data-factory":46,"./empty":48,"./fetcher":49,"./formula":50,"./indexed-formula":52,"./jsonparser":53,"./literal":54,"./log":55,"./n3parser":56,"./named-node":57,"./namespace":58,"./node":59,"./parse":60,"./patch-parser":61,"./query":63,"./query-to-sparql":62,"./rdfaparser":64,"./rdfxmlparser":65,"./serialize":66,"./serializer":67,"./sparql-to-query":68,"./statement":69,"./update-manager":70,"./updates-via":71,"./uri":72,"./util":73,"./variable":74}],52:[function(_dereq_,module,exports){ -'use strict'; + XMLDocumentCB.prototype.dtd = function(root, pubID, sysID) { + return this.doctype(root, pubID, sysID); + }; -Object.defineProperty(exports, "__esModule", { - value: true -}); + XMLDocumentCB.prototype.e = function(name, attributes, text) { + return this.element(name, attributes, text); + }; -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + XMLDocumentCB.prototype.n = function(name, attributes, text) { + return this.node(name, attributes, text); + }; -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + XMLDocumentCB.prototype.t = function(value) { + return this.text(value); + }; -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + XMLDocumentCB.prototype.d = function(value) { + return this.cdata(value); + }; -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + XMLDocumentCB.prototype.c = function(value) { + return this.comment(value); + }; -// Identity management and indexing for RDF -// -// This file provides IndexedFormula a formula (set of triples) which -// indexed by predicate, subject and object. -// -// It "smushes" (merges into a single node) things which are identical -// according to owl:sameAs or an owl:InverseFunctionalProperty -// or an owl:FunctionalProperty -// -// -// 2005-10 Written Tim Berners-Lee -// 2007 Changed so as not to munge statements from documents when smushing -// -// -/* jsl:option explicit */ -var ArrayIndexOf = _dereq_('./util').ArrayIndexOf; -var Formula = _dereq_('./formula'); -// const log = require('./log') -var RDFArrayRemove = _dereq_('./util').RDFArrayRemove; -var Statement = _dereq_('./statement'); -var Node = _dereq_('./node'); -var Variable = _dereq_('./variable'); + XMLDocumentCB.prototype.r = function(value) { + return this.raw(value); + }; -var owl_ns = 'http://www.w3.org/2002/07/owl#'; -// var link_ns = 'http://www.w3.org/2007/ont/link#' + XMLDocumentCB.prototype.i = function(target, value) { + return this.instruction(target, value); + }; -// Handle Functional Property -function handle_FP(formula, subj, pred, obj) { - var o1 = formula.any(subj, pred, undefined); - if (!o1) { - return false; // First time with this value - } - // log.warn("Equating "+o1.uri+" and "+obj.uri + " because FP "+pred.uri); //@@ - formula.equate(o1, obj); - return true; -} // handle_FP + XMLDocumentCB.prototype.att = function() { + if (this.currentNode && this.currentNode instanceof XMLDocType) { + return this.attList.apply(this, arguments); + } else { + return this.attribute.apply(this, arguments); + } + }; -// Handle Inverse Functional Property -function handle_IFP(formula, subj, pred, obj) { - var s1 = formula.any(undefined, pred, obj); - if (!s1) { - return false; // First time with this value - } - // log.warn("Equating "+s1.uri+" and "+subj.uri + " because IFP "+pred.uri); //@@ - formula.equate(s1, subj); - return true; -} // handle_IFP + XMLDocumentCB.prototype.a = function() { + if (this.currentNode && this.currentNode instanceof XMLDocType) { + return this.attList.apply(this, arguments); + } else { + return this.attribute.apply(this, arguments); + } + }; -function handleRDFType(formula, subj, pred, obj, why) { - if (formula.typeCallback) { - formula.typeCallback(formula, obj, why); - } + XMLDocumentCB.prototype.ent = function(name, value) { + return this.entity(name, value); + }; - var x = formula.classActions[obj.hashString()]; - var done = false; - if (x) { - for (var i = 0; i < x.length; i++) { - done = done || x[i](formula, subj, pred, obj, why); - } - } - return done; // statement given is not needed if true -} + XMLDocumentCB.prototype.pent = function(name, value) { + return this.pEntity(name, value); + }; -var IndexedFormula = function (_Formula) { - _inherits(IndexedFormula, _Formula); + XMLDocumentCB.prototype.not = function(name, value) { + return this.notation(name, value); + }; - // IN future - allow pass array of statements to constructor - function IndexedFormula(features) { - _classCallCheck(this, IndexedFormula); + return XMLDocumentCB; - // this.statements = [] // As in Formula NO don't overwrite inherited - // this.optional = [] + })(); - var _this = _possibleConstructorReturn(this, (IndexedFormula.__proto__ || Object.getPrototypeOf(IndexedFormula)).call(this)); +}).call(this); - _this.propertyActions = []; // Array of functions to call when getting statement with {s X o} - // maps to [f(F,s,p,o),...] - _this.classActions = []; // Array of functions to call when adding { s type X } - _this.redirections = []; // redirect to lexically smaller equivalent symbol - _this.aliases = []; // reverse mapping to redirection: aliases for this - _this.HTTPRedirects = []; // redirections we got from HTTP - _this.subjectIndex = []; // Array of statements with this X as subject - _this.predicateIndex = []; // Array of statements with this X as subject - _this.objectIndex = []; // Array of statements with this X as object - _this.whyIndex = []; // Array of statements with X as provenance - _this.index = [_this.subjectIndex, _this.predicateIndex, _this.objectIndex, _this.whyIndex]; - _this.namespaces = {}; // Dictionary of namespace prefixes - _this.features = features || ['sameAs', 'InverseFunctionalProperty', 'FunctionalProperty']; - _this.initPropertyActions(_this.features); - return _this; - } +},{"./Utility":63,"./XMLAttribute":64,"./XMLCData":65,"./XMLComment":66,"./XMLDTDAttList":67,"./XMLDTDElement":68,"./XMLDTDEntity":69,"./XMLDTDNotation":70,"./XMLDeclaration":71,"./XMLDocType":72,"./XMLElement":75,"./XMLProcessingInstruction":77,"./XMLRaw":78,"./XMLStringWriter":80,"./XMLStringifier":81,"./XMLText":82}],75:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLAttribute, XMLElement, XMLNode, isFunction, isObject, ref, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; - _createClass(IndexedFormula, [{ - key: 'substitute', - value: function substitute(bindings) { - var statementsCopy = this.statements.map(function (ea) { - return ea.substitute(bindings); - }); - // console.log('IndexedFormula subs statemnts:' + statementsCopy) - var y = new IndexedFormula(); - y.add(statementsCopy); - // console.log('indexed-form subs formula:' + y) - return y; - } - }, { - key: 'applyPatch', - value: function applyPatch(patch, target, patchCallback) { - // patchCallback(err) - var Query = _dereq_('./query').Query; - var targetKB = this; - var ds; - var binding = null; + ref = _dereq_('./Utility'), isObject = ref.isObject, isFunction = ref.isFunction; - // /////////// Debug strings - /* - var bindingDebug = function (b) { - var str = '' - var v - for (v in b) { - if (b.hasOwnProperty(v)) { - str += ' ' + v + ' -> ' + b[v] - } - } - return str - } - */ - var doPatch = function doPatch(onDonePatch) { - if (patch['delete']) { - ds = patch['delete']; - // console.log(bindingDebug(binding)) - // console.log('ds before substitute: ' + ds) - if (binding) ds = ds.substitute(binding); - // console.log('applyPatch: delete: ' + ds) - ds = ds.statements; - var bad = []; - var ds2 = ds.map(function (st) { - // Find the actual statemnts in the store - var sts = targetKB.statementsMatching(st.subject, st.predicate, st.object, target); - if (sts.length === 0) { - // log.info("NOT FOUND deletable " + st) - bad.push(st); - return null; - } else { - // log.info("Found deletable " + st) - return sts[0]; - } - }); - if (bad.length) { - // console.log('Could not find to delete ' + bad.length + 'statements') - // console.log('despite ' + targetKB.statementsMatching(bad[0].subject, bad[0].predicate)[0]) - return patchCallback('Could not find to delete: ' + bad.join('\n or ')); - } - ds2.map(function (st) { - targetKB.remove(st); - }); - } - if (patch['insert']) { - // log.info("doPatch insert "+patch['insert']) - ds = patch['insert']; - if (binding) ds = ds.substitute(binding); - ds = ds.statements; - ds.map(function (st) { - st.why = target; - targetKB.add(st.subject, st.predicate, st.object, st.why); - }); - } - onDonePatch(); - }; - if (patch.where) { - // log.info("Processing WHERE: " + patch.where + '\n') - var query = new Query('patch'); - query.pat = patch.where; - query.pat.statements.map(function (st) { - st.why = target; - }); + XMLNode = _dereq_('./XMLNode'); - var bindingsFound = []; + XMLAttribute = _dereq_('./XMLAttribute'); - targetKB.query(query, function onBinding(binding) { - bindingsFound.push(binding); - // console.log(' got a binding: ' + bindingDebug(binding)) - }, targetKB.fetcher, function onDone() { - if (bindingsFound.length === 0) { - return patchCallback('No match found to be patched:' + patch.where); - } - if (bindingsFound.length > 1) { - return patchCallback('Patch ambiguous. No patch done.'); - } - binding = bindingsFound[0]; - doPatch(patchCallback); - }); - } else { - doPatch(patchCallback); - } - } - }, { - key: 'declareExistential', - value: function declareExistential(x) { - if (!this._existentialVariables) this._existentialVariables = []; - this._existentialVariables.push(x); - return x; - } - }, { - key: 'initPropertyActions', - value: function initPropertyActions(features) { - // If the predicate is #type, use handleRDFType to create a typeCallback on the object - this.propertyActions[''] = [handleRDFType]; + module.exports = XMLElement = (function(superClass) { + extend(XMLElement, superClass); - // Assumption: these terms are not redirected @@fixme - if (ArrayIndexOf(features, 'sameAs') >= 0) { - this.propertyActions[''] = [function (formula, subj, pred, obj, why) { - // log.warn("Equating "+subj.uri+" sameAs "+obj.uri); //@@ - formula.equate(subj, obj); - return true; // true if statement given is NOT needed in the store - }]; // sameAs -> equate & don't add to index + function XMLElement(parent, name, attributes) { + XMLElement.__super__.constructor.call(this, parent); + if (name == null) { + throw new Error("Missing element name"); } - if (ArrayIndexOf(features, 'InverseFunctionalProperty') >= 0) { - this.classActions['<' + owl_ns + 'InverseFunctionalProperty>'] = [function (formula, subj, pred, obj, addFn) { - // yes subj not pred! - return formula.newPropertyAction(subj, handle_IFP); - }]; // IFP -> handle_IFP, do add to index + this.name = this.stringify.eleName(name); + this.attributes = {}; + if (attributes != null) { + this.attribute(attributes); } - if (ArrayIndexOf(features, 'FunctionalProperty') >= 0) { - this.classActions['<' + owl_ns + 'FunctionalProperty>'] = [function (formula, subj, proj, obj, addFn) { - return formula.newPropertyAction(subj, handle_FP); - }]; // FP => handleFP, do add to index + if (parent.isDocument) { + this.isRoot = true; + this.documentObject = parent; + parent.rootObject = this; } } - /** - * Adds a triple to the store. - * Returns the statement added - * (would it be better to return the original formula for chaining?) - */ - - }, { - key: 'add', - value: function add(subj, pred, obj, why) { - var i; - if (arguments.length === 1) { - if (subj instanceof Array) { - for (i = 0; i < subj.length; i++) { - this.add(subj[i]); - } - } else if (subj instanceof Statement) { - this.add(subj.subject, subj.predicate, subj.object, subj.why); - } else if (subj instanceof IndexedFormula) { - this.add(subj.statements); - } - return this; + XMLElement.prototype.clone = function() { + var att, attName, clonedSelf, ref1; + clonedSelf = Object.create(this); + if (clonedSelf.isRoot) { + clonedSelf.documentObject = null; } - var actions; - var st; - if (!why) { - // system generated - why = this.fetcher ? this.fetcher.appNode : this.sym('chrome:theSession'); + clonedSelf.attributes = {}; + ref1 = this.attributes; + for (attName in ref1) { + if (!hasProp.call(ref1, attName)) continue; + att = ref1[attName]; + clonedSelf.attributes[attName] = att.clone(); } - subj = Node.fromValue(subj); - pred = Node.fromValue(pred); - obj = Node.fromValue(obj); - why = Node.fromValue(why); - if (this.predicateCallback) { - this.predicateCallback(this, pred, why); + clonedSelf.children = []; + this.children.forEach(function(child) { + var clonedChild; + clonedChild = child.clone(); + clonedChild.parent = clonedSelf; + return clonedSelf.children.push(clonedChild); + }); + return clonedSelf; + }; + + XMLElement.prototype.attribute = function(name, value) { + var attName, attValue; + if (name != null) { + name = name.valueOf(); } - // Action return true if the statement does not need to be added - var predHash = this.canon(pred).hashString(); - actions = this.propertyActions[predHash]; // Predicate hash - var done = false; - if (actions) { - // alert('type: '+typeof actions +' @@ actions='+actions) - for (i = 0; i < actions.length; i++) { - done = done || actions[i](this, subj, pred, obj, why); + if (isObject(name)) { + for (attName in name) { + if (!hasProp.call(name, attName)) continue; + attValue = name[attName]; + this.attribute(attName, attValue); + } + } else { + if (isFunction(value)) { + value = value.apply(); + } + if (!this.options.skipNullAttributes || (value != null)) { + this.attributes[name] = new XMLAttribute(this, name, value); } } - if (this.holds(subj, pred, obj, why)) { - // Takes time but saves duplicates - // console.log('rdflib: Ignoring dup! {' + subj + ' ' + pred + ' ' + obj + ' ' + why + '}') - return null; // @@better to return self in all cases? + return this; + }; + + XMLElement.prototype.removeAttribute = function(name) { + var attName, i, len; + if (name == null) { + throw new Error("Missing attribute name"); } - // If we are tracking provenance, every thing should be loaded into the store - // if (done) return new Statement(subj, pred, obj, why) - // Don't put it in the store - // still return this statement for owl:sameAs input - var hash = [this.canon(subj).hashString(), predHash, this.canon(obj).hashString(), this.canon(why).hashString()]; - st = new Statement(subj, pred, obj, why); - for (i = 0; i < 4; i++) { - var ix = this.index[i]; - var h = hash[i]; - if (!ix[h]) { - ix[h] = []; + name = name.valueOf(); + if (Array.isArray(name)) { + for (i = 0, len = name.length; i < len; i++) { + attName = name[i]; + delete this.attributes[attName]; } - ix[h].push(st); // Set of things with this as subject, etc + } else { + delete this.attributes[name]; } + return this; + }; - // log.debug("ADDING {"+subj+" "+pred+" "+obj+"} "+why) - this.statements.push(st); - return st; - } - }, { - key: 'addAll', - value: function addAll(statements) { - var _this2 = this; + XMLElement.prototype.toString = function(options) { + return this.options.writer.set(options).element(this); + }; - statements.forEach(function (quad) { - _this2.add(quad.subject, quad.predicate, quad.object, quad.graph); - }); - } - }, { - key: 'any', - value: function any(s, p, o, g) { - var st = this.anyStatementMatching(s, p, o, g); - if (st == null) { - return void 0; - } else if (s == null) { - return st.subject; - } else if (p == null) { - return st.predicate; - } else if (o == null) { - return st.object; - } - return void 0; - } - }, { - key: 'anyValue', - value: function anyValue(s, p, o, g) { - var y = this.any(s, p, o, g); - return y ? y.value : void 0; - } - }, { - key: 'anyStatementMatching', - value: function anyStatementMatching(subj, pred, obj, why) { - var x = this.statementsMatching(subj, pred, obj, why, true); - if (!x || x.length === 0) { - return undefined; - } - return x[0]; - } - - /** - * Returns the symbol with canonical URI as smushed - */ + XMLElement.prototype.att = function(name, value) { + return this.attribute(name, value); + }; - }, { - key: 'canon', - value: function canon(term) { - if (!term) { - return term; - } - var y = this.redirections[term.hashString()]; - if (!y) { - return term; - } - return y; - } - }, { - key: 'check', - value: function check() { - this.checkStatementList(this.statements); - for (var p = 0; p < 4; p++) { - var ix = this.index[p]; - for (var key in ix) { - if (ix.hasOwnProperty(key)) { - this.checkStatementList(ix[key], p); - } - } - } - } + XMLElement.prototype.a = function(name, value) { + return this.attribute(name, value); + }; - /** - * Self-consistency checking for diagnostis only - * Is each statement properly indexed? - */ + return XMLElement; - }, { - key: 'checkStatementList', - value: function checkStatementList(sts, from) { - var names = ['subject', 'predicate', 'object', 'why']; - var origin = ' found in ' + names[from] + ' index.'; - var st; - for (var j = 0; j < sts.length; j++) { - st = sts[j]; - var term = [st.subject, st.predicate, st.object, st.why]; - var arrayContains = function arrayContains(a, x) { - for (var i = 0; i < a.length; i++) { - if (a[i].subject.sameTerm(x.subject) && a[i].predicate.sameTerm(x.predicate) && a[i].object.sameTerm(x.object) && a[i].why.sameTerm(x.why)) { - return true; - } - } - }; - for (var p = 0; p < 4; p++) { - var c = this.canon(term[p]); - var h = c.hashString(); - if (!this.index[p][h]) { - // throw new Error('No ' + name[p] + ' index for statement ' + st + '@' + st.why + origin) - } else { - if (!arrayContains(this.index[p][h], st)) { - // throw new Error('Index for ' + name[p] + ' does not have statement ' + st + '@' + st.why + origin) - } - } - } - if (!arrayContains(this.statements, st)) { - throw new Error('Statement list does not statement ' + st + '@' + st.why + origin); - } - } - } - }, { - key: 'close', - value: function close() { - return this; - } + })(XMLNode); - /** - * replaces @template with @target and add appropriate triples (no triple - * removed) - * one-direction replication - * @method copyTo - */ +}).call(this); - }, { - key: 'copyTo', - value: function copyTo(template, target, flags) { - if (!flags) flags = []; - var statList = this.statementsMatching(template); - if (ArrayIndexOf(flags, 'two-direction') !== -1) { - statList.concat(this.statementsMatching(undefined, undefined, template)); - } - for (var i = 0; i < statList.length; i++) { - var st = statList[i]; - switch (st.object.termType) { - case 'NamedNode': - this.add(target, st.predicate, st.object); - break; - case 'Literal': - case 'BlankNode': - case 'Collection': - this.add(target, st.predicate, st.object.copy(this)); - } - if (ArrayIndexOf(flags, 'delete') !== -1) { - this.remove(st); - } - } - } +},{"./Utility":63,"./XMLAttribute":64,"./XMLNode":76}],76:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLCData, XMLComment, XMLDeclaration, XMLDocType, XMLElement, XMLNode, XMLProcessingInstruction, XMLRaw, XMLText, isEmpty, isFunction, isObject, ref, + hasProp = {}.hasOwnProperty; - /** - * simplify graph in store when we realize two identifiers are equivalent - * We replace the bigger with the smaller. - */ + ref = _dereq_('./Utility'), isObject = ref.isObject, isFunction = ref.isFunction, isEmpty = ref.isEmpty; - }, { - key: 'equate', - value: function equate(u1, u2) { - // log.warn("Equating "+u1+" and "+u2); // @@ - // @@JAMBO Must canonicalize the uris to prevent errors from a=b=c - // 03-21-2010 - u1 = this.canon(u1); - u2 = this.canon(u2); - var d = u1.compareTerm(u2); - if (!d) { - return true; // No information in {a = a} - } - // var big - // var small - if (d < 0) { - // u1 less than u2 - return this.replaceWith(u2, u1); - } else { - return this.replaceWith(u1, u2); - } - } - }, { - key: 'formula', - value: function formula(features) { - return new IndexedFormula(features); - } + XMLElement = null; - /** - * Returns the number of statements contained in this IndexedFormula. - * (Getter proxy to this.statements). - * Usage: - * ``` - * var kb = rdf.graph() - * kb.length // -> 0 - * ``` - * @return {Number} - */ + XMLCData = null; - }, { - key: 'match', + XMLComment = null; + XMLDeclaration = null; - /** - * Returns any quads matching the given arguments. - * Standard RDFJS Taskforce method for Source objects, implemented as an - * alias to `statementsMatching()` - * @method match - * @param subject {Node|String|Object} - * @param predicate {Node|String|Object} - * @param object {Node|String|Object} - * @param graph {NamedNode|String} - */ - value: function match(subject, predicate, object, graph) { - return this.statementsMatching(Node.fromValue(subject), Node.fromValue(predicate), Node.fromValue(object), Node.fromValue(graph)); - } + XMLDocType = null; - /** - * Find out whether a given URI is used as symbol in the formula - */ + XMLRaw = null; - }, { - key: 'mentionsURI', - value: function mentionsURI(uri) { - var hash = '<' + uri + '>'; - return !!this.subjectIndex[hash] || !!this.objectIndex[hash] || !!this.predicateIndex[hash]; - } + XMLText = null; - // Existentials are BNodes - something exists without naming + XMLProcessingInstruction = null; - }, { - key: 'newExistential', - value: function newExistential(uri) { - if (!uri) return this.bnode(); - var x = this.sym(uri); - return this.declareExistential(x); - } - }, { - key: 'newPropertyAction', - value: function newPropertyAction(pred, action) { - // log.debug("newPropertyAction: "+pred) - var hash = pred.hashString(); - if (!this.propertyActions[hash]) { - this.propertyActions[hash] = []; + module.exports = XMLNode = (function() { + function XMLNode(parent) { + this.parent = parent; + if (this.parent) { + this.options = this.parent.options; + this.stringify = this.parent.stringify; } - this.propertyActions[hash].push(action); - // Now apply the function to to statements already in the store - var toBeFixed = this.statementsMatching(undefined, pred, undefined); - var done = false; - for (var i = 0; i < toBeFixed.length; i++) { - // NOT optimized - sort toBeFixed etc - done = done || action(this, toBeFixed[i].subject, pred, toBeFixed[i].object); + this.children = []; + if (!XMLElement) { + XMLElement = _dereq_('./XMLElement'); + XMLCData = _dereq_('./XMLCData'); + XMLComment = _dereq_('./XMLComment'); + XMLDeclaration = _dereq_('./XMLDeclaration'); + XMLDocType = _dereq_('./XMLDocType'); + XMLRaw = _dereq_('./XMLRaw'); + XMLText = _dereq_('./XMLText'); + XMLProcessingInstruction = _dereq_('./XMLProcessingInstruction'); } - return done; - } - - // Universals are Variables - - }, { - key: 'newUniversal', - value: function newUniversal(uri) { - var x = this.sym(uri); - if (!this._universalVariables) this._universalVariables = []; - this._universalVariables.push(x); - return x; } - // convenience function used by N3 parser - - }, { - key: 'variable', - value: function variable(name) { - return new Variable(name); - } + XMLNode.prototype.element = function(name, attributes, text) { + var childNode, item, j, k, key, lastChild, len, len1, ref1, val; + lastChild = null; + if (attributes == null) { + attributes = {}; + } + attributes = attributes.valueOf(); + if (!isObject(attributes)) { + ref1 = [attributes, text], text = ref1[0], attributes = ref1[1]; + } + if (name != null) { + name = name.valueOf(); + } + if (Array.isArray(name)) { + for (j = 0, len = name.length; j < len; j++) { + item = name[j]; + lastChild = this.element(item); + } + } else if (isFunction(name)) { + lastChild = this.element(name.apply()); + } else if (isObject(name)) { + for (key in name) { + if (!hasProp.call(name, key)) continue; + val = name[key]; + if (isFunction(val)) { + val = val.apply(); + } + if ((isObject(val)) && (isEmpty(val))) { + val = null; + } + if (!this.options.ignoreDecorators && this.stringify.convertAttKey && key.indexOf(this.stringify.convertAttKey) === 0) { + lastChild = this.attribute(key.substr(this.stringify.convertAttKey.length), val); + } else if (!this.options.separateArrayItems && Array.isArray(val)) { + for (k = 0, len1 = val.length; k < len1; k++) { + item = val[k]; + childNode = {}; + childNode[key] = item; + lastChild = this.element(childNode); + } + } else if (isObject(val)) { + lastChild = this.element(key); + lastChild.element(val); + } else { + lastChild = this.element(key, val); + } + } + } else { + if (!this.options.ignoreDecorators && this.stringify.convertTextKey && name.indexOf(this.stringify.convertTextKey) === 0) { + lastChild = this.text(text); + } else if (!this.options.ignoreDecorators && this.stringify.convertCDataKey && name.indexOf(this.stringify.convertCDataKey) === 0) { + lastChild = this.cdata(text); + } else if (!this.options.ignoreDecorators && this.stringify.convertCommentKey && name.indexOf(this.stringify.convertCommentKey) === 0) { + lastChild = this.comment(text); + } else if (!this.options.ignoreDecorators && this.stringify.convertRawKey && name.indexOf(this.stringify.convertRawKey) === 0) { + lastChild = this.raw(text); + } else if (!this.options.ignoreDecorators && this.stringify.convertPIKey && name.indexOf(this.stringify.convertPIKey) === 0) { + lastChild = this.instruction(name.substr(this.stringify.convertPIKey.length), text); + } else { + lastChild = this.node(name, attributes, text); + } + } + if (lastChild == null) { + throw new Error("Could not create any elements with: " + name); + } + return lastChild; + }; - /** - * Find an unused id for a file being edited: return a symbol - * (Note: Slow iff a lot of them -- could be O(log(k)) ) - */ + XMLNode.prototype.insertBefore = function(name, attributes, text) { + var child, i, removed; + if (this.isRoot) { + throw new Error("Cannot insert elements at root level"); + } + i = this.parent.children.indexOf(this); + removed = this.parent.children.splice(i); + child = this.parent.element(name, attributes, text); + Array.prototype.push.apply(this.parent.children, removed); + return child; + }; - }, { - key: 'nextSymbol', - value: function nextSymbol(doc) { - for (var i = 0;; i++) { - var uri = doc.uri + '#n' + i; - if (!this.mentionsURI(uri)) return this.sym(uri); + XMLNode.prototype.insertAfter = function(name, attributes, text) { + var child, i, removed; + if (this.isRoot) { + throw new Error("Cannot insert elements at root level"); } - } - }, { - key: 'query', - value: function query(myQuery, callback, fetcher, onDone) { - var indexedFormulaQuery = _dereq_('./query').indexedFormulaQuery; - return indexedFormulaQuery.call(this, myQuery, callback, fetcher, onDone); - } + i = this.parent.children.indexOf(this); + removed = this.parent.children.splice(i + 1); + child = this.parent.element(name, attributes, text); + Array.prototype.push.apply(this.parent.children, removed); + return child; + }; - /** - * Finds a statement object and removes it - */ + XMLNode.prototype.remove = function() { + var i, ref1; + if (this.isRoot) { + throw new Error("Cannot remove the root element"); + } + i = this.parent.children.indexOf(this); + [].splice.apply(this.parent.children, [i, i - i + 1].concat(ref1 = [])), ref1; + return this.parent; + }; - }, { - key: 'remove', - value: function remove(st) { - if (st instanceof Array) { - for (var i = 0; i < st.length; i++) { - this.remove(st[i]); - } - return this; + XMLNode.prototype.node = function(name, attributes, text) { + var child, ref1; + if (name != null) { + name = name.valueOf(); } - if (st instanceof IndexedFormula) { - return this.remove(st.statements); + attributes || (attributes = {}); + attributes = attributes.valueOf(); + if (!isObject(attributes)) { + ref1 = [attributes, text], text = ref1[0], attributes = ref1[1]; } - var sts = this.statementsMatching(st.subject, st.predicate, st.object, st.why); - if (!sts.length) { - throw new Error('Statement to be removed is not on store: ' + st); + child = new XMLElement(this, name, attributes); + if (text != null) { + child.text(text); } - this.removeStatement(sts[0]); + this.children.push(child); + return child; + }; + + XMLNode.prototype.text = function(value) { + var child; + child = new XMLText(this, value); + this.children.push(child); return this; - } + }; - /** - * Removes all statemnts in a doc - */ + XMLNode.prototype.cdata = function(value) { + var child; + child = new XMLCData(this, value); + this.children.push(child); + return this; + }; - }, { - key: 'removeDocument', - value: function removeDocument(doc) { - var sts = this.statementsMatching(undefined, undefined, undefined, doc).slice(); // Take a copy as this is the actual index - for (var i = 0; i < sts.length; i++) { - this.removeStatement(sts[i]); - } + XMLNode.prototype.comment = function(value) { + var child; + child = new XMLComment(this, value); + this.children.push(child); return this; - } + }; - /** - * remove all statements matching args (within limit) * - */ + XMLNode.prototype.commentBefore = function(value) { + var child, i, removed; + i = this.parent.children.indexOf(this); + removed = this.parent.children.splice(i); + child = this.parent.comment(value); + Array.prototype.push.apply(this.parent.children, removed); + return this; + }; - }, { - key: 'removeMany', - value: function removeMany(subj, pred, obj, why, limit) { - // log.debug("entering removeMany w/ subj,pred,obj,why,limit = " + subj +", "+ pred+", " + obj+", " + why+", " + limit) - var sts = this.statementsMatching(subj, pred, obj, why, false); - // This is a subtle bug that occcured in updateCenter.js too. - // The fact is, this.statementsMatching returns this.whyIndex instead of a copy of it - // but for perfromance consideration, it's better to just do that - // so make a copy here. - var statements = []; - for (var i = 0; i < sts.length; i++) { - statements.push(sts[i]); - }if (limit) statements = statements.slice(0, limit); - for (i = 0; i < statements.length; i++) { - this.remove(statements[i]); - } - } - }, { - key: 'removeMatches', - value: function removeMatches(subject, predicate, object, why) { - this.removeStatements(this.statementsMatching(subject, predicate, object, why)); + XMLNode.prototype.commentAfter = function(value) { + var child, i, removed; + i = this.parent.children.indexOf(this); + removed = this.parent.children.splice(i + 1); + child = this.parent.comment(value); + Array.prototype.push.apply(this.parent.children, removed); return this; - } + }; - /** - * Remove a particular statement object from the store - * - * st a statement which is already in the store and indexed. - * Make sure you only use this for these. - * Otherwise, you should use remove() above. - */ + XMLNode.prototype.raw = function(value) { + var child; + child = new XMLRaw(this, value); + this.children.push(child); + return this; + }; - }, { - key: 'removeStatement', - value: function removeStatement(st) { - // log.debug("entering remove w/ st=" + st) - var term = [st.subject, st.predicate, st.object, st.why]; - for (var p = 0; p < 4; p++) { - var c = this.canon(term[p]); - var h = c.hashString(); - if (!this.index[p][h]) { - // log.warn ("Statement removal: no index '+p+': "+st) - } else { - RDFArrayRemove(this.index[p][h], st); - } - } - RDFArrayRemove(this.statements, st); - return this; - } - }, { - key: 'removeStatements', - value: function removeStatements(sts) { - for (var i = 0; i < sts.length; i++) { - this.remove(sts[i]); + XMLNode.prototype.instruction = function(target, value) { + var insTarget, insValue, instruction, j, len; + if (target != null) { + target = target.valueOf(); } - return this; - } - - /** - * Replace big with small, obsoleted with obsoleting. - */ - - }, { - key: 'replaceWith', - value: function replaceWith(big, small) { - // log.debug("Replacing "+big+" with "+small) // @@ - var oldhash = big.hashString(); - var newhash = small.hashString(); - var moveIndex = function moveIndex(ix) { - var oldlist = ix[oldhash]; - if (!oldlist) { - return; // none to move - } - var newlist = ix[newhash]; - if (!newlist) { - ix[newhash] = oldlist; - } else { - ix[newhash] = oldlist.concat(newlist); - } - delete ix[oldhash]; - }; - // the canonical one carries all the indexes - for (var i = 0; i < 4; i++) { - moveIndex(this.index[i]); + if (value != null) { + value = value.valueOf(); } - this.redirections[oldhash] = small; - if (big.uri) { - // @@JAMBO: must update redirections,aliases from sub-items, too. - if (!this.aliases[newhash]) { - this.aliases[newhash] = []; + if (Array.isArray(target)) { + for (j = 0, len = target.length; j < len; j++) { + insTarget = target[j]; + this.instruction(insTarget); } - this.aliases[newhash].push(big); // Back link - if (this.aliases[oldhash]) { - for (i = 0; i < this.aliases[oldhash].length; i++) { - this.redirections[this.aliases[oldhash][i].hashString()] = small; - this.aliases[newhash].push(this.aliases[oldhash][i]); - } + } else if (isObject(target)) { + for (insTarget in target) { + if (!hasProp.call(target, insTarget)) continue; + insValue = target[insTarget]; + this.instruction(insTarget, insValue); } - this.add(small, this.sym('http://www.w3.org/2007/ont/link#uri'), big.uri); - // If two things are equal, and one is requested, we should request the other. - if (this.fetcher) { - this.fetcher.nowKnownAs(big, small); + } else { + if (isFunction(value)) { + value = value.apply(); } + instruction = new XMLProcessingInstruction(this, target, value); + this.children.push(instruction); } - moveIndex(this.classActions); - moveIndex(this.propertyActions); - // log.debug("Equate done. "+big+" to be known as "+small) - return true; // true means the statement does not need to be put in - } + return this; + }; - /** - * Return all equivalent URIs by which this is known - */ + XMLNode.prototype.instructionBefore = function(target, value) { + var child, i, removed; + i = this.parent.children.indexOf(this); + removed = this.parent.children.splice(i); + child = this.parent.instruction(target, value); + Array.prototype.push.apply(this.parent.children, removed); + return this; + }; - }, { - key: 'allAliases', - value: function allAliases(x) { - var a = this.aliases[this.canon(x).hashString()] || []; - a.push(this.canon(x)); - return a; - } + XMLNode.prototype.instructionAfter = function(target, value) { + var child, i, removed; + i = this.parent.children.indexOf(this); + removed = this.parent.children.splice(i + 1); + child = this.parent.instruction(target, value); + Array.prototype.push.apply(this.parent.children, removed); + return this; + }; - /** - * Compare by canonical URI as smushed - */ + XMLNode.prototype.declaration = function(version, encoding, standalone) { + var doc, xmldec; + doc = this.document(); + xmldec = new XMLDeclaration(doc, version, encoding, standalone); + if (doc.children[0] instanceof XMLDeclaration) { + doc.children[0] = xmldec; + } else { + doc.children.unshift(xmldec); + } + return doc.root() || doc; + }; - }, { - key: 'sameThings', - value: function sameThings(x, y) { - if (x.sameTerm(y)) { - return true; + XMLNode.prototype.doctype = function(pubID, sysID) { + var child, doc, doctype, i, j, k, len, len1, ref1, ref2; + doc = this.document(); + doctype = new XMLDocType(doc, pubID, sysID); + ref1 = doc.children; + for (i = j = 0, len = ref1.length; j < len; i = ++j) { + child = ref1[i]; + if (child instanceof XMLDocType) { + doc.children[i] = doctype; + return doctype; + } } - var x1 = this.canon(x); - // alert('x1='+x1) - if (!x1) return false; - var y1 = this.canon(y); - // alert('y1='+y1); //@@ - if (!y1) return false; - return x1.uri === y1.uri; - } - }, { - key: 'setPrefixForURI', - value: function setPrefixForURI(prefix, nsuri) { - // TODO: This is a hack for our own issues, which ought to be fixed - // post-release - // See http://dig.csail.mit.edu/cgi-bin/roundup.cgi/$rdf/issue227 - if (prefix === 'tab' && this.namespaces['tab']) { - return; - } // There are files around with long badly generated prefixes like this - if (prefix.slice(0, 2) === 'ns' || prefix.slice(0, 7) === 'default') { - return; + ref2 = doc.children; + for (i = k = 0, len1 = ref2.length; k < len1; i = ++k) { + child = ref2[i]; + if (child.isRoot) { + doc.children.splice(i, 0, doctype); + return doctype; + } } - this.namespaces[prefix] = nsuri; - } + doc.children.push(doctype); + return doctype; + }; - /** - * Return statements matching a pattern - * ALL CONVENIENCE LOOKUP FUNCTIONS RELY ON THIS! - */ + XMLNode.prototype.up = function() { + if (this.isRoot) { + throw new Error("The root node has no parent. Use doc() if you need to get the document object."); + } + return this.parent; + }; - }, { - key: 'statementsMatching', - value: function statementsMatching(subj, pred, obj, why, justOne) { - // log.debug("Matching {"+subj+" "+pred+" "+obj+"}") - var pat = [subj, pred, obj, why]; - var pattern = []; - var hash = []; - var wild = []; // wildcards - var given = []; // Not wild - var p; - var list; - for (p = 0; p < 4; p++) { - pattern[p] = this.canon(Node.fromValue(pat[p])); - if (!pattern[p]) { - wild.push(p); + XMLNode.prototype.root = function() { + var node; + node = this; + while (node) { + if (node.isDocument) { + return node.rootObject; + } else if (node.isRoot) { + return node; } else { - given.push(p); - hash[p] = pattern[p].hashString(); + node = node.parent; } } - if (given.length === 0) { - return this.statements; - } - if (given.length === 1) { - // Easy too, we have an index for that - p = given[0]; - list = this.index[p][hash[p]]; - if (list && justOne) { - if (list.length > 1) { - list = list.slice(0, 1); - } + }; + + XMLNode.prototype.document = function() { + var node; + node = this; + while (node) { + if (node.isDocument) { + return node; + } else { + node = node.parent; } - list = list || []; - return list; } - // Now given.length is 2, 3 or 4. - // We hope that the scale-free nature of the data will mean we tend to get - // a short index in there somewhere! - var best = 1e10; // really bad - var best_i; + }; + + XMLNode.prototype.end = function(options) { + return this.document().end(options); + }; + + XMLNode.prototype.prev = function() { var i; - for (i = 0; i < given.length; i++) { - p = given[i]; // Which part we are dealing with - list = this.index[p][hash[p]]; - if (!list) { - return []; // No occurrences - } - if (list.length < best) { - best = list.length; - best_i = i; // (not p!) - } + i = this.parent.children.indexOf(this); + if (i < 1) { + throw new Error("Already at the first node"); } - // Ok, we have picked the shortest index but now we have to filter it - var best_p = given[best_i]; - var possibles = this.index[best_p][hash[best_p]]; - var check = given.slice(0, best_i).concat(given.slice(best_i + 1)); // remove best_i - var results = []; - var parts = ['subject', 'predicate', 'object', 'why']; - for (var j = 0; j < possibles.length; j++) { - var st = possibles[j]; + return this.parent.children[i - 1]; + }; - for (i = 0; i < check.length; i++) { - // for each position to be checked - p = check[i]; - if (!this.canon(st[parts[p]]).sameTerm(pattern[p])) { - st = null; - break; - } - } - if (st != null) { - results.push(st); - if (justOne) break; - } + XMLNode.prototype.next = function() { + var i; + i = this.parent.children.indexOf(this); + if (i === -1 || i === this.parent.children.length - 1) { + throw new Error("Already at the last node"); } - return results; - } + return this.parent.children[i + 1]; + }; - /** - * A list of all the URIs by which this thing is known - */ + XMLNode.prototype.importDocument = function(doc) { + var clonedRoot; + clonedRoot = doc.root().clone(); + clonedRoot.parent = this; + clonedRoot.isRoot = false; + this.children.push(clonedRoot); + return this; + }; - }, { - key: 'uris', - value: function uris(term) { - var cterm = this.canon(term); - var terms = this.aliases[cterm.hashString()]; - if (!cterm.uri) return []; - var res = [cterm.uri]; - if (terms) { - for (var i = 0; i < terms.length; i++) { - res.push(terms[i].uri); - } - } - return res; - } - }, { - key: 'length', - get: function get() { - return this.statements.length; - } - }]); + XMLNode.prototype.ele = function(name, attributes, text) { + return this.element(name, attributes, text); + }; - return IndexedFormula; -}(Formula); + XMLNode.prototype.nod = function(name, attributes, text) { + return this.node(name, attributes, text); + }; -exports.default = IndexedFormula; + XMLNode.prototype.txt = function(value) { + return this.text(value); + }; + XMLNode.prototype.dat = function(value) { + return this.cdata(value); + }; -IndexedFormula.handleRDFType = handleRDFType; -},{"./formula":50,"./node":59,"./query":63,"./statement":69,"./util":73,"./variable":74}],53:[function(_dereq_,module,exports){ -'use strict'; + XMLNode.prototype.com = function(value) { + return this.comment(value); + }; -var jsonParser = function () { - return { - parseJSON: function parseJSON(data, source, store) { - var subject, predicate, object; - var bnodes = {}; - var why = store.sym(source); - for (var x in data) { - if (x.indexOf('_:') === 0) { - if (bnodes[x]) { - subject = bnodes[x]; - } else { - subject = store.bnode(x); - bnodes[x] = subject; - } - } else { - subject = store.sym(x); - } - var preds = data[x]; - for (var y in preds) { - var objects = preds[y]; - predicate = store.sym(y); - for (var z in objects) { - var obj = objects[z]; - if (obj.type === 'uri') { - object = store.sym(obj.value); - store.add(subject, predicate, object, why); - } else if (obj.type === 'BlankNode') { - if (bnodes[obj.value]) { - object = bnodes[obj.value]; - } else { - object = store.bnode(obj.value); - bnodes[obj.value] = object; - } - store.add(subject, predicate, object, why); - } else if (obj.type === 'Literal') { - // var datatype - if (obj.datatype) { - object = store.literal(obj.value, undefined, store.sym(obj.datatype)); - } else if (obj.lang) { - object = store.literal(obj.value, obj.lang); - } else { - object = store.literal(obj.value); - } - store.add(subject, predicate, object, why); - } else { - throw new Error('error: unexpected termtype: ' + z.type); - } - } - } - } - } - }; -}(); + XMLNode.prototype.ins = function(target, value) { + return this.instruction(target, value); + }; -module.exports = jsonParser; -},{}],54:[function(_dereq_,module,exports){ -'use strict'; + XMLNode.prototype.doc = function() { + return this.document(); + }; -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + XMLNode.prototype.dec = function(version, encoding, standalone) { + return this.declaration(version, encoding, standalone); + }; -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + XMLNode.prototype.dtd = function(pubID, sysID) { + return this.doctype(pubID, sysID); + }; -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + XMLNode.prototype.e = function(name, attributes, text) { + return this.element(name, attributes, text); + }; -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + XMLNode.prototype.n = function(name, attributes, text) { + return this.node(name, attributes, text); + }; -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + XMLNode.prototype.t = function(value) { + return this.text(value); + }; -var ClassOrder = _dereq_('./class-order'); -var NamedNode = _dereq_('./named-node'); -var Node = _dereq_('./node'); -var XSD = _dereq_('./xsd'); + XMLNode.prototype.d = function(value) { + return this.cdata(value); + }; -var Literal = function (_Node) { - _inherits(Literal, _Node); + XMLNode.prototype.c = function(value) { + return this.comment(value); + }; - function Literal(value, language, datatype) { - _classCallCheck(this, Literal); + XMLNode.prototype.r = function(value) { + return this.raw(value); + }; - var _this = _possibleConstructorReturn(this, (Literal.__proto__ || Object.getPrototypeOf(Literal)).call(this)); + XMLNode.prototype.i = function(target, value) { + return this.instruction(target, value); + }; - _this.termType = Literal.termType; - _this.value = value; - if (language) { - _this.lang = language; - datatype = XSD.langString; - } - // If not specified, a literal has the implied XSD.string default datatype - if (datatype) { - _this.datatype = NamedNode.fromValue(datatype); - } - return _this; - } + XMLNode.prototype.u = function() { + return this.up(); + }; - _createClass(Literal, [{ - key: 'copy', - value: function copy() { - return new Literal(this.value, this.lang, this.datatype); - } - }, { - key: 'equals', - value: function equals(other) { - if (!other) { - return false; - } - return this.termType === other.termType && this.value === other.value && this.language === other.language && (!this.datatype && !other.datatype || this.datatype && this.datatype.equals(other.datatype)); - } - }, { - key: 'toNT', - value: function toNT() { - if (typeof this.value === 'number') { - return this.toString(); - } else if (typeof this.value !== 'string') { - throw new Error('Value of RDF literal is not string or number: ' + this.value); - } - var str = this.value; - str = str.replace(/\\/g, '\\\\'); - str = str.replace(/\"/g, '\\"'); - str = str.replace(/\n/g, '\\n'); - str = '"' + str + '"'; + XMLNode.prototype.importXMLBuilder = function(doc) { + return this.importDocument(doc); + }; - if (this.language) { - str += '@' + this.language; - } else if (!this.datatype.equals(XSD.string)) { - // Only add datatype if it's not a string - str += '^^' + this.datatype.toCanonical(); + return XMLNode; + + })(); + +}).call(this); + +},{"./Utility":63,"./XMLCData":65,"./XMLComment":66,"./XMLDeclaration":71,"./XMLDocType":72,"./XMLElement":75,"./XMLProcessingInstruction":77,"./XMLRaw":78,"./XMLText":82}],77:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLNode, XMLProcessingInstruction, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + XMLNode = _dereq_('./XMLNode'); + + module.exports = XMLProcessingInstruction = (function(superClass) { + extend(XMLProcessingInstruction, superClass); + + function XMLProcessingInstruction(parent, target, value) { + XMLProcessingInstruction.__super__.constructor.call(this, parent); + if (target == null) { + throw new Error("Missing instruction target"); + } + this.target = this.stringify.insTarget(target); + if (value) { + this.value = this.stringify.insValue(value); } - return str; } - }, { - key: 'toString', - value: function toString() { - return '' + this.value; - } - /** - * @method fromBoolean - * @static - * @param value {Boolean} - * @return {Literal} - */ - }, { - key: 'language', - get: function get() { - return this.lang; - }, - set: function set(language) { - this.lang = language || ''; - } - }], [{ - key: 'fromBoolean', - value: function fromBoolean(value) { - var strValue = value ? '1' : '0'; - return new Literal(strValue, null, XSD.boolean); - } - /** - * @method fromDate - * @static - * @param value {Date} - * @return {Literal} - */ + XMLProcessingInstruction.prototype.clone = function() { + return Object.create(this); + }; - }, { - key: 'fromDate', - value: function fromDate(value) { - if (!(value instanceof Date)) { - throw new TypeError('Invalid argument to Literal.fromDate()'); - } - var d2 = function d2(x) { - return ('' + (100 + x)).slice(1, 3); - }; - var date = '' + value.getUTCFullYear() + '-' + d2(value.getUTCMonth() + 1) + '-' + d2(value.getUTCDate()) + 'T' + d2(value.getUTCHours()) + ':' + d2(value.getUTCMinutes()) + ':' + d2(value.getUTCSeconds()) + 'Z'; - return new Literal(date, null, XSD.dateTime); - } - /** - * @method fromNumber - * @static - * @param value {Number} - * @return {Literal} - */ + XMLProcessingInstruction.prototype.toString = function(options) { + return this.options.writer.set(options).processingInstruction(this); + }; - }, { - key: 'fromNumber', - value: function fromNumber(value) { - if (typeof value !== 'number') { - throw new TypeError('Invalid argument to Literal.fromNumber()'); - } - var datatype = void 0; - var strValue = value.toString(); - if (strValue.indexOf('e') < 0 && Math.abs(value) <= Number.MAX_SAFE_INTEGER) { - datatype = Number.isInteger(value) ? XSD.integer : XSD.decimal; - } else { - datatype = XSD.double; - } - return new Literal(strValue, null, datatype); - } - /** - * @method fromValue - * @param value - * @return {Literal} - */ + return XMLProcessingInstruction; - }, { - key: 'fromValue', - value: function fromValue(value) { - if (typeof value === 'undefined' || value === null) { - return value; - } - if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && value.termType) { - // this is a Node instance - return value; - } - switch (typeof value === 'undefined' ? 'undefined' : _typeof(value)) { - case 'object': - if (value instanceof Date) { - return Literal.fromDate(value); - } - case 'boolean': - return Literal.fromBoolean(value); - case 'number': - return Literal.fromNumber(value); - case 'string': - return new Literal(value); + })(XMLNode); + +}).call(this); + +},{"./XMLNode":76}],78:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLNode, XMLRaw, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; + + XMLNode = _dereq_('./XMLNode'); + + module.exports = XMLRaw = (function(superClass) { + extend(XMLRaw, superClass); + + function XMLRaw(parent, text) { + XMLRaw.__super__.constructor.call(this, parent); + if (text == null) { + throw new Error("Missing raw text"); } - throw new Error("Can't make literal from " + value + ' of type ' + (typeof value === 'undefined' ? 'undefined' : _typeof(value))); + this.value = this.stringify.raw(text); } - }]); - return Literal; -}(Node); + XMLRaw.prototype.clone = function() { + return Object.create(this); + }; -Literal.termType = 'Literal'; -Literal.prototype.classOrder = ClassOrder['Literal']; -Literal.prototype.datatype = XSD.string; -Literal.prototype.lang = ''; -Literal.prototype.isVar = 0; + XMLRaw.prototype.toString = function(options) { + return this.options.writer.set(options).raw(this); + }; -module.exports = Literal; -},{"./class-order":43,"./named-node":57,"./node":59,"./xsd":75}],55:[function(_dereq_,module,exports){ -"use strict"; + return XMLRaw; -/** - * A Dummy log - * @module log - */ -module.exports = { - debug: function debug(x) { - return; - }, - warn: function warn(x) { - return; - }, - info: function info(x) { - return; - }, - error: function error(x) { - return; - }, - success: function success(x) { - return; - }, - msg: function msg(x) { - return; - } -}; -},{}],56:[function(_dereq_,module,exports){ -'use strict'; + })(XMLNode); -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; +}).call(this); -/** -* -* UTF-8 data encode / decode -* http://www.webtoolkit.info/ -* -**/ -var Uri = _dereq_('./uri'); -var ArrayIndexOf = _dereq_('./util').ArrayIndexOf; +},{"./XMLNode":76}],79:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLCData, XMLComment, XMLDTDAttList, XMLDTDElement, XMLDTDEntity, XMLDTDNotation, XMLDeclaration, XMLDocType, XMLElement, XMLProcessingInstruction, XMLRaw, XMLStreamWriter, XMLText, XMLWriterBase, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; -var N3Parser = function () { + XMLDeclaration = _dereq_('./XMLDeclaration'); - function hexify(str) { - // also used in parser - return encodeURI(str); - } + XMLDocType = _dereq_('./XMLDocType'); - var Utf8 = { - // public method for url encoding - encode: function encode(string) { - string = string.replace(/\r\n/g, "\n"); - var utftext = ""; + XMLCData = _dereq_('./XMLCData'); - for (var n = 0; n < string.length; n++) { + XMLComment = _dereq_('./XMLComment'); - var c = string.charCodeAt(n); + XMLElement = _dereq_('./XMLElement'); - if (c < 128) { - utftext += String.fromCharCode(c); - } else if (c > 127 && c < 2048) { - utftext += String.fromCharCode(c >> 6 | 192); - utftext += String.fromCharCode(c & 63 | 128); - } else { - utftext += String.fromCharCode(c >> 12 | 224); - utftext += String.fromCharCode(c >> 6 & 63 | 128); - utftext += String.fromCharCode(c & 63 | 128); - } - } + XMLRaw = _dereq_('./XMLRaw'); - return utftext; - }, - // public method for url decoding - decode: function decode(utftext) { - var string = ""; - var i = 0; + XMLText = _dereq_('./XMLText'); - while (i < utftext.length) { + XMLProcessingInstruction = _dereq_('./XMLProcessingInstruction'); - var c = utftext.charCodeAt(i); - if (c < 128) { - string += String.fromCharCode(c); - i++; - } else if (c > 191 && c < 224) { - string += String.fromCharCode((c & 31) << 6 | utftext.charCodeAt(i + 1) & 63); - i += 2; - } else { - string += String.fromCharCode((c & 15) << 12 | (utftext.charCodeAt(i + 1) & 63) << 6 | utftext.charCodeAt(i + 2) & 63); - i += 3; - } - } - return string; - } - }; // Things we need to define to make converted pythn code work in js - // environment of $rdf + XMLDTDAttList = _dereq_('./XMLDTDAttList'); - var RDFSink_forSomeSym = "http://www.w3.org/2000/10/swap/log#forSome"; - var RDFSink_forAllSym = "http://www.w3.org/2000/10/swap/log#forAll"; - var Logic_NS = "http://www.w3.org/2000/10/swap/log#"; + XMLDTDElement = _dereq_('./XMLDTDElement'); - // pyjs seems to reference runtime library which I didn't find + XMLDTDEntity = _dereq_('./XMLDTDEntity'); - var pyjslib_Tuple = function pyjslib_Tuple(theList) { - return theList; + XMLDTDNotation = _dereq_('./XMLDTDNotation'); + + XMLWriterBase = _dereq_('./XMLWriterBase'); + + module.exports = XMLStreamWriter = (function(superClass) { + extend(XMLStreamWriter, superClass); + + function XMLStreamWriter(stream, options) { + this.stream = stream; + XMLStreamWriter.__super__.constructor.call(this, options); + } + + XMLStreamWriter.prototype.document = function(doc) { + var child, i, j, len, len1, ref, ref1, results; + ref = doc.children; + for (i = 0, len = ref.length; i < len; i++) { + child = ref[i]; + child.isLastRootNode = false; + } + doc.children[doc.children.length - 1].isLastRootNode = true; + ref1 = doc.children; + results = []; + for (j = 0, len1 = ref1.length; j < len1; j++) { + child = ref1[j]; + switch (false) { + case !(child instanceof XMLDeclaration): + results.push(this.declaration(child)); + break; + case !(child instanceof XMLDocType): + results.push(this.docType(child)); + break; + case !(child instanceof XMLComment): + results.push(this.comment(child)); + break; + case !(child instanceof XMLProcessingInstruction): + results.push(this.processingInstruction(child)); + break; + default: + results.push(this.element(child)); + } + } + return results; }; - var pyjslib_List = function pyjslib_List(theList) { - return theList; + XMLStreamWriter.prototype.attribute = function(att) { + return this.stream.write(' ' + att.name + '="' + att.value + '"'); }; - var pyjslib_Dict = function pyjslib_Dict(listOfPairs) { - if (listOfPairs.length > 0) throw "missing.js: oops nnonempty dict not imp"; - return []; + XMLStreamWriter.prototype.cdata = function(node, level) { + return this.stream.write(this.space(level) + '' + this.endline(node)); }; - var pyjslib_len = function pyjslib_len(s) { - return s.length; + XMLStreamWriter.prototype.comment = function(node, level) { + return this.stream.write(this.space(level) + '' + this.endline(node)); }; - var pyjslib_slice = function pyjslib_slice(str, i, j) { - if (typeof str.slice == 'undefined') throw '@@ mising.js: No .slice function for ' + str + ' of type ' + (typeof str === 'undefined' ? 'undefined' : _typeof(str)); - if (typeof j == 'undefined' || j == null) return str.slice(i); - return str.slice(i, j); // @ exactly the same spec? + XMLStreamWriter.prototype.declaration = function(node, level) { + this.stream.write(this.space(level)); + this.stream.write(''); + return this.stream.write(this.endline(node)); }; - var StopIteration = Error('dummy error stop iteration'); - var pyjslib_Iterator = function pyjslib_Iterator(theList) { - this.last = 0; - this.li = theList; - this.next = function () { - if (this.last == this.li.length) throw StopIteration; - return this.li[this.last++]; - }; - return this; + XMLStreamWriter.prototype.docType = function(node, level) { + var child, i, len, ref; + level || (level = 0); + this.stream.write(this.space(level)); + this.stream.write(' 0) { + this.stream.write(' ['); + this.stream.write(this.endline(node)); + ref = node.children; + for (i = 0, len = ref.length; i < len; i++) { + child = ref[i]; + switch (false) { + case !(child instanceof XMLDTDAttList): + this.dtdAttList(child, level + 1); + break; + case !(child instanceof XMLDTDElement): + this.dtdElement(child, level + 1); + break; + case !(child instanceof XMLDTDEntity): + this.dtdEntity(child, level + 1); + break; + case !(child instanceof XMLDTDNotation): + this.dtdNotation(child, level + 1); + break; + case !(child instanceof XMLCData): + this.cdata(child, level + 1); + break; + case !(child instanceof XMLComment): + this.comment(child, level + 1); + break; + case !(child instanceof XMLProcessingInstruction): + this.processingInstruction(child, level + 1); + break; + default: + throw new Error("Unknown DTD node type: " + child.constructor.name); + } + } + this.stream.write(']'); + } + this.stream.write(this.spacebeforeslash + '>'); + return this.stream.write(this.endline(node)); }; - var ord = function ord(str) { - return str.charCodeAt(0); + XMLStreamWriter.prototype.element = function(node, level) { + var att, child, i, len, name, ref, ref1, space; + level || (level = 0); + space = this.space(level); + this.stream.write(space + '<' + node.name); + ref = node.attributes; + for (name in ref) { + if (!hasProp.call(ref, name)) continue; + att = ref[name]; + this.attribute(att); + } + if (node.children.length === 0 || node.children.every(function(e) { + return e.value === ''; + })) { + if (this.allowEmpty) { + this.stream.write('>'); + } else { + this.stream.write(this.spacebeforeslash + '/>'); + } + } else if (this.pretty && node.children.length === 1 && (node.children[0].value != null)) { + this.stream.write('>'); + this.stream.write(node.children[0].value); + this.stream.write(''); + } else { + this.stream.write('>' + this.newline); + ref1 = node.children; + for (i = 0, len = ref1.length; i < len; i++) { + child = ref1[i]; + switch (false) { + case !(child instanceof XMLCData): + this.cdata(child, level + 1); + break; + case !(child instanceof XMLComment): + this.comment(child, level + 1); + break; + case !(child instanceof XMLElement): + this.element(child, level + 1); + break; + case !(child instanceof XMLRaw): + this.raw(child, level + 1); + break; + case !(child instanceof XMLText): + this.text(child, level + 1); + break; + case !(child instanceof XMLProcessingInstruction): + this.processingInstruction(child, level + 1); + break; + default: + throw new Error("Unknown XML node type: " + child.constructor.name); + } + } + this.stream.write(space + ''); + } + return this.stream.write(this.endline(node)); }; - var string_find = function string_find(str, s) { - return str.indexOf(s); + XMLStreamWriter.prototype.processingInstruction = function(node, level) { + this.stream.write(this.space(level) + '' + this.endline(node)); }; - var assertFudge = function assertFudge(condition, desc) { - if (condition) return; - if (desc) throw "python Assertion failed: " + desc; - throw "(python) Assertion failed."; + XMLStreamWriter.prototype.raw = function(node, level) { + return this.stream.write(this.space(level) + node.value + this.endline(node)); }; - var stringFromCharCode = function stringFromCharCode(uesc) { - return String.fromCharCode(uesc); + XMLStreamWriter.prototype.text = function(node, level) { + return this.stream.write(this.space(level) + node.value + this.endline(node)); }; - String.prototype.encode = function (encoding) { - if (encoding != 'utf-8') throw "UTF8_converter: can only do utf-8"; - return Utf8.encode(this); + XMLStreamWriter.prototype.dtdAttList = function(node, level) { + this.stream.write(this.space(level) + '' + this.endline(node)); }; - String.prototype.decode = function (encoding) { - if (encoding != 'utf-8') throw "UTF8_converter: can only do utf-8"; - //return Utf8.decode(this); - return this; + + XMLStreamWriter.prototype.dtdElement = function(node, level) { + this.stream.write(this.space(level) + '' + this.endline(node)); }; - var uripath_join = function uripath_join(base, given) { - return Uri.join(given, base); // sad but true + XMLStreamWriter.prototype.dtdEntity = function(node, level) { + this.stream.write(this.space(level) + '' + this.endline(node)); }; - var becauseSubexpression = null; // No reason needed - var diag_tracking = 0; - var diag_chatty_flag = 0; - var diag_progress = function diag_progress(str) {} /*$rdf.log.debug(str);*/ + XMLStreamWriter.prototype.dtdNotation = function(node, level) { + this.stream.write(this.space(level) + '' + this.endline(node)); + }; - // why_BecauseOfData = function(doc, reason) { return doc }; + XMLStreamWriter.prototype.endline = function(node) { + if (!node.isLastRootNode) { + return this.newline; + } else { + return ''; + } + }; + return XMLStreamWriter; - ;var RDF_type_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"; - var DAML_sameAs_URI = "http://www.w3.org/2002/07/owl#sameAs"; + })(XMLWriterBase); - /* - function SyntaxError(details) { - return new __SyntaxError(details); - } - */ +}).call(this); - function __SyntaxError(details) { - this.details = details; - } +},{"./XMLCData":65,"./XMLComment":66,"./XMLDTDAttList":67,"./XMLDTDElement":68,"./XMLDTDEntity":69,"./XMLDTDNotation":70,"./XMLDeclaration":71,"./XMLDocType":72,"./XMLElement":75,"./XMLProcessingInstruction":77,"./XMLRaw":78,"./XMLText":82,"./XMLWriterBase":83}],80:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLCData, XMLComment, XMLDTDAttList, XMLDTDElement, XMLDTDEntity, XMLDTDNotation, XMLDeclaration, XMLDocType, XMLElement, XMLProcessingInstruction, XMLRaw, XMLStringWriter, XMLText, XMLWriterBase, + extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, + hasProp = {}.hasOwnProperty; - /* - - $Id: n3parser.js 14561 2008-02-23 06:37:26Z kennyluck $ - - HAND EDITED FOR CONVERSION TO JAVASCRIPT - - This module implements a Nptation3 parser, and the final - part of a notation3 serializer. - - See also: - - Notation 3 - http://www.w3.org/DesignIssues/Notation3 - - Closed World Machine - and RDF Processor - http://www.w3.org/2000/10/swap/cwm - - To DO: See also "@@" in comments - - - Clean up interfaces - ______________________________________________ - - Module originally by Dan Connolly, includeing notation3 - parser and RDF generator. TimBL added RDF stream model - and N3 generation, replaced stream model with use - of common store/formula API. Yosi Scharf developped - the module, including tests and test harness. - - */ + XMLDeclaration = _dereq_('./XMLDeclaration'); - var ADDED_HASH = "#"; - var LOG_implies_URI = "http://www.w3.org/2000/10/swap/log#implies"; - var INTEGER_DATATYPE = "http://www.w3.org/2001/XMLSchema#integer"; - var FLOAT_DATATYPE = "http://www.w3.org/2001/XMLSchema#double"; - var DECIMAL_DATATYPE = "http://www.w3.org/2001/XMLSchema#decimal"; - var DATE_DATATYPE = "http://www.w3.org/2001/XMLSchema#date"; - var DATETIME_DATATYPE = "http://www.w3.org/2001/XMLSchema#dateTime"; - var BOOLEAN_DATATYPE = "http://www.w3.org/2001/XMLSchema#boolean"; - var option_noregen = 0; - var _notQNameChars = "\t\r\n !\"#$%&'()*.,+/;<=>?@[\\]^`{|}~"; - var _notNameChars = _notQNameChars + ":"; - var _rdfns = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; - var N3CommentCharacter = "#"; - var eol = new RegExp("^[ \\t]*(#[^\\n]*)?\\r?\\n", 'g'); - var eof = new RegExp("^[ \\t]*(#[^\\n]*)?$", 'g'); - var ws = new RegExp("^[ \\t]*", 'g'); - var signed_integer = new RegExp("^[-+]?[0-9]+", 'g'); - var number_syntax = new RegExp("^([-+]?[0-9]+)(\\.[0-9]+)?(e[-+]?[0-9]+)?", 'g'); - var datetime_syntax = new RegExp('^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9](T[0-9][0-9]:[0-9][0-9](:[0-9][0-9](\\.[0-9]*)?)?)?Z?'); + XMLDocType = _dereq_('./XMLDocType'); - var digitstring = new RegExp("^[0-9]+", 'g'); - var interesting = new RegExp("[\\\\\\r\\n\\\"]", 'g'); - var langcode = new RegExp("^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*", 'g'); - function SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why) { - return new __SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why); - } - function __SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why) { - if (typeof openFormula == 'undefined') openFormula = null; - if (typeof thisDoc == 'undefined') thisDoc = ""; - if (typeof baseURI == 'undefined') baseURI = null; - if (typeof genPrefix == 'undefined') genPrefix = ""; - if (typeof metaURI == 'undefined') metaURI = null; - if (typeof flags == 'undefined') flags = ""; - if (typeof why == 'undefined') why = null; - /* - note: namespace names should *not* end in #; - the # will get added during qname processing */ + XMLCData = _dereq_('./XMLCData'); - this._bindings = new pyjslib_Dict([]); - this._flags = flags; - if (thisDoc != "") { - assertFudge(thisDoc.indexOf(":") >= 0, "Document URI not absolute: " + thisDoc); - this._bindings[""] = thisDoc + "#"; - } - this._store = store; - if (genPrefix) { - store.setGenPrefix(genPrefix); - } - this._thisDoc = thisDoc; - this.source = store.sym(thisDoc); - this.lines = 0; - this.statementCount = 0; - this.startOfLine = 0; - this.previousLine = 0; - this._genPrefix = genPrefix; - this.keywords = new pyjslib_List(["a", "this", "bind", "has", "is", "of", "true", "false"]); - this.keywordsSet = 0; - this._anonymousNodes = new pyjslib_Dict([]); - this._variables = new pyjslib_Dict([]); - this._parentVariables = new pyjslib_Dict([]); - this._reason = why; - this._reason2 = null; - if (diag_tracking) { - this._reason2 = why_BecauseOfData(store.sym(thisDoc), this._reason); - } - if (baseURI) { - this._baseURI = baseURI; - } else { - if (thisDoc) { - this._baseURI = thisDoc; - } else { - this._baseURI = null; - } - } - assertFudge(!this._baseURI || this._baseURI.indexOf(":") >= 0); - if (!this._genPrefix) { - if (this._thisDoc) { - this._genPrefix = this._thisDoc + "#_g"; - } else { - this._genPrefix = RDFSink_uniqueURI(); - } - } - if (openFormula == null) { - if (this._thisDoc) { - this._formula = store.formula(thisDoc + "#_formula"); - } else { - this._formula = store.formula(); - } - } else { - this._formula = openFormula; - } - this._context = this._formula; - this._parentContext = null; + XMLComment = _dereq_('./XMLComment'); + + XMLElement = _dereq_('./XMLElement'); + + XMLRaw = _dereq_('./XMLRaw'); + + XMLText = _dereq_('./XMLText'); + + XMLProcessingInstruction = _dereq_('./XMLProcessingInstruction'); + + XMLDTDAttList = _dereq_('./XMLDTDAttList'); + + XMLDTDElement = _dereq_('./XMLDTDElement'); + + XMLDTDEntity = _dereq_('./XMLDTDEntity'); + + XMLDTDNotation = _dereq_('./XMLDTDNotation'); + + XMLWriterBase = _dereq_('./XMLWriterBase'); + + module.exports = XMLStringWriter = (function(superClass) { + extend(XMLStringWriter, superClass); + + function XMLStringWriter(options) { + XMLStringWriter.__super__.constructor.call(this, options); } - __SinkParser.prototype.here = function (i) { - return this._genPrefix + "_L" + this.lines + "C" + (i - this.startOfLine + 1); - }; - __SinkParser.prototype.formula = function () { - return this._formula; + + XMLStringWriter.prototype.document = function(doc) { + var child, i, len, r, ref; + this.textispresent = false; + r = ''; + ref = doc.children; + for (i = 0, len = ref.length; i < len; i++) { + child = ref[i]; + r += (function() { + switch (false) { + case !(child instanceof XMLDeclaration): + return this.declaration(child); + case !(child instanceof XMLDocType): + return this.docType(child); + case !(child instanceof XMLComment): + return this.comment(child); + case !(child instanceof XMLProcessingInstruction): + return this.processingInstruction(child); + default: + return this.element(child, 0); + } + }).call(this); + } + if (this.pretty && r.slice(-this.newline.length) === this.newline) { + r = r.slice(0, -this.newline.length); + } + return r; }; - __SinkParser.prototype.loadStream = function (stream) { - return this.loadBuf(stream.read()); + + XMLStringWriter.prototype.attribute = function(att) { + return ' ' + att.name + '="' + att.value + '"'; }; - __SinkParser.prototype.loadBuf = function (buf) { - /* - Parses a buffer and returns its top level formula*/ - this.startDoc(); - this.feed(buf); - return this.endDoc(); + XMLStringWriter.prototype.cdata = function(node, level) { + return this.space(level) + '' + this.newline; }; - __SinkParser.prototype.feed = function (octets) { - /* - Feed an octet stream tothe parser - if BadSyntax is raised, the string - passed in the exception object is the - remainder after any statements have been parsed. - So if there is more data to feed to the - parser, it should be straightforward to recover.*/ - var str = octets.decode("utf-8"); - var i = 0; - while (i >= 0) { - var j = this.skipSpace(str, i); - if (j < 0) { - return; - } - var i = this.directiveOrStatement(str, j); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, j, "expected directive or statement"); - } - } + XMLStringWriter.prototype.comment = function(node, level) { + return this.space(level) + '' + this.newline; }; - __SinkParser.prototype.directiveOrStatement = function (str, h) { - var i = this.skipSpace(str, h); - if (i < 0) { - return i; - } - var j = this.directive(str, i); - if (j >= 0) { - return this.checkDot(str, j); - } - var j = this.statement(str, i); - if (j >= 0) { - return this.checkDot(str, j); - } - return j; + + XMLStringWriter.prototype.declaration = function(node, level) { + var r; + r = this.space(level); + r += ''; + r += this.newline; + return r; }; - __SinkParser.prototype.tok = function (tok, str, i) { - /* - Check for keyword. Space must have been stripped on entry and - we must not be at end of file.*/ - var whitespace = "\t\n\v\f\r "; - if (pyjslib_slice(str, i, i + 1) == "@") { - var i = i + 1; - } else { - if (ArrayIndexOf(this.keywords, tok) < 0) { - return -1; + + XMLStringWriter.prototype.docType = function(node, level) { + var child, i, len, r, ref; + level || (level = 0); + r = this.space(level); + r += ' 0) { + r += ' ['; + r += this.newline; + ref = node.children; + for (i = 0, len = ref.length; i < len; i++) { + child = ref[i]; + r += (function() { + switch (false) { + case !(child instanceof XMLDTDAttList): + return this.dtdAttList(child, level + 1); + case !(child instanceof XMLDTDElement): + return this.dtdElement(child, level + 1); + case !(child instanceof XMLDTDEntity): + return this.dtdEntity(child, level + 1); + case !(child instanceof XMLDTDNotation): + return this.dtdNotation(child, level + 1); + case !(child instanceof XMLCData): + return this.cdata(child, level + 1); + case !(child instanceof XMLComment): + return this.comment(child, level + 1); + case !(child instanceof XMLProcessingInstruction): + return this.processingInstruction(child, level + 1); + default: + throw new Error("Unknown DTD node type: " + child.constructor.name); } + }).call(this); } - var k = i + pyjslib_len(tok); - if (pyjslib_slice(str, i, k) == tok && _notQNameChars.indexOf(str.charAt(k)) >= 0) { - return k; - } else { - return -1; - } + r += ']'; + } + r += this.spacebeforeslash + '>'; + r += this.newline; + return r; }; - __SinkParser.prototype.directive = function (str, i) { - var j = this.skipSpace(str, i); - if (j < 0) { - return j; - } - var res = new pyjslib_List([]); - var j = this.tok("bind", str, i); - if (j > 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "keyword bind is obsolete: use @prefix"); - } - var j = this.tok("keywords", str, i); - if (j > 0) { - var i = this.commaSeparatedList(str, j, res, false); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "'@keywords' needs comma separated list of words"); - } - this.setKeywords(pyjslib_slice(res, null, null)); - if (diag_chatty_flag > 80) { - diag_progress("Keywords ", this.keywords); - } - return i; - } - var j = this.tok("forAll", str, i); - if (j > 0) { - var i = this.commaSeparatedList(str, j, res, true); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad variable list after @forAll"); - } - - var __x = new pyjslib_Iterator(res); - try { - while (true) { - var x = __x.next(); - - if (ArrayIndexOf(this._variables, x) < 0 || ArrayIndexOf(this._parentVariables, x) >= 0) { - this._variables[x] = this._context.newUniversal(x); - } - } - } catch (e) { - if (e != StopIteration) { - throw e; - } - } - return i; + XMLStringWriter.prototype.element = function(node, level) { + var att, child, i, j, len, len1, name, r, ref, ref1, ref2, space, textispresentwasset; + level || (level = 0); + textispresentwasset = false; + if (this.textispresent) { + this.newline = ''; + this.pretty = false; + } else { + this.newline = this.newlinedefault; + this.pretty = this.prettydefault; + } + space = this.space(level); + r = ''; + r += space + '<' + node.name; + ref = node.attributes; + for (name in ref) { + if (!hasProp.call(ref, name)) continue; + att = ref[name]; + r += this.attribute(att); + } + if (node.children.length === 0 || node.children.every(function(e) { + return e.value === ''; + })) { + if (this.allowEmpty) { + r += '>' + this.newline; + } else { + r += this.spacebeforeslash + '/>' + this.newline; } - var j = this.tok("forSome", str, i); - if (j > 0) { - var i = this.commaSeparatedList(str, j, res, this.uri_ref2); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad variable list after @forSome"); - } - - var __x = new pyjslib_Iterator(res); - try { - while (true) { - var x = __x.next(); - - this._context.declareExistential(x); - } - } catch (e) { - if (e != StopIteration) { - throw e; - } + } else if (this.pretty && node.children.length === 1 && (node.children[0].value != null)) { + r += '>'; + r += node.children[0].value; + r += '' + this.newline; + } else { + if (this.dontprettytextnodes) { + ref1 = node.children; + for (i = 0, len = ref1.length; i < len; i++) { + child = ref1[i]; + if (child.value != null) { + this.textispresent++; + textispresentwasset = true; + break; } - - return i; + } } - var j = this.tok("prefix", str, i); - if (j >= 0) { - var t = new pyjslib_List([]); - var i = this.qname(str, j, t); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, j, "expected qname after @prefix"); - } - var j = this.uri_ref2(str, i, t); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "expected after @prefix _qname_"); - } - var ns = t[1].uri; - if (this._baseURI) { - var ns = uripath_join(this._baseURI, ns); - } else { - assertFudge(ns.indexOf(":") >= 0, "With no base URI, cannot handle relative URI for NS"); - } - assertFudge(ns.indexOf(":") >= 0); - this._bindings[t[0][0]] = ns; - - this.bind(t[0][0], hexify(ns)); - return j; + if (this.textispresent) { + this.newline = ''; + this.pretty = false; + space = this.space(level); } - var j = this.tok("base", str, i); - if (j >= 0) { - var t = new pyjslib_List([]); - var i = this.uri_ref2(str, j, t); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, j, "expected after @base "); - } - var ns = t[0].uri; - if (this._baseURI) { - var ns = uripath_join(this._baseURI, ns); - } else { - throw BadSyntax(this._thisDoc, this.lines, str, j, "With no previous base URI, cannot use relative URI in @base <" + ns + ">"); + r += '>' + this.newline; + ref2 = node.children; + for (j = 0, len1 = ref2.length; j < len1; j++) { + child = ref2[j]; + r += (function() { + switch (false) { + case !(child instanceof XMLCData): + return this.cdata(child, level + 1); + case !(child instanceof XMLComment): + return this.comment(child, level + 1); + case !(child instanceof XMLElement): + return this.element(child, level + 1); + case !(child instanceof XMLRaw): + return this.raw(child, level + 1); + case !(child instanceof XMLText): + return this.text(child, level + 1); + case !(child instanceof XMLProcessingInstruction): + return this.processingInstruction(child, level + 1); + default: + throw new Error("Unknown XML node type: " + child.constructor.name); } - assertFudge(ns.indexOf(":") >= 0); - this._baseURI = ns; - return i; + }).call(this); } - return -1; - }; - __SinkParser.prototype.bind = function (qn, uri) { - if (qn == "") {} else { - this._store.setPrefixForURI(qn, uri); + if (textispresentwasset) { + this.textispresent--; + } + if (!this.textispresent) { + this.newline = this.newlinedefault; + this.pretty = this.prettydefault; } + r += space + '' + this.newline; + } + return r; }; - __SinkParser.prototype.setKeywords = function (k) { - /* - Takes a list of strings*/ - if (k == null) { - this.keywordsSet = 0; - } else { - this.keywords = k; - this.keywordsSet = 1; - } + XMLStringWriter.prototype.processingInstruction = function(node, level) { + var r; + r = this.space(level) + '' + this.newline; + return r; }; - __SinkParser.prototype.startDoc = function () {}; - __SinkParser.prototype.endDoc = function () { - /* - Signal end of document and stop parsing. returns formula*/ - return this._formula; + XMLStringWriter.prototype.raw = function(node, level) { + return this.space(level) + node.value + this.newline; }; - __SinkParser.prototype.makeStatement = function (quad) { - quad[0].add(quad[2], quad[1], quad[3], this.source); - this.statementCount += 1; + + XMLStringWriter.prototype.text = function(node, level) { + return this.space(level) + node.value + this.newline; }; - __SinkParser.prototype.statement = function (str, i) { - var r = new pyjslib_List([]); - var i = this.object(str, i, r); - if (i < 0) { - return i; - } - var j = this.property_list(str, i, r[0]); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "expected propertylist"); - } - return j; + + XMLStringWriter.prototype.dtdAttList = function(node, level) { + var r; + r = this.space(level) + '' + this.newline; + return r; }; - __SinkParser.prototype.subject = function (str, i, res) { - return this.item(str, i, res); + + XMLStringWriter.prototype.dtdElement = function(node, level) { + return this.space(level) + '' + this.newline; }; - __SinkParser.prototype.verb = function (str, i, res) { - /* - has _prop_ - is _prop_ of - a - = - _prop_ - >- prop -> - <- prop -< - _operator_*/ - var j = this.skipSpace(str, i); - if (j < 0) { - return j; - } - var r = new pyjslib_List([]); - var j = this.tok("has", str, i); - if (j >= 0) { - var i = this.prop(str, j, r); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, j, "expected property after 'has'"); - } - res.push(new pyjslib_Tuple(["->", r[0]])); - return i; - } - var j = this.tok("is", str, i); - if (j >= 0) { - var i = this.prop(str, j, r); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, j, "expected after 'is'"); - } - var j = this.skipSpace(str, i); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "End of file found, expected property after 'is'"); - return j; - } - var i = j; - var j = this.tok("of", str, i); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "expected 'of' after 'is' "); - } - res.push(new pyjslib_Tuple(["<-", r[0]])); - return j; - } - var j = this.tok("a", str, i); - if (j >= 0) { - res.push(new pyjslib_Tuple(["->", this._store.sym(RDF_type_URI)])); - return j; - } - if (pyjslib_slice(str, i, i + 2) == "<=") { - res.push(new pyjslib_Tuple(["<-", this._store.sym(Logic_NS + "implies")])); - return i + 2; - } - if (pyjslib_slice(str, i, i + 1) == "=") { - if (pyjslib_slice(str, i + 1, i + 2) == ">") { - res.push(new pyjslib_Tuple(["->", this._store.sym(Logic_NS + "implies")])); - return i + 2; - } - res.push(new pyjslib_Tuple(["->", this._store.sym(DAML_sameAs_URI)])); - return i + 1; - } - if (pyjslib_slice(str, i, i + 2) == ":=") { - res.push(new pyjslib_Tuple(["->", Logic_NS + "becomes"])); - return i + 2; - } - var j = this.prop(str, i, r); - if (j >= 0) { - res.push(new pyjslib_Tuple(["->", r[0]])); - return j; + XMLStringWriter.prototype.dtdEntity = function(node, level) { + var r; + r = this.space(level) + '-" || pyjslib_slice(str, i, i + 2) == "<-") { - throw BadSyntax(this._thisDoc, this.lines, str, j, ">- ... -> syntax is obsolete."); + if (node.nData) { + r += ' NDATA ' + node.nData; } - return -1; - }; - __SinkParser.prototype.prop = function (str, i, res) { - return this.item(str, i, res); - }; - __SinkParser.prototype.item = function (str, i, res) { - return this.path(str, i, res); + } + r += this.spacebeforeslash + '>' + this.newline; + return r; }; - __SinkParser.prototype.blankNode = function (uri) { - return this._context.bnode(uri, this._reason2); + + XMLStringWriter.prototype.dtdNotation = function(node, level) { + var r; + r = this.space(level) + '' + this.newline; + return r; }; - __SinkParser.prototype.path = function (str, i, res) { - /* - Parse the path production. - */ - var j = this.nodeOrLiteral(str, i, res); - if (j < 0) { - return j; + XMLStringWriter.prototype.openNode = function(node, level) { + var att, name, r, ref; + level || (level = 0); + if (node instanceof XMLElement) { + r = this.space(level) + '<' + node.name; + ref = node.attributes; + for (name in ref) { + if (!hasProp.call(ref, name)) continue; + att = ref[name]; + r += this.attribute(att); } - while ("!^.".indexOf(pyjslib_slice(str, j, j + 1)) >= 0) { - var ch = pyjslib_slice(str, j, j + 1); - if (ch == ".") { - var ahead = pyjslib_slice(str, j + 1, j + 2); - if (!ahead || _notNameChars.indexOf(ahead) >= 0 && ":?<[{(".indexOf(ahead) < 0) { - break; - } - } - var subj = res.pop(); - var obj = this.blankNode(this.here(j)); - var j = this.node(str, j + 1, res); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found in middle of path syntax"); - } - var pred = res.pop(); - if (ch == "^") { - this.makeStatement(new pyjslib_Tuple([this._context, pred, obj, subj])); - } else { - this.makeStatement(new pyjslib_Tuple([this._context, pred, subj, obj])); - } - res.push(obj); + r += (node.children ? '>' : '/>') + this.newline; + return r; + } else { + r = this.space(level) + '') + this.newline; + return r; + } }; - __SinkParser.prototype.anonymousNode = function (ln) { - /* - Remember or generate a term for one of these _: anonymous nodes*/ - var term = this._anonymousNodes[ln]; - if (term) { - return term; - } - var term = this._store.bnode(this._context, this._reason2); - this._anonymousNodes[ln] = term; - return term; + XMLStringWriter.prototype.closeNode = function(node, level) { + level || (level = 0); + switch (false) { + case !(node instanceof XMLElement): + return this.space(level) + '' + this.newline; + case !(node instanceof XMLDocType): + return this.space(level) + ']>' + this.newline; + } }; - __SinkParser.prototype.node = function (str, i, res, subjectAlready) { - if (typeof subjectAlready == 'undefined') subjectAlready = null; - /* - Parse the production. - Space is now skipped once at the beginning - instead of in multipe calls to self.skipSpace(). - */ - var subj = subjectAlready; - var j = this.skipSpace(str, i); - if (j < 0) { - return j; - } - var i = j; - var ch = pyjslib_slice(str, i, i + 1); - if (ch == "[") { - var bnodeID = this.here(i); - var j = this.skipSpace(str, i + 1); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF after '['"); - } - if (pyjslib_slice(str, j, j + 1) == "=") { - var i = j + 1; - var objs = new pyjslib_List([]); - var j = this.objectList(str, i, objs); + return XMLStringWriter; - if (j >= 0) { - var subj = objs[0]; - if (pyjslib_len(objs) > 1) { + })(XMLWriterBase); - var __obj = new pyjslib_Iterator(objs); - try { - while (true) { - var obj = __obj.next(); +}).call(this); - this.makeStatement(new pyjslib_Tuple([this._context, this._store.sym(DAML_sameAs_URI), subj, obj])); - } - } catch (e) { - if (e != StopIteration) { - throw e; - } - } - } - var j = this.skipSpace(str, j); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF when objectList expected after [ = "); - } - if (pyjslib_slice(str, j, j + 1) == ";") { - var j = j + 1; - } - } else { - throw BadSyntax(this._thisDoc, this.lines, str, i, "objectList expected after [= "); - } - } - if (subj == null) { - var subj = this.blankNode(bnodeID); - } - var i = this.property_list(str, j, subj); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, j, "property_list expected"); - } - var j = this.skipSpace(str, i); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF when ']' expected after [ "); - } - if (pyjslib_slice(str, j, j + 1) != "]") { - throw BadSyntax(this._thisDoc, this.lines, str, j, "']' expected"); - } - res.push(subj); - return j + 1; - } - if (ch == "{") { - var ch2 = pyjslib_slice(str, i + 1, i + 2); - if (ch2 == "$") { - i += 1; - var j = i + 1; - var mylist = new pyjslib_List([]); - var first_run = true; - while (1) { - var i = this.skipSpace(str, j); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "needed '$}', found end."); - } - if (pyjslib_slice(str, i, i + 2) == "$}") { - var j = i + 2; - break; - } - if (!first_run) { - if (pyjslib_slice(str, i, i + 1) == ",") { - i += 1; - } else { - throw BadSyntax(this._thisDoc, this.lines, str, i, "expected: ','"); - } - } else { - var first_run = false; - } - var item = new pyjslib_List([]); - var j = this.item(str, i, item); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "expected item in set or '$}'"); - } - mylist.push(item[0]); - } - res.push(this._store.newSet(mylist, this._context)); - return j; - } else { - var j = i + 1; - var oldParentContext = this._parentContext; - this._parentContext = this._context; - var parentAnonymousNodes = this._anonymousNodes; - var grandParentVariables = this._parentVariables; - this._parentVariables = this._variables; - this._anonymousNodes = new pyjslib_Dict([]); - this._variables = this._variables.slice(); - var reason2 = this._reason2; - this._reason2 = becauseSubexpression; - if (subj == null) { - var subj = this._store.formula(); - } - this._context = subj; - while (1) { - var i = this.skipSpace(str, j); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "needed '}', found end."); - } - if (pyjslib_slice(str, i, i + 1) == "}") { - var j = i + 1; - break; - } - var j = this.directiveOrStatement(str, i); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "expected statement or '}'"); - } - } - this._anonymousNodes = parentAnonymousNodes; - this._variables = this._parentVariables; - this._parentVariables = grandParentVariables; - this._context = this._parentContext; - this._reason2 = reason2; - this._parentContext = oldParentContext; - res.push(subj.close()); - return j; - } - } - if (ch == "(") { - var thing_type = this._store.list; - var ch2 = pyjslib_slice(str, i + 1, i + 2); - if (ch2 == "$") { - var thing_type = this._store.newSet; - i += 1; - } - var j = i + 1; - var mylist = new pyjslib_List([]); - while (1) { - var i = this.skipSpace(str, j); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "needed ')', found end."); - } - if (pyjslib_slice(str, i, i + 1) == ")") { - var j = i + 1; - break; - } - var item = new pyjslib_List([]); - var j = this.item(str, i, item); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "expected item in list or ')'"); - } - mylist.push(item[0]); - } - res.push(thing_type(mylist, this._context)); - return j; - } - var j = this.tok("this", str, i); - if (j >= 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "Keyword 'this' was ancient N3. Now use @forSome and @forAll keywords."); - res.push(this._context); - return j; - } - var j = this.tok("true", str, i); - if (j >= 0) { - res.push(true); - return j; - } - var j = this.tok("false", str, i); - if (j >= 0) { - res.push(false); - return j; - } - if (subj == null) { - var j = this.uri_ref2(str, i, res); - if (j >= 0) { - return j; - } - } - return -1; +},{"./XMLCData":65,"./XMLComment":66,"./XMLDTDAttList":67,"./XMLDTDElement":68,"./XMLDTDEntity":69,"./XMLDTDNotation":70,"./XMLDeclaration":71,"./XMLDocType":72,"./XMLElement":75,"./XMLProcessingInstruction":77,"./XMLRaw":78,"./XMLText":82,"./XMLWriterBase":83}],81:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLStringifier, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + hasProp = {}.hasOwnProperty; + + module.exports = XMLStringifier = (function() { + function XMLStringifier(options) { + this.assertLegalChar = bind(this.assertLegalChar, this); + var key, ref, value; + options || (options = {}); + this.noDoubleEncoding = options.noDoubleEncoding; + ref = options.stringify || {}; + for (key in ref) { + if (!hasProp.call(ref, key)) continue; + value = ref[key]; + this[key] = value; + } + } + + XMLStringifier.prototype.eleName = function(val) { + val = '' + val || ''; + return this.assertLegalChar(val); }; - __SinkParser.prototype.property_list = function (str, i, subj) { - /* - Parse property list - Leaves the terminating punctuation in the buffer - */ - while (1) { - var j = this.skipSpace(str, i); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF found when expected verb in property list"); - return j; - } - if (pyjslib_slice(str, j, j + 2) == ":-") { - var i = j + 2; - var res = new pyjslib_List([]); - var j = this.node(str, i, res, subj); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "bad {} or () or [] node after :- "); - } - var i = j; - continue; - } - var i = j; - var v = new pyjslib_List([]); - var j = this.verb(str, i, v); - if (j <= 0) { - return i; - } - var objs = new pyjslib_List([]); - var i = this.objectList(str, j, objs); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, j, "objectList expected"); - } + XMLStringifier.prototype.eleText = function(val) { + val = '' + val || ''; + return this.assertLegalChar(this.elEscape(val)); + }; - var __obj = new pyjslib_Iterator(objs); - try { - while (true) { - var obj = __obj.next(); + XMLStringifier.prototype.cdata = function(val) { + val = '' + val || ''; + val = val.replace(']]>', ']]]]>'); + return this.assertLegalChar(val); + }; - var pairFudge = v[0]; - var dir = pairFudge[0]; - var sym = pairFudge[1]; - if (dir == "->") { - this.makeStatement(new pyjslib_Tuple([this._context, sym, subj, obj])); - } else { - this.makeStatement(new pyjslib_Tuple([this._context, sym, obj, subj])); - } - } - } catch (e) { - if (e != StopIteration) { - throw e; - } - } + XMLStringifier.prototype.comment = function(val) { + val = '' + val || ''; + if (val.match(/--/)) { + throw new Error("Comment text cannot contain double-hypen: " + val); + } + return this.assertLegalChar(val); + }; - var j = this.skipSpace(str, i); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found in list of objects"); - return j; - } - if (pyjslib_slice(str, i, i + 1) != ";") { - return i; - } - var i = i + 1; - } + XMLStringifier.prototype.raw = function(val) { + return '' + val || ''; }; - __SinkParser.prototype.commaSeparatedList = function (str, j, res, ofUris) { - /* - return value: -1 bad syntax; >1 new position in str - res has things found appended - Used to use a final value of the function to be called, e.g. this.bareWord - but passing the function didn't work fo js converion pyjs - */ - var i = this.skipSpace(str, j); - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF found expecting comma sep list"); - return i; - } - if (str.charAt(i) == ".") { - return j; - } - if (ofUris) { - var i = this.uri_ref2(str, i, res); - } else { - var i = this.bareWord(str, i, res); - } - if (i < 0) { - return -1; - } - while (1) { - var j = this.skipSpace(str, i); - if (j < 0) { - return j; - } - var ch = pyjslib_slice(str, j, j + 1); - if (ch != ",") { - if (ch != ".") { - return -1; - } - return j; - } - if (ofUris) { - var i = this.uri_ref2(str, j + 1, res); - } else { - var i = this.bareWord(str, j + 1, res); - } - if (i < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "bad list content"); - return i; - } - } + XMLStringifier.prototype.attName = function(val) { + return val = '' + val || ''; }; - __SinkParser.prototype.objectList = function (str, i, res) { - var i = this.object(str, i, res); - if (i < 0) { - return -1; - } - while (1) { - var j = this.skipSpace(str, i); - if (j < 0) { - throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found after object"); - return j; - } - if (pyjslib_slice(str, j, j + 1) != ",") { - return j; - } - var i = this.object(str, j + 1, res); - if (i < 0) { - return i; - } - } + + XMLStringifier.prototype.attValue = function(val) { + val = '' + val || ''; + return this.attEscape(val); }; - __SinkParser.prototype.checkDot = function (str, i) { - var j = this.skipSpace(str, i); - if (j < 0) { - return j; - } - if (pyjslib_slice(str, j, j + 1) == ".") { - return j + 1; - } - if (pyjslib_slice(str, j, j + 1) == "}") { - return j; - } - if (pyjslib_slice(str, j, j + 1) == "]") { - return j; - } - throw BadSyntax(this._thisDoc, this.lines, str, j, "expected '.' or '}' or ']' at end of statement"); - return i; + + XMLStringifier.prototype.insTarget = function(val) { + return '' + val || ''; }; - __SinkParser.prototype.uri_ref2 = function (str, i, res) { - /* - Generate uri from n3 representation. - Note that the RDF convention of directly concatenating - NS and local name is now used though I prefer inserting a '#' - to make the namesapces look more like what XML folks expect. - */ - var qn = new pyjslib_List([]); - var j = this.qname(str, i, qn); - if (j >= 0) { - var pairFudge = qn[0]; - var pfx = pairFudge[0]; - var ln = pairFudge[1]; - if (pfx == null) { - assertFudge(0, "not used?"); - var ns = this._baseURI + ADDED_HASH; - } else { - var ns = this._bindings[pfx]; - if (!ns) { - if (pfx == "_") { - res.push(this.anonymousNode(ln)); - return j; - } - throw BadSyntax(this._thisDoc, this.lines, str, i, "Prefix " + pfx + " not bound."); - } - } - var symb = this._store.sym(ns + ln); - if (ArrayIndexOf(this._variables, symb) >= 0) { - res.push(this._variables[symb]); - } else { - res.push(symb); - } - return j; - } - var i = this.skipSpace(str, i); - if (i < 0) { - return -1; - } - if (str.charAt(i) == "?") { - var v = new pyjslib_List([]); - var j = this.variable(str, i, v); - if (j > 0) { - res.push(v[0]); - return j; - } - return -1; - } else if (str.charAt(i) == "<") { - var i = i + 1; - var st = i; - while (i < pyjslib_len(str)) { - if (str.charAt(i) == ">") { - var uref = pyjslib_slice(str, st, i); - if (this._baseURI) { - var uref = uripath_join(this._baseURI, uref); - } else { - assertFudge(uref.indexOf(":") >= 0, "With no base URI, cannot deal with relative URIs"); - } - if (pyjslib_slice(str, i - 1, i) == "#" && !(pyjslib_slice(uref, -1, null) == "#")) { - var uref = uref + "#"; - } - var symb = this._store.sym(uref); - if (ArrayIndexOf(this._variables, symb) >= 0) { - res.push(this._variables[symb]); - } else { - res.push(symb); - } - return i + 1; - } - var i = i + 1; - } - throw BadSyntax(this._thisDoc, this.lines, str, j, "unterminated URI reference"); - } else if (this.keywordsSet) { - var v = new pyjslib_List([]); - var j = this.bareWord(str, i, v); - if (j < 0) { - return -1; - } - if (ArrayIndexOf(this.keywords, v[0]) >= 0) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "Keyword \"" + v[0] + "\" not allowed here."); - } - res.push(this._store.sym(this._bindings[""] + v[0])); - return j; - } else { - return -1; - } + XMLStringifier.prototype.insValue = function(val) { + val = '' + val || ''; + if (val.match(/\?>/)) { + throw new Error("Invalid processing instruction value: " + val); + } + return val; }; - __SinkParser.prototype.skipSpace = function (str, i) { - /* - Skip white space, newlines and comments. - return -1 if EOF, else position of first non-ws character*/ - var whitespace = ' \n\r\t\f\x0B\xA0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u200B\u2028\u2029\u3000'; - for (var j = i ? i : 0; j < str.length; j++) { - var ch = str.charAt(j); - // console.log(" skipspace j= "+j + " i= " + i + " n= " + str.length); - // console.log(" skipspace ch <" + ch + ">"); - if (whitespace.indexOf(ch) < 0) { - //not ws - // console.log(" skipspace 2 ch <" + ch + ">"); - if (str.charAt(j) === '#') { - for (;; j++) { - // console.log(" skipspace2 j= "+j + " i= " + i + " n= " + str.length); - if (j === str.length) { - return -1; // EOF - } - if (str.charAt(j) === '\n') { - this.lines = this.lines + 1; - break; - } - }; - } else { - // Not hash - something interesting - // console.log(" skipspace 3 ch <" + ch + ">"); - return j; - } - } else { - // Whitespace - // console.log(" skipspace 5 ch <" + ch + ">"); - if (str.charAt(j) === '\n') { - this.lines = this.lines + 1; - } - } - } // next j - return -1; // EOF + XMLStringifier.prototype.xmlVersion = function(val) { + val = '' + val || ''; + if (!val.match(/1\.[0-9]+/)) { + throw new Error("Invalid version number: " + val); + } + return val; }; - __SinkParser.prototype.variable = function (str, i, res) { - /* - ?abc -> variable(:abc) - */ + XMLStringifier.prototype.xmlEncoding = function(val) { + val = '' + val || ''; + if (!val.match(/^[A-Za-z](?:[A-Za-z0-9._-]|-)*$/)) { + throw new Error("Invalid encoding: " + val); + } + return val; + }; - var j = this.skipSpace(str, i); - if (j < 0) { - return -1; - } - if (pyjslib_slice(str, j, j + 1) != "?") { - return -1; - } - var j = j + 1; - var i = j; - if ("0123456789-".indexOf(str.charAt(j)) >= 0) { - throw BadSyntax(this._thisDoc, this.lines, str, j, "Varible name can't start with '" + str.charAt(j) + "s'"); - return -1; - } - while (i < pyjslib_len(str) && _notNameChars.indexOf(str.charAt(i)) < 0) { - var i = i + 1; - } - if (this._parentContext == null) { - throw BadSyntax(this._thisDoc, this.lines, str, j, "Can't use ?xxx syntax for variable in outermost level: " + pyjslib_slice(str, j - 1, i)); - } - res.push(this._store.variable(pyjslib_slice(str, j, i))); - return i; + XMLStringifier.prototype.xmlStandalone = function(val) { + if (val) { + return "yes"; + } else { + return "no"; + } }; - __SinkParser.prototype.bareWord = function (str, i, res) { - /* - abc -> :abc - */ - var j = this.skipSpace(str, i); - if (j < 0) { - return -1; - } - var ch = str.charAt(j); - if ("0123456789-".indexOf(ch) >= 0) { - return -1; - } - if (_notNameChars.indexOf(ch) >= 0) { - return -1; - } - var i = j; - while (i < pyjslib_len(str) && _notNameChars.indexOf(str.charAt(i)) < 0) { - var i = i + 1; - } - res.push(pyjslib_slice(str, j, i)); - return i; + XMLStringifier.prototype.dtdPubID = function(val) { + return '' + val || ''; }; - __SinkParser.prototype.qname = function (str, i, res) { - /* - xyz:def -> ('xyz', 'def') - If not in keywords and keywordsSet: def -> ('', 'def') - :def -> ('', 'def') - */ - var i = this.skipSpace(str, i); - if (i < 0) { - return -1; - } - var c = str.charAt(i); - if ("0123456789-+".indexOf(c) >= 0) { - return -1; - } - if (_notNameChars.indexOf(c) < 0) { - var ln = c; - var i = i + 1; - while (i < pyjslib_len(str)) { - var c = str.charAt(i); - if (_notNameChars.indexOf(c) < 0) { - var ln = ln + c; - var i = i + 1; - } else { - break; - } - } - } else { - var ln = ""; - } - if (i < pyjslib_len(str) && str.charAt(i) == ":") { - var pfx = ln; - var i = i + 1; - var ln = ""; - while (i < pyjslib_len(str)) { - var c = str.charAt(i); - if (_notNameChars.indexOf(c) < 0) { - var ln = ln + c; - var i = i + 1; - } else { - break; - } - } - res.push(new pyjslib_Tuple([pfx, ln])); - return i; - } else { - if (ln && this.keywordsSet && ArrayIndexOf(this.keywords, ln) < 0) { - res.push(new pyjslib_Tuple(["", ln])); - return i; - } - return -1; - } + XMLStringifier.prototype.dtdSysID = function(val) { + return '' + val || ''; }; - __SinkParser.prototype.object = function (str, i, res) { - var j = this.subject(str, i, res); - if (j >= 0) { - return j; - } else { - var j = this.skipSpace(str, i); - if (j < 0) { - return -1; - } else { - var i = j; - } - if (str.charAt(i) == "\"") { - if (pyjslib_slice(str, i, i + 3) == "\"\"\"") { - var delim = "\"\"\""; - } else { - var delim = "\""; - } - var i = i + pyjslib_len(delim); - var pairFudge = this.strconst(str, i, delim); - var j = pairFudge[0]; - var s = pairFudge[1]; - res.push(this._store.literal(s)); - diag_progress("New string const ", s, j); - return j; - } else { - return -1; - } - } + + XMLStringifier.prototype.dtdElementValue = function(val) { + return '' + val || ''; }; - __SinkParser.prototype.nodeOrLiteral = function (str, i, res) { - var j = this.node(str, i, res); - if (j >= 0) { - return j; - } else { - var j = this.skipSpace(str, i); - if (j < 0) { - return -1; - } else { - var i = j; - } - var ch = str.charAt(i); - if ("-+0987654321".indexOf(ch) >= 0) { - datetime_syntax.lastIndex = 0; - var m = datetime_syntax.exec(str.slice(i)); - if (m != null) { - // j = ( i + datetime_syntax.lastIndex ) ; - var val = m[0]; - j = i + val.length; - if (val.indexOf("T") >= 0) { - res.push(this._store.literal(val, undefined, this._store.sym(DATETIME_DATATYPE))); - } else { - res.push(this._store.literal(val, undefined, this._store.sym(DATE_DATATYPE))); - } - } else { - number_syntax.lastIndex = 0; - var m = number_syntax.exec(str.slice(i)); - if (m == null) { - throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad number or date syntax"); - } - j = i + number_syntax.lastIndex; - var val = pyjslib_slice(str, i, j); - if (val.indexOf("e") >= 0) { - res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(FLOAT_DATATYPE))); - } else if (pyjslib_slice(str, i, j).indexOf(".") >= 0) { - res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(DECIMAL_DATATYPE))); - } else { - res.push(this._store.literal(parseInt(val), undefined, this._store.sym(INTEGER_DATATYPE))); - } - }; - return j; // Where we have got up to - } - if (str.charAt(i) == "\"") { - if (pyjslib_slice(str, i, i + 3) == "\"\"\"") { - var delim = "\"\"\""; - } else { - var delim = "\""; - } - var i = i + pyjslib_len(delim); - var dt = null; - var pairFudge = this.strconst(str, i, delim); - var j = pairFudge[0]; - var s = pairFudge[1]; - var lang = null; - if (pyjslib_slice(str, j, j + 1) == "@") { - langcode.lastIndex = 0; + XMLStringifier.prototype.dtdAttType = function(val) { + return '' + val || ''; + }; - var m = langcode.exec(str.slice(j + 1)); - if (m == null) { - throw BadSyntax(this._thisDoc, startline, str, i, "Bad language code syntax on string literal, after @"); - } - var i = langcode.lastIndex + j + 1; + XMLStringifier.prototype.dtdAttDefault = function(val) { + if (val != null) { + return '' + val || ''; + } else { + return val; + } + }; - var lang = pyjslib_slice(str, j + 1, i); - var j = i; - } - if (pyjslib_slice(str, j, j + 2) == "^^") { - var res2 = new pyjslib_List([]); - var j = this.uri_ref2(str, j + 2, res2); - var dt = res2[0]; - } - res.push(this._store.literal(s, lang, dt)); - return j; - } else { - return -1; - } - } + XMLStringifier.prototype.dtdEntityValue = function(val) { + return '' + val || ''; }; - __SinkParser.prototype.strconst = function (str, i, delim) { - /* - parse an N3 string constant delimited by delim. - return index, val - */ - var j = i; - var ustr = ""; - var startline = this.lines; - while (j < pyjslib_len(str)) { - var i = j + pyjslib_len(delim); - if (pyjslib_slice(str, j, i) == delim) { - return new pyjslib_Tuple([i, ustr]); - } - if (str.charAt(j) == "\"") { - var ustr = ustr + "\""; - var j = j + 1; - continue; - } - interesting.lastIndex = 0; - var m = interesting.exec(str.slice(j)); - if (!m) { - throw BadSyntax(this._thisDoc, startline, str, j, "Closing quote missing in string at ^ in " + pyjslib_slice(str, j - 20, j) + "^" + pyjslib_slice(str, j, j + 20)); - } - var i = j + interesting.lastIndex - 1; - var ustr = ustr + pyjslib_slice(str, j, i); - var ch = str.charAt(i); - if (ch == "\"") { - var j = i; - continue; - } else if (ch == "\r") { - var j = i + 1; - continue; - } else if (ch == "\n") { - if (delim == "\"") { - throw BadSyntax(this._thisDoc, startline, str, i, "newline found in string literal"); - } - this.lines = this.lines + 1; - var ustr = ustr + ch; - var j = i + 1; - this.previousLine = this.startOfLine; - this.startOfLine = j; - } else if (ch == "\\") { - var j = i + 1; - var ch = pyjslib_slice(str, j, j + 1); - if (!ch) { - throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal (2)"); - } - var k = string_find("abfrtvn\\\"", ch); - if (k >= 0) { - var uch = "\a\b\f\r\t\v\n\\\"".charAt(k); - var ustr = ustr + uch; - var j = j + 1; - } else if (ch == "u") { - var pairFudge = this.uEscape(str, j + 1, startline); - var j = pairFudge[0]; - var ch = pairFudge[1]; - var ustr = ustr + ch; - } else if (ch == "U") { - var pairFudge = this.UEscape(str, j + 1, startline); - var j = pairFudge[0]; - var ch = pairFudge[1]; - var ustr = ustr + ch; - } else { - throw BadSyntax(this._thisDoc, this.lines, str, i, "bad escape"); - } - } - } - throw BadSyntax(this._thisDoc, this.lines, str, i, "unterminated string literal"); + XMLStringifier.prototype.dtdNData = function(val) { + return '' + val || ''; }; - __SinkParser.prototype.uEscape = function (str, i, startline) { - var j = i; - var count = 0; - var value = 0; - while (count < 4) { - var chFudge = pyjslib_slice(str, j, j + 1); - var ch = chFudge.toLowerCase(); - var j = j + 1; - if (ch == "") { - throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal(3)"); - } - var k = string_find("0123456789abcdef", ch); - if (k < 0) { - throw BadSyntax(this._thisDoc, startline, str, i, "bad string literal hex escape"); - } - var value = value * 16 + k; - var count = count + 1; - } - var uch = String.fromCharCode(value); - return new pyjslib_Tuple([j, uch]); - }; - __SinkParser.prototype.UEscape = function (str, i, startline) { - var j = i; - var count = 0; - var value = '\\U'; - while (count < 8) { - var chFudge = pyjslib_slice(str, j, j + 1); - var ch = chFudge.toLowerCase(); - var j = j + 1; - if (ch == "") { - throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal(3)"); - } - var k = string_find("0123456789abcdef", ch); - if (k < 0) { - throw BadSyntax(this._thisDoc, startline, str, i, "bad string literal hex escape"); - } - var value = value + ch; - var count = count + 1; - } - var uch = stringFromCharCode("0x" + pyjslib_slice(value, 2, 10) - 0); - return new pyjslib_Tuple([j, uch]); - }; - function OLD_BadSyntax(uri, lines, str, i, why) { - return new __OLD_BadSyntax(uri, lines, str, i, why); - } - function __OLD_BadSyntax(uri, lines, str, i, why) { - this._str = str.encode("utf-8"); - this._str = str; - this._i = i; - this._why = why; - this.lines = lines; - this._uri = uri; - } - __OLD_BadSyntax.prototype.toString = function () { - var str = this._str; - var i = this._i; - var st = 0; - if (i > 60) { - var pre = "..."; - var st = i - 60; - } else { - var pre = ""; - } - if (pyjslib_len(str) - i > 60) { - var post = "..."; - } else { - var post = ""; - } - return "Line %i of <%s>: Bad syntax (%s) at ^ in:\n\"%s%s^%s%s\"" % new pyjslib_Tuple([this.lines + 1, this._uri, this._why, pre, pyjslib_slice(str, st, i), pyjslib_slice(str, i, i + 60), post]); - }; - function BadSyntax(uri, lines, str, i, why) { - return "Line " + (lines + 1) + " of <" + uri + ">: Bad syntax: " + why + "\nat: \"" + pyjslib_slice(str, i, i + 30) + "\""; - } - - function stripCR(str) { - var res = ""; - var __ch = new pyjslib_Iterator(str); - try { - while (true) { - var ch = __ch.next(); + XMLStringifier.prototype.convertAttKey = '@'; - if (ch != "\r") { - var res = res + ch; - } - } - } catch (e) { - if (e != StopIteration) { - throw e; - } - } + XMLStringifier.prototype.convertPIKey = '?'; - return res; - } + XMLStringifier.prototype.convertTextKey = '#text'; - function dummyWrite(x) {} + XMLStringifier.prototype.convertCDataKey = '#cdata'; - return SinkParser; -}(); + XMLStringifier.prototype.convertCommentKey = '#comment'; -module.exports = N3Parser; -},{"./uri":72,"./util":73}],57:[function(_dereq_,module,exports){ -'use strict'; + XMLStringifier.prototype.convertRawKey = '#raw'; -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + XMLStringifier.prototype.assertLegalChar = function(str) { + var res; + res = str.match(/[\0\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/); + if (res) { + throw new Error("Invalid character in string: " + str + " at index " + res.index); + } + return str; + }; -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + XMLStringifier.prototype.elEscape = function(str) { + var ampregex; + ampregex = this.noDoubleEncoding ? /(?!&\S+;)&/g : /&/g; + return str.replace(ampregex, '&').replace(//g, '>').replace(/\r/g, ' '); + }; -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + XMLStringifier.prototype.attEscape = function(str) { + var ampregex; + ampregex = this.noDoubleEncoding ? /(?!&\S+;)&/g : /&/g; + return str.replace(ampregex, '&').replace(/= 0 && p < q + 2 || p < 0) return null; - return new NamedNode(str.slice(0, p + 1)); - } - /** - * Returns an NN for the whole web site, ending in slash. - * Contrast with the "origin" which does NOT have a trailing slash - */ + XMLText.prototype.toString = function(options) { + return this.options.writer.set(options).text(this); + }; - }, { - key: 'site', - value: function site() { - var str = this.uri.split('#')[0]; - var p = str.indexOf('//'); - if (p < 0) throw new Error('This URI does not have a web site part (origin)'); - var q = str.indexOf('/', p + 2); - if (q < 0) throw new Error('This URI does not have a web site part. (origin)'); - return new NamedNode(str.slice(0, q + 1)); - } - }, { - key: 'doc', - value: function doc() { - if (this.uri.indexOf('#') < 0) { - return this; + return XMLText; + + })(XMLNode); + +}).call(this); + +},{"./XMLNode":76}],83:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLWriterBase, + hasProp = {}.hasOwnProperty; + + module.exports = XMLWriterBase = (function() { + function XMLWriterBase(options) { + var key, ref, ref1, ref2, ref3, ref4, ref5, ref6, value; + options || (options = {}); + this.pretty = options.pretty || false; + this.allowEmpty = (ref = options.allowEmpty) != null ? ref : false; + if (this.pretty) { + this.indent = (ref1 = options.indent) != null ? ref1 : ' '; + this.newline = (ref2 = options.newline) != null ? ref2 : '\n'; + this.offset = (ref3 = options.offset) != null ? ref3 : 0; + this.dontprettytextnodes = (ref4 = options.dontprettytextnodes) != null ? ref4 : 0; } else { - return new NamedNode(this.uri.split('#')[0]); + this.indent = ''; + this.newline = ''; + this.offset = 0; + this.dontprettytextnodes = 0; + } + this.spacebeforeslash = (ref5 = options.spacebeforeslash) != null ? ref5 : ''; + if (this.spacebeforeslash === true) { + this.spacebeforeslash = ' '; + } + this.newlinedefault = this.newline; + this.prettydefault = this.pretty; + ref6 = options.writer || {}; + for (key in ref6) { + if (!hasProp.call(ref6, key)) continue; + value = ref6[key]; + this[key] = value; } - } - }, { - key: 'toString', - value: function toString() { - return '<' + this.uri + '>'; } - /** - * Legacy getter and setter alias, node.uri - */ - - }, { - key: 'uri', - get: function get() { - return this.value; - }, - set: function set(uri) { - this.value = uri; - } - }], [{ - key: 'fromValue', - value: function fromValue(value) { - if (typeof value === 'undefined' || value === null) { - return value; + XMLWriterBase.prototype.set = function(options) { + var key, ref, value; + options || (options = {}); + if ("pretty" in options) { + this.pretty = options.pretty; } - var isNode = value && value.termType; - if (isNode) { - return value; + if ("allowEmpty" in options) { + this.allowEmpty = options.allowEmpty; } - return new NamedNode(value); - } - }]); + if (this.pretty) { + this.indent = "indent" in options ? options.indent : ' '; + this.newline = "newline" in options ? options.newline : '\n'; + this.offset = "offset" in options ? options.offset : 0; + this.dontprettytextnodes = "dontprettytextnodes" in options ? options.dontprettytextnodes : 0; + } else { + this.indent = ''; + this.newline = ''; + this.offset = 0; + this.dontprettytextnodes = 0; + } + this.spacebeforeslash = "spacebeforeslash" in options ? options.spacebeforeslash : ''; + if (this.spacebeforeslash === true) { + this.spacebeforeslash = ' '; + } + this.newlinedefault = this.newline; + this.prettydefault = this.pretty; + ref = options.writer || {}; + for (key in ref) { + if (!hasProp.call(ref, key)) continue; + value = ref[key]; + this[key] = value; + } + return this; + }; - return NamedNode; -}(Node); + XMLWriterBase.prototype.space = function(level) { + var indent; + if (this.pretty) { + indent = (level || 0) + this.offset + 1; + if (indent > 0) { + return new Array(indent).join(this.indent); + } else { + return ''; + } + } else { + return ''; + } + }; -NamedNode.termType = 'NamedNode'; -NamedNode.prototype.classOrder = ClassOrder['NamedNode']; -NamedNode.prototype.isVar = 0; + return XMLWriterBase; -module.exports = NamedNode; -},{"./class-order":43,"./node":59}],58:[function(_dereq_,module,exports){ -'use strict'; + })(); -var NamedNode = _dereq_('./named-node'); +}).call(this); -function Namespace(nsuri) { - return function (ln) { - return new NamedNode(nsuri + (ln || '')); - }; -} +},{}],84:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.6 +(function() { + var XMLDocument, XMLDocumentCB, XMLStreamWriter, XMLStringWriter, assign, isFunction, ref; -module.exports = Namespace; -},{"./named-node":57}],59:[function(_dereq_,module,exports){ -'use strict'; -/** - * The superclass of all RDF Statement objects, that is - * NamedNode, Literal, BlankNode, etc. - * @class Node - */ + ref = _dereq_('./Utility'), assign = ref.assign, isFunction = ref.isFunction; -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + XMLDocument = _dereq_('./XMLDocument'); -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + XMLDocumentCB = _dereq_('./XMLDocumentCB'); -var Node = function () { - function Node() { - _classCallCheck(this, Node); - } + XMLStringWriter = _dereq_('./XMLStringWriter'); - _createClass(Node, [{ - key: 'substitute', - value: function substitute(bindings) { - console.log('@@@ node substitute' + this); - return this; - } - }, { - key: 'compareTerm', - value: function compareTerm(other) { - if (this.classOrder < other.classOrder) { - return -1; - } - if (this.classOrder > other.classOrder) { - return +1; - } - if (this.value < other.value) { - return -1; - } - if (this.value > other.value) { - return +1; - } - return 0; + XMLStreamWriter = _dereq_('./XMLStreamWriter'); + + module.exports.create = function(name, xmldec, doctype, options) { + var doc, root; + if (name == null) { + throw new Error("Root element needs a name"); } - }, { - key: 'equals', - value: function equals(other) { - if (!other) { - return false; + options = assign({}, xmldec, doctype, options); + doc = new XMLDocument(options); + root = doc.element(name); + if (!options.headless) { + doc.declaration(options); + if ((options.pubID != null) || (options.sysID != null)) { + doc.doctype(options); } - return this.termType === other.termType && this.value === other.value; - } - }, { - key: 'hashString', - value: function hashString() { - return this.toCanonical(); - } - }, { - key: 'sameTerm', - value: function sameTerm(other) { - return this.equals(other); - } - }, { - key: 'toCanonical', - value: function toCanonical() { - return this.toNT(); } - }, { - key: 'toNT', - value: function toNT() { - return this.toString(); + return root; + }; + + module.exports.begin = function(options, onData, onEnd) { + var ref1; + if (isFunction(options)) { + ref1 = [options, onData], onData = ref1[0], onEnd = ref1[1]; + options = {}; } - }, { - key: 'toString', - value: function toString() { - throw new Error('Node.toString() is abstract - see the subclasses instead'); + if (onData) { + return new XMLDocumentCB(options, onData, onEnd); + } else { + return new XMLDocument(options); } - }]); + }; - return Node; -}(); + module.exports.stringWriter = function(options) { + return new XMLStringWriter(options); + }; -module.exports = Node; + module.exports.streamWriter = function(stream, options) { + return new XMLStreamWriter(stream, options); + }; -/** - * Creates an RDF Node from a native javascript value. - * RDF Nodes are returned unchanged, undefined returned as itself. - * @method fromValue - * @static - * @param value {Node|Date|String|Number|Boolean|Undefined} - * @return {Node|Collection} - */ -Node.fromValue = function fromValue(value) { - var Collection = _dereq_('./collection'); - var Literal = _dereq_('./literal'); - var NamedNode = _dereq_('./named-node'); - if (typeof value === 'undefined' || value === null) { - return value; - } - var isNode = value && value.termType; - if (isNode) { - // a Node subclass or a Collection - return value; - } - if (Array.isArray(value)) { - return new Collection(value); - } - return Literal.fromValue(value); +}).call(this); + +},{"./Utility":63,"./XMLDocument":73,"./XMLDocumentCB":74,"./XMLStreamWriter":79,"./XMLStringWriter":80}],85:[function(_dereq_,module,exports){ +var N3 = _dereq_('n3'); + +var ns = {}; + +ns.prefixes = { rdf: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + bqmodel: "http://biomodels.net/model-qualifiers/", + bqbiol: "http://biomodels.net/biology-qualifiers/", + sio: "http://semanticscience.org/resource/", + eisbm: "http://www.eisbm.org/"}; + +// pure shortcut function +ns.expandPrefix = function(prefix) { + return N3.Util.expandPrefixedName(prefix, ns.prefixes) }; -},{"./collection":44,"./literal":54,"./named-node":57}],60:[function(_dereq_,module,exports){ -'use strict'; -module.exports = parse; +// commonly used strings +str_sio223 = "sio:SIO_000223"; +str_sio223exp = ns.expandPrefix(str_sio223); +str_sio116 = "sio:SIO_000116"; +str_sio116exp = ns.expandPrefix(str_sio116); +str_rdfvalue = "rdf:value"; +str_rdfvalueexp = ns.expandPrefix(str_rdfvalue); +str_rdftype = "rdf:type"; +str_rdftypeexp = ns.expandPrefix(str_rdftype); +str_rdfbag = "rdf:Bag"; +str_rdfbagexp = ns.expandPrefix(str_rdfbag); -var BlankNode = _dereq_('./blank-node'); -var jsonld = _dereq_('jsonld'); -var Literal = _dereq_('./literal'); -var N3 = _dereq_('n3'); // @@ Goal: remove this dependency -var N3Parser = _dereq_('./n3parser'); -var NamedNode = _dereq_('./named-node'); -var parseRDFaDOM = _dereq_('./rdfaparser').parseRDFaDOM; -var RDFParser = _dereq_('./rdfxmlparser'); -var sparqlUpdateParser = _dereq_('./patch-parser'); -var Util = _dereq_('./util'); +controlledVocabularyList = [ + "bqmodel:is", + "bqmodel:isDerivedFrom", + "bqmodel:isDescribedBy", + "bqmodel:isInstanceOf", + "bqmodel:hasInstance", -/** - * Parse a string and put the result into the graph kb. - * Normal method is sync. - * Unfortunately jsdonld is currently written to need to be called async. - * Hence the mess below with executeCallback. - */ -function parse(str, kb, base, contentType, callback) { - contentType = contentType || 'text/turtle'; - try { - if (contentType === 'text/n3' || contentType === 'text/turtle') { - var p = N3Parser(kb, kb, base, base, null, null, '', null); - p.loadBuf(str); - executeCallback(); - } else if (contentType === 'application/rdf+xml') { - var parser = new RDFParser(kb); - parser.parse(Util.parseXML(str), base, kb.sym(base)); - executeCallback(); - } else if (contentType === 'application/xhtml+xml') { - parseRDFaDOM(Util.parseXML(str, { contentType: 'application/xhtml+xml' }), kb, base); - executeCallback(); - } else if (contentType === 'text/html') { - parseRDFaDOM(Util.parseXML(str, { contentType: 'text/html' }), kb, base); - executeCallback(); - } else if (contentType === 'application/sparql-update') { - // @@ we handle a subset - sparqlUpdateParser(str, kb, base); - executeCallback(); - } else if (contentType === 'application/ld+json' || contentType === 'application/nquads' || contentType === 'application/n-quads') { - var n3Parser = N3.Parser(); - var triples = []; - if (contentType === 'application/ld+json') { - var jsonDocument; - try { - jsonDocument = JSON.parse(str); - } catch (parseErr) { - callback(parseErr, null); - } - jsonld.toRDF(jsonDocument, { format: 'application/nquads' }, nquadCallback); - } else { - nquadCallback(null, str); - } - } else { - throw new Error("Don't know how to parse " + contentType + ' yet'); - } - } catch (e) { - executeErrorCallback(e); - } + "bqbiol:is", + "bqbiol:encodes", + "bqbiol:hasPart", + "bqbiol:hasProperty", + "bqbiol:hasVersion", + "bqbiol:isDescribedBy", + "bqbiol:isEncodedBy", + "bqbiol:isHomologTo", + "bqbiol:isPartOf", + "bqbiol:isPropertyOf", + "bqbiol:isVersionOf", + "bqbiol:occursIn", + "bqbiol:hasTaxon", - function executeCallback() { - if (callback) { - callback(null, kb); - } else { - return; - } - } + "sio:SIO_000223" +]; - function executeErrorCallback(e) { - if (contentType !== 'application/ld+json' || contentType !== 'application/nquads' || contentType !== 'application/n-quads') { - if (callback) { - callback(e, kb); - } else { - throw new Error('Error trying to parse <' + base + '> as ' + contentType + ':\n' + e + ':\n' + e.stack); - } - } - } - /* - function setJsonLdBase (doc, base) { - if (doc instanceof Array) { - return - } - if (!('@context' in doc)) { - doc['@context'] = {} - } - doc['@context']['@base'] = base - } - */ - function nquadCallback(err, nquads) { - if (err) { - callback(err, kb); - } - try { - n3Parser.parse(nquads, tripleCallback); - } catch (err) { - callback(err, kb); - } - } +ns.isControlledVocabulary = {}; +for(var i=0; i patch:where {xxx}; patch:delete {yyy}; patch:insert {zzz}. -module.exports = sparqlUpdateParser; +/** + * will add triples to represent key/value properties attached to the id + * kvObject can have one or multiple properties + */ +ns.addCustomProperty = function (graph, id, kvObject) { + var sio223Element = ns.getRelationship(graph, id, str_sio223)[0]; // doesn't matter if more than one + //console.log("add kv to", hasPropElement); + for(var key in kvObject) { + // using elemnt count as index may be dangerous if previous manipulation of + // the elements has happened. Like removing one. + var propIndex = ns.countBagElements(graph, sio223Element) + 1; + //console.log("elements in bag:", propIndex); + var newBlank = graph.createBlankNode(); + //console.log("expand list element", ns.expandPrefix("rdf:_"+propIndex)); + graph.addTriple(sio223Element, ns.expandPrefix("rdf:_"+propIndex), newBlank); + graph.addTriple(newBlank, str_sio116exp, N3.Util.createLiteral(key)); + graph.addTriple(newBlank, str_rdfvalueexp, N3.Util.createLiteral(kvObject[key])); + //console.log("added", key, kvObject[key]); + } +}; -var N3Parser = _dereq_('./n3parser'); -var Namespace = _dereq_('./namespace'); +ns.hasRelationship = function (graph, id, relationship) { + var countProp = graph.countTriples(id, relationship, null); + return countProp > 0; +}; -function sparqlUpdateParser(str, kb, base) { - var i, j, k; - var keywords = ['INSERT', 'DELETE', 'WHERE']; - var SQNS = Namespace('http://www.w3.org/ns/pim/patch#'); - var p = N3Parser(kb, kb, base, base, null, null, '', null); - var clauses = {}; +ns.countBagElements = function(graph, subject) { + return graph.countTriples(subject, null, null) - 1; +}; - var badSyntax = function badSyntax(uri, lines, str, i, why) { - return 'Line ' + (lines + 1) + ' of <' + uri + '>: Bad syntax:\n ' + why + '\n at: "' + str.slice(i, i + 30) + '"'; - }; +ns.getResourcesOfId = function(graph, id) { + var result = {}; + graph.forEach(function(init_triple){ // iterate over all id relationships + // we want everything that is not a simpel key/value property + if(init_triple.predicate != str_sio223exp) { + var relation = init_triple.predicate; + // initialize relation array if never encountered before + if(!result.hasOwnProperty(relation)) { + result[relation] = []; + } - // var check = function (next, last, message) { - // if (next < 0) { - // throw badSyntax(p._thisDoc, p.lines, str, j, last, message) - // } - // return next - // } - i = 0; - var query = kb.sym(base + '#query'); // Invent a URI for the query - clauses['query'] = query; // A way of accessing it in its N3 model. + // if multiple resources specified, or a single element with several attributes, + // blank node is involved, possibly with a bag attribute + if(N3.Util.isBlank(init_triple.object)) { + var resourceContainer = init_triple.object; + graph.forEach(function(triple){ // iterate over the elements of the relationship + // relationship may be a bag, and thus contains undesirable rdf:type bag line + if(triple.object != str_rdfbagexp) { + var resource = triple.object; + result[relation].push(resource); + } + }, resourceContainer, null, null); + } + else { + // simple case, no bag, only 1 resource is linked with 1 attribute + var resource = init_triple.object; + result[relation].push(resource); + } + } + }, id, null, null); + return result; +}; - while (true) { - // console.log("A Now at i = " + i) - j = p.skipSpace(str, i); - if (j < 0) { - return clauses; - } - // console.log("B After space at j= " + j) - if (str[j] === ';') { - i = p.skipSpace(str, j + 1); - if (i < 0) { - return clauses; // Allow end in a - } - j = i; - } - var found = false; - for (k = 0; k < keywords.length; k++) { - var key = keywords[k]; - if (str.slice(j, j + key.length) === key) { - i = p.skipSpace(str, j + key.length); - if (i < 0) { - throw badSyntax(p._thisDoc, p.lines, str, j + key.length, 'found EOF, needed {...} after ' + key); - } - if ((key === 'INSERT' || key === 'DELETE') && str.slice(i, i + 4) === 'DATA') { - // Some wanted 'DATA'. Whatever - j = p.skipSpace(str, i + 4); - if (j < 0) { - throw badSyntax(p._thisDoc, p.lines, str, i + 4, 'needed {...} after INSERT DATA ' + key); - } - i = j; - } - var res2 = []; - j = p.node(str, i, res2); // Parse all the complexity of the clause +/** + * returns the id of a newly created blank node representing the HasProperty predicate + * if one already exists, returns its id + * returns array, potentially several SIO223 present + */ +ns.getRelationship = function (graph, id, relationship) { + if (ns.hasRelationship(graph, id, relationship)) { + var object = graph.getObjects(id, relationship, null)[0]; // careful here + if (!N3.Util.isBlank(object)){ + // object of relationship isn't a bag. Need to turn it into a bag. + var newBag = ns.createBag(graph, id, relationship); + graph.addTriple(id, relationship, newBag); + graph.addTriple(newBag, ns.expandPrefix("rdf:_1"), object); + return [newBag]; + } + else { + return graph.getObjects(id, relationship, null); + } + } + else { + return [ns.createBag(graph, id, relationship)]; + } +}; - if (j < 0) { - throw badSyntax(p._thisDoc, p.lines, str, i, 'bad syntax or EOF in {...} after ' + key); - } - clauses[key.toLowerCase()] = res2[0]; - kb.add(query, SQNS(key.toLowerCase()), res2[0]); // , kb.sym(base) - // key is the keyword and res2 has the contents - found = true; - i = j; - } - } - if (!found && str.slice(j, j + 7) === '@prefix') { - i = p.directive(str, j); - if (i < 0) { - throw badSyntax(p._thisDoc, p.lines, str, i, 'bad syntax or EOF after @prefix '); - } - // console.log("P before dot i= " + i) - i = p.checkDot(str, i); - // console.log("Q after dot i= " + i) - found = true; - } - if (!found) { - // console.log("Bad syntax " + j) - throw badSyntax(p._thisDoc, p.lines, str, j, "Unknown syntax at start of statememt: '" + str.slice(j).slice(0, 20) + "'"); - } - } // while - // return clauses -} -},{"./n3parser":56,"./namespace":58}],62:[function(_dereq_,module,exports){ -'use strict'; +ns.createBag = function (graph, id, relationship) { + var newBlank = graph.createBlankNode(); + graph.addTriple(id, ns.expandPrefix(relationship), newBlank); + graph.addTriple(newBlank, str_rdftypeexp, str_rdfbagexp); + return newBlank; +}; -var log = _dereq_('./log'); +/** + * kvobject contains biology qualifier as key and miriam resource as value + */ +ns.addResource = function (graph, id, kvObject) { + for(var relation in kvObject) { + //console.log("relation", relation); + var relationElement = ns.getRelationship(graph, id, relation)[0]; // doesn't matter if more than one + //console.log("after get relation",relationElement, graph.getTriples(id, relation)); + //console.log("after get realtion", graph.getTriples()); + // using elemnt count as index may be dangerous if previous manipulation of + // the elements has happened. Like removing one. + var propIndex = ns.countBagElements(graph, relationElement) + 1; + //console.log("elements in bag:", propIndex); + //console.log("new blank node", graph.getTriples()); + //console.log("Will add", relationElement, ns.expandPrefix("rdf:_"+propIndex), kvObject[relation]); + graph.addTriple(relationElement, ns.expandPrefix("rdf:_"+propIndex), kvObject[relation]); + //console.log("end result", graph.getTriples()); + //console.log("added", relation, kvObject[relation]); + } +}; -function queryToSPARQL(query) { - var indent = 0; - function getSelect(query) { - var str = addIndent() + 'SELECT '; - for (var i = 0; i < query.vars.length; i++) { - str += query.vars[i] + ' '; - } - str += '\n'; - return str; - } +module.exports = ns; +},{"n3":230}],86:[function(_dereq_,module,exports){ +/** + * This submodule manages the annotations extension. It adds the ability to save semantic data into + * SBGN-ML in the form of RDF elements. Any SBGN element that can host an extension tag can also + * get RDF annotations. This means that almost every element can get annotated. + * + * The annotations here are intended to be used in two ways: + * - with controlled vocabulary and resources, as suggested by COMBINE, with the help of MIRIAM + * identifiers. + * - as a mean to attach arbitrary data in the form of key-value properties. + * + * # Controlled vocabulary + * + * The formal way of using annotations is to use specific vocabulary with specific identifiers to + * provide additional information that can not be conveyed otherwise through the SBGN format. + * See --link to combine qualifiers-- and --link to identifiers.org and MIRIAM--- + * This was also based on the annotation extension of SBML --link to annotation proposal for SBML-- + * + * + * See {@link Extension} for more general information on extensions in the SBGN-ML format. + * + * You can access the following classes like this: libsbgn.annot.Annotation + * + * @module libsbgn-annotations + * @namespace libsbgn.annot +*/ - function getPattern(pat) { - var str = ''; - var st = pat.statements; - for (var x in st) { - log.debug('Found statement: ' + st); - str += addIndent() + st[x] + '\n'; - } - return str; - } +var checkParams = _dereq_('./utilities').checkParams; +var $rdf = _dereq_('rdflib'); +var N3 = _dereq_('n3'); +var Util = _dereq_('./annotation-utils'); +var utils = _dereq_('./utilities'); - function getConstraints(pat) { - var str = ''; - for (var v in pat.constraints) { - var foo = pat.constraints[v]; - str += addIndent() + 'FILTER ( ' + foo.describe(v) + ' ) ' + '\n'; - } - return str; - } +var ns = {}; - function getOptionals(pat) { - var str = ''; - for (var x = 0; x < pat.optional.length; x++) { - // alert(pat.optional.termType) - log.debug('Found optional query'); - str += addIndent() + 'OPTIONAL { ' + '\n'; - indent++; - str += getPattern(pat.optional[x]); - str += getConstraints(pat.optional[x]); - str += getOptionals(pat.optional[x]); - indent--; - str += addIndent() + '}' + '\n'; - } - return str; - } +//ns.xmlns = "http://www.sbml.org/sbml/level3/version1/render/version1"; - function getWhere(pat) { - var str = addIndent() + 'WHERE \n' + '{ \n'; - indent++; - str += getPattern(pat); - str += getConstraints(pat); - str += getOptionals(pat); - indent--; - str += '}'; - return str; - } +// ------- ANNOTATION ------- +/** + * Represents the <annotation> element. + * @class + * @param {Object} params + * @param {RdfElement=} params.rdfElement + */ +var Annotation = function (params) { + var params = checkParams(params, ['rdfElement']); + this.rdfElement = params.rdfElement; +}; - function addIndent() { - var str = ''; - for (var i = 0; i < indent; i++) { - str += ' '; - } - return str; - } +/** + * @param {RdfElement} rdfElement + */ +Annotation.prototype.setRdfElement = function(rdfElement) { + this.rdfElement = rdfElement; +}; - function getSPARQL(query) { - return getSelect(query) + getWhere(query.pat); - } +Annotation.prototype.buildJsObj = function () { + var annotationJsonObj = {}; - return getSPARQL(query); -} + if(this.rdfElement != null) { + annotationJsonObj = this.rdfElement.buildJsObj(); + } -module.exports = queryToSPARQL; -},{"./log":55}],63:[function(_dereq_,module,exports){ -'use strict'; + return annotationJsonObj; +}; -var _indexedFormula = _dereq_('./indexed-formula'); +/** + * @return {string} + */ +Annotation.prototype.toXML = function() { + return utils.buildString({annotation: this.buildJsObj()}) +}; -var _indexedFormula2 = _interopRequireDefault(_indexedFormula); +Annotation.fromXML = function (string) { + var annotation; + function fn (err, result) { + annotation = Annotation.fromObj(result); + }; + utils.parseStringKeepPrefix(string, fn); + return annotation; +}; -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +Annotation.fromObj = function (jsObj) { + if (typeof jsObj.annotation == 'undefined') { + throw new Error("Bad XML provided, expected tagName annotation, got: " + Object.keys(jsObj)[0]); + } -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // Matching a formula against another formula -// Assync as well as Synchronously -// -// W3C open source licence 2005. -// -// This builds on term.js, match.js (and identity.js?) -// to allow a query of a formula. -// -// Here we introduce for the first time a subclass of term: variable. -// -// SVN ID: $Id: query.js 25116 2008-11-15 16:13:48Z timbl $ + var annotation = new ns.Annotation(); + jsObj = jsObj.annotation; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return annotation; + } -// Variable -// -// Compare with BlankNode. They are similar, but a variable -// stands for something whose value is to be returned. -// Also, users name variables and want the same name back when stuff is printed -/* jsl:option explicit*/ // Turn on JavaScriptLint variable declaration checking + // children + if(jsObj['rdf:RDF']) { + var obj = {}; + obj['rdf:RDF'] = jsObj['rdf:RDF'][0]; + var rdf = ns.RdfElement.fromObj(obj); + annotation.setRdfElement(rdf); + } -var log = _dereq_('./log'); -var docpart = _dereq_('./uri').docpart; + return annotation; +}; -/** - * Query class, for tracking queries the user has in the UI. - */ +ns.Annotation = Annotation; +// ------- END ANNOTATION ------- -var Query = function Query(name, id) { - _classCallCheck(this, Query); +// ------- STOREOBJECT ------- +var StoreObject = function (params) { + var params = checkParams(params, ['store']); + if (params.store) { + this.store = params.store; + } + else { + var store = N3.Store(); + store.addPrefixes(Util.prefixes); + this.store = store; + } +}; - this.pat = new _indexedFormula2.default(); // The pattern to search for - this.vars = []; // Used by UI code but not in query.js - // this.orderBy = [] // Not used yet - this.name = name; - this.id = id; +StoreObject.prototype.getCustomPropertiesOfId = function (id) { + return Util.getCustomPropertiesOfId(this.store, id); }; -/** - * This function will match a pattern to the current kb - * - * The callback function is called whenever a match is found - * When fetcher is supplied this will be called to satisfy any resource requests - * currently not in the kb. The fetcher function needs to be defined manualy and - * should call $rdf.Util.AJAR_handleNewTerm to process the requested resource. - * - * @param myQuery, a knowledgebase containing a pattern to use as query - * @param callback, whenever the pattern in myQuery is met this is called with - * the new bindings as parameter - * @param fetcher, whenever a resource needs to be loaded this gets called IGNORED OBSOLETE - * f.fetecher is used as a Fetcher instance to do this. - * @param onDone callback when - */ +StoreObject.prototype.getAllIds = function () { + return Util.getAllIds(this.store); +}; +StoreObject.prototype.addCustomProperty = function (id, kvObject) { + return Util.addCustomProperty(this.store, id, kvObject); +}; -function indexedFormulaQuery(myQuery, callback, fetcher, onDone) { - // var kb = this - // /////////// Debug strings - var bindingDebug = function bindingDebug(b) { - var str = ''; - var v; - for (v in b) { - if (b.hasOwnProperty(v)) { - str += ' ' + v + ' -> ' + b[v]; - } - } - return str; - }; +StoreObject.prototype.getResourcesOfId = function(id) { + return Util.getResourcesOfId(this.store, id); +}; - var bindingsDebug = function bindingsDebug(nbs) { - var str = 'Bindings: '; - var i; - var n = nbs.length; - for (i = 0; i < n; i++) { - str += bindingDebug(nbs[i][0]) + ';\n\t'; - } - return str; - }; // bindingsDebug +StoreObject.prototype.addResource = function (id, kvObject) { + return Util.addResource(this.store, id, kvObject); +}; - // Unification: see also - // http://www.w3.org/2000/10/swap/term.py - // for similar things in python - // - // Unification finds all bindings such that when the binding is applied - // to one term it is equal to the other. - // Returns: a list of bindings, where a binding is an associative array - // mapping variuable to value. +ns.StoreObject = StoreObject; +// ------- END STOREOBJECT ------- - var unifyTerm = function unifyTerm(self, other, bindings, formula) { - var actual = bindings[self]; - if (actual === undefined) { - // Not mapped - if (self.isVar) { - /* if (self.isBlank) //bnodes are existential variables - { - if (self.toString() == other.toString()) return [[ [], null]] - else return [] - }*/ - var b = []; - b[self] = other; - return [[b, null]]; // Match - } - actual = self; - } - if (!actual.complexType) { - if (formula.redirections[actual]) { - actual = formula.redirections[actual]; - } - if (formula.redirections[other]) { - other = formula.redirections[other]; - } - if (actual.sameTerm(other)) { - return [[[], null]]; - } - return []; - } - if (self instanceof Array) { - if (!(other instanceof Array)) { - return []; - } - return unifyContents(self, other, bindings); - } - throw new Error('query.js: oops - code not written yet'); - // return undefined; // for lint - no jslint objects to unreachables - // return actual.unifyContents(other, bindings) - }; // unifyTerm +// ------- GLOBALSTORE ------- +var GlobalRdfStore = function (params) { + ns.StoreObject.call(this, params); +}; +GlobalRdfStore.prototype = Object.create(ns.StoreObject.prototype); +GlobalRdfStore.prototype.constructor = GlobalRdfStore; - var unifyContents = function unifyContents(self, other, bindings, formula) { - var nbs2; - if (self.length !== other.length) { - return []; // no way - } - if (!self.length) { - return [[[], null]]; // Success - } - var nbs = unifyTerm(self[0], other[0], bindings, formula); - if (nbs.length === 0) { - return nbs; - } - var res = []; - var i; - var n = nbs.length; - var nb; - var j; - var m; - var v; - var nb2; - var bindings2; - for (i = 0; i < n; i++) { - // for each possibility from the first term - nb = nbs[i][0]; // new bindings - bindings2 = []; - for (v in nb) { - if (nb.hasOwnProperty(v)) { - bindings2[v] = nb[v]; // copy - } - } - for (v in bindings) { - if (bindings.hasOwnProperty(v)) { - bindings2[v] = bindings[v]; // copy - } - } - nbs2 = unifyContents(self.slice(1), other.slice(1), bindings2, formula); - m = nbs2.length; - for (j = 0; j < m; j++) { - nb2 = nbs2[j][0]; // @@@@ no idea whether this is used or right - for (v in nb) { - if (nb.hasOwnProperty(v)) { - nb2[v] = nb[v]; - } - } - res.push([nb2, null]); - } - } - return res; - }; // unifyContents +GlobalRdfStore.prototype.load = function (annotations) { + for(var i=0; i<rd:RDFf> element. + * @class + */ +var RdfElement = function (params) { + ns.StoreObject.call(this, params); +}; +RdfElement.prototype = Object.create(ns.StoreObject.prototype); +RdfElement.prototype.constructor = RdfElement; - var union = function union(a, b) { - var c = {}; - var x; - for (x in a) { - if (a.hasOwnProperty(x)) { - c[x] = a[x]; - } - } - for (x in b) { - if (b.hasOwnProperty(x)) { - c[x] = b[x]; - } - } - return c; - }; +RdfElement.uri = 'http://www.eisbm.org/'; - var OptionalBranchJunction = function OptionalBranchJunction(originalCallback, trunkBindings) { - this.trunkBindings = trunkBindings; - this.originalCallback = originalCallback; - this.branches = []; - // this.results = []; // result[i] is an array of bindings for branch i - // this.done = {}; // done[i] means all/any results are in for branch i - // this.count = {} - return this; - }; +/** + * @return {string} + */ +RdfElement.prototype.toXML = function() { + /* + Add some functions to the writer object of N3 + Those functions will allow us to serialize triples synchronously. + Without it, we would be forced to use the asynchronous functions. + */ + function addSimpleWrite (writer) { + // replicates the writer._write function but returns a string + writer.simpleWriteTriple = function (subject, predicate, object, graph) { + return this._encodeIriOrBlankNode(subject) + ' ' + + this._encodeIriOrBlankNode(predicate) + ' ' + + this._encodeObject(object) + + (graph ? ' ' + this._encodeIriOrBlankNode(graph) + '.\n' : '.\n') + }; + // allows to provide an array of triples and concatenate their serialized strings + writer.simpleWriteTriples = function (array) { + var stringN3 = ''; + for (var i=0; i[\s\S]*?<(\w+):SIO_000116>([\s\S]*?)<\/\2:SIO_000116>[\s\S]*?([\s\S]*?)<\/rdf:value>[\s\S]*?<\/rdf:li>/g; + var result = string.replace(regexpLi, ''); + return result; + } - // An optional branch hoards its results. - var OptionalBranch = function OptionalBranch(junction) { - this.count = 0; - this.done = false; - this.results = []; - this.junction = junction; - junction.branches.push(this); - return this; - }; + function replaceBag(string) { + // regexp will spot a transformed bag and capture its content + var regexpBag = /(([\s\S]*?)[\s\S]*?<\/rdf:Description>)/g; + var result1 = string.replace(regexpBag, '$2'); + var result2 = result1.replace(/ <\/rdf:Bag>/g, ''); + return result2; + } - OptionalBranch.prototype.reportMatch = function (bindings) { - this.results.push(bindings); - }; + function replaceParseType(string) { + var regexp = / rdf:parseType="Resource"/g; + return string.replace(regexp, ''); + } - OptionalBranch.prototype.reportDone = function () { - log.debug('Optional branch finished - results.length = ' + this.results.length); - if (this.results.length === 0) { - // This is what optional means: if no hits, - this.results.push({}); // mimic success, but with no bindings - log.debug("Optional branch FAILED - that's OK."); - } - this.done = true; - this.junction.checkAllDone(); - }; + function replaceSlashInID(string) { + return string.replace(new RegExp(/rdf:about="\//g), 'rdf:about="'); + } + + var result = replaceSlashInID(replaceParseType(replaceLi(replaceBag(serialize)))); + + return result; +}; - /** prepare -- sets the index of the item to the possible matches - * @param f - formula - * @param item - an Statement, possibly w/ vars in it - * @param bindings - - * @returns true if the query fails -- there are no items that match **/ - var prepare = function prepare(f, item, bindings) { - var t, terms, termIndex, i, ind; - item.nvars = 0; - item.index = null; - // if (!f.statements) log.warn("@@@ prepare: f is "+f) - // log.debug("Prepare: f has "+ f.statements.length) - // log.debug("Prepare: Kb size "+f.statements.length+" Preparing "+item) +/** + * @param {Element} xml + * @return {RdfElement} + */ +RdfElement.fromString = function (stringXml) { - terms = [item.subject, item.predicate, item.object]; - ind = [f.subjectIndex, f.predicateIndex, f.objectIndex]; - for (i = 0; i < 3; i++) { - // alert("Prepare "+terms[i]+" "+(terms[i] in bindings)) - if (terms[i].isVar && !(bindings[terms[i]] !== undefined)) { - item.nvars++; - } else { - t = bind(terms[i], bindings); // returns the RDF binding if bound, otherwise itself - // if (terms[i]!=bind(terms[i],bindings) alert("Term: "+terms[i]+"Binding: "+bind(terms[i], bindings)) - if (f.redirections[t.hashString()]) { - t = f.redirections[t.hashString()]; // redirect - } - termIndex = ind[i][t.hashString()]; + var rdfElement = new RdfElement(); + var graph = $rdf.graph(); - if (!termIndex) { - item.index = []; - return false; // Query line cannot match - } - if (item.index === null || item.index.length > termIndex.length) { - item.index = termIndex; - } - } - } + // rdflib only accepts string as input, not xml elements + try { + $rdf.parse(stringXml, graph, RdfElement.uri, 'application/rdf+xml'); + } catch (err) { + console.log(err); + } + + // convert to turtle to feed to N3 + var turtle = $rdf.serialize($rdf.sym(RdfElement.uri), graph, undefined, 'text/turtle'); - if (item.index === null) { - // All 3 are variables? - item.index = f.statements; - } - return true; - }; // prepare + var parser = N3.Parser(); + var store = N3.Store(); + store.addPrefixes(Util.prefixes); + store.addTriples(parser.parse(turtle)); + + rdfElement.store = store; - /** sorting function -- negative if self is easier **/ - // We always prefer to start with a URI to be able to browse a graph - // this is why we put off items with more variables till later. - function easiestQuery(self, other) { - if (self.nvars !== other.nvars) { - return self.nvars - other.nvars; - } - return self.index.length - other.index.length; - } + return rdfElement; +}; - var match_index = 0; // index - /** matches a pattern formula against the knowledge base, e.g. to find matches for table-view - * - * @param f - knowledge base formula - * @param g - pattern formula (may have vars) - * @param bindingsSoFar - bindings accumulated in matching to date - * @param level - spaces to indent stuff also lets you know what level of recursion you're at - * @param fetcher - function (term, requestedBy) - myFetcher / AJAR_handleNewTerm / the sort - * @param localCallback - function(bindings, pattern, branch) called on sucess - * @returns nothing - * - * Will fetch linked data from the web iff the knowledge base an associated source fetcher (f.fetcher) - ***/ - var match = function match(f, g, bindingsSoFar, level, fetcher, localCallback, branch) { - log.debug('Match begins, Branch count now: ' + branch.count + ' for ' + branch.pattern_debug); - var sf = f.fetcher ? f.fetcher : null; - // log.debug("match: f has "+f.statements.length+", g has "+g.statements.length) - var pattern = g.statements; - if (pattern.length === 0) { - // when it's satisfied all the pattern triples - log.debug('FOUND MATCH WITH BINDINGS:' + bindingDebug(bindingsSoFar)); - if (g.optional.length === 0) { - branch.reportMatch(bindingsSoFar); - } else { - log.debug('OPTIONAL: ' + g.optional); - var junction = new OptionalBranchJunction(callback, bindingsSoFar); // @@ won't work with nested optionals? nest callbacks - var br = []; - var b; - for (b = 0; b < g.optional.length; b++) { - br[b] = new OptionalBranch(junction); // Allocate branches to prevent premature ending - br[b].pattern_debug = g.optional[b]; // for diagnotics only - } - for (b = 0; b < g.optional.length; b++) { - br[b].count = br[b].count + 1; // Count how many matches we have yet to complete - match(f, g.optional[b], bindingsSoFar, '', fetcher, callback, br[b]); - } - } - branch.count--; - log.debug('Match ends -- success , Branch count now: ' + branch.count + ' for ' + branch.pattern_debug); - return; // Success - } +RdfElement.fromXML = function (string) { + var rdfElement; + function fn (err, result) { + rdfElement = RdfElement.fromObj(result); + }; + utils.parseStringKeepPrefix(string, fn); + return rdfElement; +}; - var item; - var i; - var n = pattern.length; - // log.debug(level + "Match "+n+" left, bs so far:"+bindingDebug(bindingsSoFar)) +RdfElement.prototype.buildJsObj = function () { + var rdfElementJsObj; + function fn (err, result) { + rdfElementJsObj = result; + }; + utils.parseStringKeepPrefix(this.toXML(), fn); + return rdfElementJsObj; +}; - // Follow links from variables in query - if (sf) { - // Fetcher is used to fetch URIs, function first term is a URI term, second is the requester - var id = 'match' + match_index++; - var fetchResource = function fetchResource(requestedTerm, id) { - var docuri = requestedTerm.uri.split('#')[0]; - sf.nowOrWhenFetched(docuri, undefined, function (err, body, xhr) { - if (err) { - console.log('Error following link to <' + requestedTerm.uri + '> in query: ' + body); - } - match(f, g, bindingsSoFar, level, fetcher, // match not match2 to look up any others necessary. - localCallback, branch); - }); - /* - if( sf ) { - sf.addCallback('done', function(uri) { - if ((kb.canon(kb.sym(uri)).uri !== path) && (uri !== kb.canon(kb.sym(path)))) { - return true - } - return false - }) - } - fetcher(requestedTerm, id) - */ - }; - for (i = 0; i < n; i++) { - item = pattern[i]; // for each of the triples in the query - if (bindingsSoFar[item.subject] !== undefined && bindingsSoFar[item.subject].uri && sf && sf.getState(docpart(bindingsSoFar[item.subject].uri)) === 'unrequested') { - // fetch the subject info and return to id - fetchResource(bindingsSoFar[item.subject], id); - return; // only look up one per line this time, but we will come back again though match - } - if (bindingsSoFar[item.object] !== undefined && bindingsSoFar[item.object].uri && sf && sf.getState(docpart(bindingsSoFar[item.object].uri)) === 'unrequested') { - fetchResource(bindingsSoFar[item.object], id); - return; - } - } - } // if sf - match2(f, g, bindingsSoFar, level, fetcher, localCallback, branch); - return; - }; // match +RdfElement.fromObj = function (jsObj) { + if (typeof jsObj['rdf:RDF'] == 'undefined') { + throw new Error("Bad XML provided, expected tagName rdf:RDF, got: " + Object.keys(jsObj)[0]); + } - var constraintsSatisfied = function constraintsSatisfied(bindings, constraints) { - var res = true; - var x; - var test; - for (x in bindings) { - if (bindings.hasOwnProperty(x)) { - if (constraints[x]) { - test = constraints[x].test; - if (test && !test(bindings[x])) { - res = false; - } - } - } - } - return res; - }; + var rdfElement = new ns.RdfElement(); + jsObj = jsObj['rdf:RDF']; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return rdfElement; + } - /** match2 -- stuff after the fetch **/ - var match2 = function match2(f, g, bindingsSoFar, level, fetcher, callback, branch) { - // post fetch - var pattern = g.statements; - var n = pattern.length; - var i; - var k; - var nk; - var v; - var bindings2; - var newBindings1; - var item; - for (i = 0; i < n; i++) { - // For each statement left in the query, run prepare - item = pattern[i]; - log.info('match2: item=' + item + ', bindingsSoFar=' + bindingDebug(bindingsSoFar)); - prepare(f, item, bindingsSoFar); - } - pattern.sort(easiestQuery); - item = pattern[0]; - // log.debug("Sorted pattern:\n"+pattern) - var rest = f.formula(); - rest.optional = g.optional; - rest.constraints = g.constraints; - rest.statements = pattern.slice(1); // No indexes: we will not query g. - log.debug(level + 'match2 searching ' + item.index.length + ' for ' + item + '; bindings so far=' + bindingDebug(bindingsSoFar)); - // var results = [] - var c; - var nc = item.index.length; - var nbs1; - var st; - var onward = 0; - // var x - for (c = 0; c < nc; c++) { - // For each candidate statement - st = item.index[c]; // for each statement in the item's index, spawn a new match with that binding - nbs1 = unifyContents([item.subject, item.predicate, item.object], [st.subject, st.predicate, st.object], bindingsSoFar, f); - log.info(level + ' From first: ' + nbs1.length + ': ' + bindingsDebug(nbs1)); - nk = nbs1.length; - // branch.count += nk - // log.debug("Branch count bumped "+nk+" to: "+branch.count) - for (k = 0; k < nk; k++) { - // For each way that statement binds - bindings2 = []; - newBindings1 = nbs1[k][0]; - if (!constraintsSatisfied(newBindings1, g.constraints)) { - // branch.count-- - log.debug('Branch count CS: ' + branch.count); - } else { - for (v in newBindings1) { - if (newBindings1.hasOwnProperty(v)) { - bindings2[v] = newBindings1[v]; // copy - } - } - for (v in bindingsSoFar) { - if (bindingsSoFar.hasOwnProperty(v)) { - bindings2[v] = bindingsSoFar[v]; // copy - } - } + var obj = {}; + obj['rdf:RDF'] = jsObj; + rdfElement = ns.RdfElement.fromString(utils.buildString(obj)); - branch.count++; // Count how many matches we have yet to complete - onward++; - match(f, rest, bindings2, level + ' ', fetcher, callback, branch); // call match - } - } - } - branch.count--; - if (onward === 0) { - log.debug('Match2 fails completely on ' + item); - } - log.debug('Match2 ends, Branch count: ' + branch.count + ' for ' + branch.pattern_debug); - if (branch.count === 0) { - log.debug('Branch finished.'); - branch.reportDone(); - } - }; // match2 - // ////////////////////////// Body of query() /////////////////////// - /* - if(!fetcher) { - fetcher=function (x, requestedBy) { - if (x === null) { - return - } - $rdf.Util.AJAR_handleNewTerm(kb, x, requestedBy) - } - } - */ - // prepare, oncallback: match1 - // match1: fetcher, oncallback: match2 - // match2, oncallback: populatetable - // log.debug("Query F length"+this.statements.length+" G="+myQuery) - var f = this; - log.debug('Query on ' + this.statements.length); - // kb.remoteQuery(myQuery,'http://jena.hpl.hp.com:3040/backstage',callback) - // return - var trunck = new MandatoryBranch(callback, onDone); - trunck.count++; // count one branch to complete at the moment - setTimeout(function () { - match(f, myQuery.pat, myQuery.pat.initBindings, '', fetcher, callback, trunck /* branch */); - }, 0); + return rdfElement; +}; - return; // returns nothing; callback does the work -} // query +RdfElement.prototype.test = function() { + //console.log(this.store); + //console.log(this.store.getTriples("http://local/anID000001", null, null)); + console.log("expand prefix shortcut", Util.expandPrefix("sio:SIO_000116")); + console.log("all properties of id", this.getCustomPropertiesOfId("http://local/anID000001")); + console.log("all ids", this.getAllIds()); +}; -module.exports.Query = Query; -module.exports.indexedFormulaQuery = indexedFormulaQuery; -},{"./indexed-formula":52,"./log":55,"./uri":72}],64:[function(_dereq_,module,exports){ -'use strict'; +ns.RdfElement = RdfElement; +// ------- END RDFELEMENT ------- -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +ns.rdflib = $rdf; +ns.Util = Util; -// RDFa Parser for rdflib.js +module.exports = ns; -// Originally by: Alex Milowski -// From https://github.com/alexmilowski/green-turtle -// Converted: timbl 2015-08-25 not yet working -// Added wrapper: csarven 2016-05-09 working +},{"./annotation-utils":85,"./utilities":89,"n3":230,"rdflib":248}],87:[function(_dereq_,module,exports){ +/** + * This submodule contains the classes to manage the render extension's xml and some utility functions. + * It adds the ability to save the styles and colors used in an SBGN map, as features like background-color, + * border thickness or font properties are not part of the SBGN standard. + * + * It is loosely based on the {@link http://sbml.org/Documents/Specifications/SBML_Level_3/Packages/render|render extension of the SBML format}. + * A subset of this specification has been adapted for SBGN-ML integration. + * + * See {@link Extension} for more general information on extensions in the SBGN-ML format. + * + * You can access the following classes like this: libsbgn.render.ColorDefinition + * + * @module libsbgn-render + * @namespace libsbgn.render +*/ -// RDFaProcessor.prototype = new Object() // Was URIResolver +var utils = _dereq_('./utilities'); +var checkParams = utils.checkParams; +var xml2js = _dereq_('xml2js'); -// RDFaProcessor.prototype.constructor=RDFaProcessor +var ns = {}; -// options.base = base URI not really an option, shopuld always be set. -// +ns.xmlns = "http://www.sbml.org/sbml/level3/version1/render/version1"; -var BlankNode = _dereq_('./blank-node'); -var Literal = _dereq_('./literal'); -var rdf = _dereq_('./data-factory'); -var NamedNode = _dereq_('./named-node'); -var Uri = _dereq_('./uri'); -var Util = _dereq_('./util'); +// ------- COLORDEFINITION ------- +/** + * Represents the <colorDefinition> element. + * @class + * @param {Object} params + * @param {string=} params.id + * @param {string=} params.value + */ +var ColorDefinition = function(params) { + var params = checkParams(params, ['id', 'value']); + this.id = params.id; + this.value = params.value; +}; -if (typeof Node === 'undefined') { - // @@@@@@ Global. Interface to xmldom. - var Node = { - ELEMENT_NODE: 1, - ATTRIBUTE_NODE: 2, - TEXT_NODE: 3, - CDATA_SECTION_NODE: 4, - ENTITY_REFERENCE_NODE: 5, - ENTITY_NODE: 6, - PROCESSING_INSTRUCTION_NODE: 7, - COMMENT_NODE: 8, - DOCUMENT_NODE: 9, - DOCUMENT_TYPE_NODE: 10, - DOCUMENT_FRAGMENT_NODE: 11, - NOTATION_NODE: 12 - }; -} +/** + * @return {Object} - xml2js formatted object + */ +ColorDefinition.prototype.buildJsObj = function () { + var colordefObj = {}; -var RDFaProcessor = function () { - function RDFaProcessor(kb, options) { - _classCallCheck(this, RDFaProcessor); + // attributes + var attributes = {}; + if(this.id != null) { + attributes.id = this.id; + } + if(this.value != null) { + attributes.value = this.value; + } + utils.addAttributes(colordefObj, attributes); + return colordefObj; +}; - this.options = options || {}; - this.kb = kb; - this.target = options.target || { - graph: { - subjects: {}, - prefixes: {}, - terms: {} - } +/** + * @return {string} + */ +ColorDefinition.prototype.toXML = function () { + return utils.buildString({colorDefinition: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {ColorDefinition} + */ +ColorDefinition.fromXML = function (string) { + var colorDefinition; + function fn (err, result) { + colorDefinition = ColorDefinition.fromObj(result); }; - // XXX: Added to track bnodes - this.blankNodes = []; - // XXX: Added for normalisation - this.htmlOptions = { - 'selfClosing': 'br img input area base basefont col colgroup source wbr isindex link meta param hr' + utils.parseString(string, fn); + return colorDefinition; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {ColorDefinition} + */ +ColorDefinition.fromObj = function (jsObj) { + if (typeof jsObj.colorDefinition == 'undefined') { + throw new Error("Bad XML provided, expected tagName colorDefinition, got: " + Object.keys(jsObj)[0]); + } + + var colorDefinition = new ns.ColorDefinition(); + jsObj = jsObj.colorDefinition; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return colorDefinition; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + colorDefinition.id = attributes.id || null; + colorDefinition.value = attributes.value || null; + } + return colorDefinition; +}; + +ns.ColorDefinition = ColorDefinition; +// ------- END COLORDEFINITION ------- + +// ------- LISTOFCOLORDEFINITIONS ------- +/** + * Represents the <listOfColorDefinitions> element. + * @class + */ +var ListOfColorDefinitions = function () { + this.colorDefinitions = []; + this.colorIndex = {}; +}; + +/** + * @param {ColorDefinition} colorDefinition + */ +ListOfColorDefinitions.prototype.addColorDefinition = function (colorDefinition) { + this.colorDefinitions.push(colorDefinition); + this.colorIndex[colorDefinition.id] = colorDefinition.value; +}; + +/** + * Convenient method to get a color value directly. + * @param {string} id + * @return {string} + */ +ListOfColorDefinitions.prototype.getColorById = function (id) { + return this.colorIndex[id]; +}; + +/** + * Convenient method to get all the color values in the list. + * @return {string[]} + */ +ListOfColorDefinitions.prototype.getAllColors = function () { + return Object.values(this.colorIndex); +}; + +/** + * @return {Object} - xml2js formatted object + */ +ListOfColorDefinitions.prototype.buildJsObj = function () { + var listOfColorDefinitionsObj = {}; + + for(var i=0; i < this.colorDefinitions.length; i++) { + if (i==0) { + listOfColorDefinitionsObj.colorDefinition = []; + } + listOfColorDefinitionsObj.colorDefinition.push(this.colorDefinitions[i].buildJsObj()); + } + + return listOfColorDefinitionsObj; +}; + +/** + * @return {string} + */ +ListOfColorDefinitions.prototype.toXML = function () { + return utils.buildString({listOfColorDefinitions: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {ListOfColorDefinitions} + */ +ListOfColorDefinitions.fromXML = function (string) { + var listOfColorDefinitions; + function fn (err, result) { + listOfColorDefinitions = ListOfColorDefinitions.fromObj(result); }; - this.theOne = '_:' + new Date().getTime(); - this.language = null; - this.vocabulary = null; - this.blankCounter = 0; - this.langAttributes = [{ namespaceURI: 'http://www.w3.org/XML/1998/namespace', localName: 'lang' }]; - this.inXHTMLMode = false; - this.absURIRE = /[\w\_\-]+:\S+/; - this.finishedHandlers = []; - this.init(); - } + utils.parseString(string, fn); + return listOfColorDefinitions; +}; - _createClass(RDFaProcessor, [{ - key: 'addTriple', - value: function addTriple(origin, subject, predicate, object) { - var su, ob, pr, or; - if (typeof subject === 'undefined') { - su = rdf.namedNode(this.options.base); - } else { - su = this.toRDFNodeObject(subject); - } - pr = this.toRDFNodeObject(predicate); - ob = this.toRDFNodeObject(object); - or = rdf.namedNode(this.options.base); - // console.log('Adding { ' + su + ' ' + pr + ' ' + ob + ' ' + or + ' }') - this.kb.add(su, pr, ob, or); - } - }, { - key: 'ancestorPath', - value: function ancestorPath(node) { - var path = ''; - while (node && node.nodeType !== Node.DOCUMENT_NODE) { - path = '/' + node.localName + path; - node = node.parentNode; - } - return path; - } - }, { - key: 'copyMappings', - value: function copyMappings(mappings) { - var newMappings = {}; - for (var k in mappings) { - newMappings[k] = mappings[k]; - } - return newMappings; - } - }, { - key: 'copyProperties', - value: function copyProperties() {} - }, { - key: 'deriveDateTimeType', - value: function deriveDateTimeType(value) { - for (var i = 0; i < RDFaProcessor.dateTimeTypes.length; i++) { - // console.log("Checking "+value+" against "+RDFaProcessor.dateTimeTypes[i].type) - var matched = RDFaProcessor.dateTimeTypes[i].pattern.exec(value); - if (matched && matched[0].length === value.length) { - // console.log("Matched!") - return RDFaProcessor.dateTimeTypes[i].type; +/** + * @param {Object} jsObj - xml2js formatted object + * @return {ListOfColorDefinitions} + */ +ListOfColorDefinitions.fromObj = function (jsObj) { + if (typeof jsObj.listOfColorDefinitions == 'undefined') { + throw new Error("Bad XML provided, expected tagName listOfColorDefinitions, got: " + Object.keys(jsObj)[0]); + } + + var listOfColorDefinitions = new ns.ListOfColorDefinitions(); + jsObj = jsObj.listOfColorDefinitions; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return listOfColorDefinitions; + } + + // children + if(jsObj.colorDefinition) { + var colorDefinitions = jsObj.colorDefinition; + for (var i=0; i < colorDefinitions.length; i++) { + var colorDefinition = ns.ColorDefinition.fromObj({colorDefinition: colorDefinitions[i]}); + listOfColorDefinitions.addColorDefinition(colorDefinition); + } + } + + return listOfColorDefinitions; +}; + +ns.ListOfColorDefinitions = ListOfColorDefinitions; +// ------- END LISTOFCOLORDEFINITIONS ------- + +// ------- RENDERGROUP ------- +/** + * Represents the <g> element. + * @class + * @param {Object} params + * @param {string=} params.id + * @param {string=} params.fontSize + * @param {string=} params.fontFamily + * @param {string=} params.fontWeight + * @param {string=} params.fontStyle + * @param {string=} params.textAnchor + * @param {string=} params.vtextAnchor + * @param {string=} params.fill The element's background color + * @param {string=} params.stroke Border color for glyphs, line color for arcs. + * @param {string=} params.strokeWidth + */ +var RenderGroup = function (params) { + // each of those are optional, so test if it is defined is mandatory + var params = checkParams(params, ['fontSize', 'fontFamily', 'fontWeight', + 'fontStyle', 'textAnchor', 'vtextAnchor', 'fill', 'id', 'stroke', 'strokeWidth']); + // specific to renderGroup + this.fontSize = params.fontSize; + this.fontFamily = params.fontFamily; + this.fontWeight = params.fontWeight; + this.fontStyle = params.fontStyle; + this.textAnchor = params.textAnchor; // probably useless + this.vtextAnchor = params.vtextAnchor; // probably useless + // from GraphicalPrimitive2D + this.fill = params.fill; // fill color + // from GraphicalPrimitive1D + this.id = params.id; + this.stroke = params.stroke; // stroke color + this.strokeWidth = params.strokeWidth; +}; + +/** + * @return {Object} - xml2js formatted object + */ +RenderGroup.prototype.buildJsObj = function () { + var renderGroupObj = {}; + + // attributes + var attributes = {}; + if(this.id != null) { + attributes.id = this.id; + } + if(this.fontSize != null) { + attributes.fontSize = this.fontSize; + } + if(this.fontFamily != null) { + attributes.fontFamily = this.fontFamily; + } + if(this.fontWeight != null) { + attributes.fontWeight = this.fontWeight; + } + if(this.fontStyle != null) { + attributes.fontStyle = this.fontStyle; + } + if(this.textAnchor != null) { + attributes.textAnchor = this.textAnchor; + } + if(this.vtextAnchor != null) { + attributes.vtextAnchor = this.vtextAnchor; + } + if(this.stroke != null) { + attributes.stroke = this.stroke; + } + if(this.strokeWidth != null) { + attributes.strokeWidth = this.strokeWidth; + } + if(this.fill != null) { + attributes.fill = this.fill; + } + utils.addAttributes(renderGroupObj, attributes); + return renderGroupObj; +}; + +/** + * @return {string} + */ +RenderGroup.prototype.toXML = function () { + return utils.buildString({g: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {RenderGroup} + */ +RenderGroup.fromXML = function (string) { + var g; + function fn (err, result) { + g = RenderGroup.fromObj(result); + }; + utils.parseString(string, fn); + return g; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {RenderGroup} + */ +RenderGroup.fromObj = function (jsObj) { + if (typeof jsObj.g == 'undefined') { + throw new Error("Bad XML provided, expected tagName g, got: " + Object.keys(jsObj)[0]); + } + + var g = new ns.RenderGroup(); + jsObj = jsObj.g; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return g; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + g.id = attributes.id || null; + g.fontSize = attributes.fontSize || null; + g.fontFamily = attributes.fontFamily || null; + g.fontWeight = attributes.fontWeight || null; + g.fontStyle = attributes.fontStyle || null; + g.textAnchor = attributes.textAnchor || null; + g.vtextAnchor = attributes.vtextAnchor || null; + g.stroke = attributes.stroke || null; + g.strokeWidth = attributes.strokeWidth || null; + g.fill = attributes.fill || null; + } + return g; +}; + +ns.RenderGroup = RenderGroup; +// ------- END RENDERGROUP ------- + +// ------- STYLE ------- +/** + * Represents the <style> element. + * @class + * @param {Object} params + * @param {string=} params.id + * @param {string=} params.name + * @param {string=} params.idList + * @param {RenderGroup=} params.renderGroup + */ +var Style = function(params) { + var params = checkParams(params, ['id', 'name', 'idList', 'renderGroup']); + this.id = params.id; + this.name = params.name; + this.idList = params.idList; // TODO add utility functions to manage this (should be array) + this.renderGroup = params.renderGroup; +}; + +/** + * @param {RenderGroup} renderGroup + */ +Style.prototype.setRenderGroup = function (renderGroup) { + this.renderGroup = renderGroup; +}; + +/** + * @return {string[]} + */ +Style.prototype.getIdListAsArray = function () { + return this.idList.split(' '); +} + +/** + * @param {string[]} idArray + */ +Style.prototype.setIdListFromArray = function (idArray) { + this.idList = idArray.join(' '); +} + +/** + * Convenience function returning a map of ids to their respective RenderGroup object. + * The style properties can then be directly accessed. Example: map[id].stroke + * @return {Object.} + */ +Style.prototype.getStyleMap = function () { + var index = {}; + var ids = this.getIdListAsArray(); + for(var i=0; i < ids.length; i++) { + var id = ids[i]; + index[id] = this.renderGroup; + } + return index; +}; +/** + * @return {Object} - xml2js formatted object + */ +Style.prototype.buildJsObj = function () { + var styleObj = {}; + + // attributes + var attributes = {}; + if(this.id != null) { + attributes.id = this.id; + } + if(this.name != null) { + attributes.name = this.name; + } + if(this.idList != null) { + attributes.idList = this.idList; + } + utils.addAttributes(styleObj, attributes); + + // children + if(this.renderGroup != null) { + styleObj.g = this.renderGroup.buildJsObj(); + } + return styleObj; +}; + +/** + * @return {string} + */ +Style.prototype.toXML = function () { + return utils.buildString({style: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {Style} + */ +Style.fromXML = function (string) { + var style; + function fn (err, result) { + style = Style.fromObj(result); + }; + utils.parseString(string, fn); + return style; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {Style} + */ +Style.fromObj = function (jsObj) { + if (typeof jsObj.style == 'undefined') { + throw new Error("Bad XML provided, expected tagName style, got: " + Object.keys(jsObj)[0]); + } + + var style = new ns.Style(); + jsObj = jsObj.style; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return style; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + style.id = attributes.id || null; + style.name = attributes.name || null; + style.idList = attributes.idList || null; + } + + // children + if(jsObj.g) { + var g = ns.RenderGroup.fromObj({g: jsObj.g[0]}); + style.setRenderGroup(g); + } + + return style; +}; + +ns.Style = Style; +// ------- END STYLE ------- + +// ------- LISTOFSTYLES ------- +/** + * Represents the <listOfStyles> element. + * @class + */ +var ListOfStyles = function() { + this.styles = []; +}; + +/** + * @param {Style} style + */ +ListOfStyles.prototype.addStyle = function (style) { + this.styles.push(style); +}; + +/** + * Convenience function returning a map of ids to their respective RenderGroup object, + * for all the styles. + * The style properties can then be directly accessed. Example: map[id].stroke + * @return {Object.} + */ +ListOfStyles.prototype.getStyleMap = function () { + var index = {}; + for(var i=0; i < this.styles.length; i++) { + var style = this.styles[i]; + var subIndex = style.getStyleMap(); + for(var id in subIndex) { + index[id] = subIndex[id]; + } + } + return index; +} + +/** + * @return {Object} - xml2js formatted object + */ +ListOfStyles.prototype.buildJsObj = function () { + var listOfStylesObj = {}; + + for(var i=0; i < this.styles.length; i++) { + if (i==0) { + listOfStylesObj.style = []; + } + listOfStylesObj.style.push(this.styles[i].buildJsObj()); + } + + return listOfStylesObj; +}; + +/** + * @return {string} + */ +ListOfStyles.prototype.toXML = function () { + return utils.buildString({listOfStyles: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {ListOfStyles} + */ +ListOfStyles.fromXML = function (string) { + var listOfStyles; + function fn (err, result) { + listOfStyles = ListOfStyles.fromObj(result); + }; + utils.parseString(string, fn); + return listOfStyles; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {ListOfStyles} + */ +ListOfStyles.fromObj = function (jsObj) { + if (typeof jsObj.listOfStyles == 'undefined') { + throw new Error("Bad XML provided, expected tagName listOfStyles, got: " + Object.keys(jsObj)[0]); + } + + var listOfStyles = new ns.ListOfStyles(); + jsObj = jsObj.listOfStyles; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return listOfStyles; + } + + // children + if(jsObj.style) { + var styles = jsObj.style; + for (var i=0; i < styles.length; i++) { + var style = ns.Style.fromObj({style: styles[i]}); + listOfStyles.addStyle(style); + } + } + + return listOfStyles; +}; + +ns.ListOfStyles = ListOfStyles; +// ------- END LISTOFSTYLES ------- + +// ------- RENDERINFORMATION ------- +/** + * Represents the <renderInformation> element. + * @class + * @param {Object} params + * @param {string=} params.id + * @param {string=} params.name + * @param {string=} params.programName + * @param {string=} params.programVersion + * @param {string=} params.backgroundColor + * @param {ListOfColorDefinitions=} params.listOfColorDefinitions + * @param {ListOfStyles=} params.listOfStyles + */ +var RenderInformation = function (params) { + var params = checkParams(params, ['id', 'name', 'programName', + 'programVersion', 'backgroundColor', 'listOfColorDefinitions', 'listOfStyles']); + this.id = params.id; // required, rest is optional + this.name = params.name; + this.programName = params.programName; + this.programVersion = params.programVersion; + this.backgroundColor = params.backgroundColor; + this.listOfColorDefinitions = params.listOfColorDefinitions; + this.listOfStyles = params.listOfStyles; +}; + +/** + * @param {ListOfColorDefinitions} listOfColorDefinitions + */ +RenderInformation.prototype.setListOfColorDefinitions = function(listOfColorDefinitions) { + this.listOfColorDefinitions = listOfColorDefinitions; +}; + +/** + * @param {ListOfStyles} listOfStyles + */ +RenderInformation.prototype.setListOfStyles = function(listOfStyles) { + this.listOfStyles = listOfStyles; +}; + +/** + * @return {Object} - xml2js formatted object + */ +RenderInformation.prototype.buildJsObj = function () { + var renderInformationObj = {}; + + // attributes + var attributes = {}; + attributes.xmlns = ns.xmlns; + if(this.id != null) { + attributes.id = this.id; + } + if(this.name != null) { + attributes.name = this.name; + } + if(this.programName != null) { + attributes.programName = this.programName; + } + if(this.programVersion != null) { + attributes.programVersion = this.programVersion; + } + if(this.backgroundColor != null) { + attributes.backgroundColor = this.backgroundColor; + } + utils.addAttributes(renderInformationObj, attributes); + + // children + if(this.listOfColorDefinitions != null) { + renderInformationObj.listOfColorDefinitions = this.listOfColorDefinitions.buildJsObj(); + } + if(this.listOfStyles != null) { + renderInformationObj.listOfStyles = this.listOfStyles.buildJsObj(); + } + return renderInformationObj; +}; + +/** + * @return {string} + */ +RenderInformation.prototype.toXML = function() { + return utils.buildString({renderInformation: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {RenderInformation} + */ +RenderInformation.fromXML = function (string) { + var renderInformation; + function fn (err, result) { + renderInformation = RenderInformation.fromObj(result); + }; + utils.parseString(string, fn); + return renderInformation; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {RenderInformation} + */ +RenderInformation.fromObj = function (jsObj) { + if (typeof jsObj.renderInformation == 'undefined') { + throw new Error("Bad XML provided, expected tagName renderInformation, got: " + Object.keys(jsObj)[0]); + } + + var renderInformation = new ns.RenderInformation(); + jsObj = jsObj.renderInformation; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return renderInformation; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + renderInformation.id = attributes.id || null; + renderInformation.name = attributes.name || null; + renderInformation.programName = attributes.programName || null; + renderInformation.programVersion = attributes.programVersion || null; + renderInformation.backgroundColor = attributes.backgroundColor || null; + } + + // children + if(jsObj.listOfColorDefinitions) { + var listOfColorDefinitions = ns.ListOfColorDefinitions.fromObj({listOfColorDefinitions: jsObj.listOfColorDefinitions[0]}); + renderInformation.setListOfColorDefinitions(listOfColorDefinitions); + } + if(jsObj.listOfStyles) { + var listOfStyles = ns.ListOfStyles.fromObj({listOfStyles: jsObj.listOfStyles[0]}); + renderInformation.setListOfStyles(listOfStyles); + } + + return renderInformation; +}; + +ns.RenderInformation = RenderInformation; +// ------- END RENDERINFORMATION ------- + +module.exports = ns; +},{"./utilities":89,"xml2js":62}],88:[function(_dereq_,module,exports){ +/** + * The API contains two other submodules: {@link libsbgn.render} and {@link libsbgn.annot} + * @module libsbgn + * @namespace libsbgn +*/ + +var renderExt = _dereq_('./libsbgn-render'); +var annotExt = _dereq_('./libsbgn-annotations'); +var xml2js = _dereq_('xml2js'); +var utils = _dereq_('./utilities'); +var checkParams = utils.checkParams; + +var ns = {}; // namespace that encapsulates all exportable features + +ns.xmlns = "http://sbgn.org/libsbgn/0.3"; + +// ------- SBGNBase ------- +/** + * Parent class for several sbgn elements. Used to provide extension and notes element. + * End users don't need to interact with it. It can be safely ignored. + * @class + * @param {Object} params + * @param {Extension=} params.extension + * @param {Notes=} params.notes + */ +var SBGNBase = function (params) { + var params = checkParams(params, ['extension', 'notes']); + this.extension = params.extension; + this.notes = params.notes; +}; + +/** + * Allows inheriting objects to get an extension element. + * @param {Extension} extension + */ +SBGNBase.prototype.setExtension = function (extension) { + this.extension = extension; +}; + +/** + * Allows inheriting objects to get a notes element. + * @param {Notes} notes + */ +SBGNBase.prototype.setNotes = function (notes) { + this.notes = notes; +}; + +/** + * Add the appropriate properties to jsObj. + * @param {Object} jsObj - xml2js formatted object + */ +SBGNBase.prototype.baseToJsObj = function (jsObj) { + if(this.extension != null) { + jsObj.extension = this.extension.buildJsObj(); + } + if(this.notes != null) { + jsObj.notes = this.notes.buildJsObj(); + } +}; + +/** + * Get the appropriate properties from jsObj. + * @param {Object} jsObj - xml2js formatted object + */ +SBGNBase.prototype.baseFromObj = function (jsObj) { + if (jsObj.extension) { + var extension = ns.Extension.fromObj({extension: jsObj.extension[0]}); + this.setExtension(extension); + } + if (jsObj.notes) { + var notes = ns.Notes.fromObj({notes: jsObj.notes[0]}); + this.setNotes(notes); + } +}; +ns.SBGNBase = SBGNBase; +// ------- END SBGNBase ------- + +// ------- SBGN ------- +/** + * Represents the <sbgn> element. + * @class + * @extends SBGNBase + * @param {Object} params + * @param {string=} params.xmlns + * @param {Map[]=} params.maps + */ +var Sbgn = function (params) { + ns.SBGNBase.call(this, params); + var params = checkParams(params, ['xmlns', 'maps']); + this.xmlns = params.xmlns; + this.maps = params.maps || []; +}; + +Sbgn.prototype = Object.create(ns.SBGNBase.prototype); +Sbgn.prototype.constructor = Sbgn; + +/** + * @param {Map} map + */ +Sbgn.prototype.addMap = function (map) { + this.maps.push(map); +}; + +/** + * @return {Object} - xml2js formatted object + */ +Sbgn.prototype.buildJsObj = function () { + var sbgnObj = {}; + + // attributes + var attributes = {}; + if(this.xmlns != null) { + attributes.xmlns = this.xmlns; + } + utils.addAttributes(sbgnObj, attributes); + + // children + this.baseToJsObj(sbgnObj); + for(var i=0; i < this.maps.length; i++) { + if (i==0) { + sbgnObj.map = []; + } + sbgnObj.map.push(this.maps[i].buildJsObj()); + } + return sbgnObj; +}; + +/** + * @return {string} + */ +Sbgn.prototype.toXML = function () { + return utils.buildString({sbgn: this.buildJsObj()}); +}; + +/** + * @param {String} string + * @return {Sbgn} + */ +Sbgn.fromXML = function (string) { + var sbgn; + function fn (err, result) { + sbgn = Sbgn.fromObj(result); + } + utils.parseString(string, fn); + return sbgn; + +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {Sbgn} + */ +Sbgn.fromObj = function (jsObj) { + if (typeof jsObj.sbgn == 'undefined') { + throw new Error("Bad XML provided, expected tagName sbgn, got: " + Object.keys(jsObj)[0]); + } + + var sbgn = new ns.Sbgn(); + jsObj = jsObj.sbgn; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return sbgn; + } + + if(jsObj.$) { // we have some atributes + var attributes = jsObj.$; + sbgn.xmlns = attributes.xmlns || null; + + // getting attribute with 'xmlns' doesn't work if some namespace is defined like 'xmlns:sbgn' + // so if there is some attribute there, and we didn't find the xmlns directly, we need to into it + if(!sbgn.xmlns && Object.keys(attributes).length > 0) { + // sbgn is not supposed to have any other attribute than an xmlns, so we assume the first attr is the xmlns + var key = Object.keys(attributes)[0]; + if(key.startsWith('xmlns')) { + sbgn.xmlns = attributes[key]; + sbgn.namespacePrefix = key.replace('xmlns:', ''); + } + else { + throw new Error("Couldn't find xmlns definition in sbgn element"); + } + } + } + + if(jsObj.map) { + var maps = jsObj.map; + for (var i=0; i < maps.length; i++) { + var map = ns.Map.fromObj({map: maps[i]}); + sbgn.addMap(map); + } + } + + sbgn.baseFromObj(jsObj); // call to parent class + return sbgn; +}; +ns.Sbgn = Sbgn; +// ------- END SBGN ------- + +// ------- MAP ------- +/** + * Represents the <map> element. + * @class + * @extends SBGNBase + * @param {Object} params + * @param {string=} params.id + * @param {string=} params.language + * @param {string=} params.version + * @param {Glyph[]=} params.glyphs + * @param {Arc[]=} params.arcs + * @param {Bbox=} params.bbox + * @param {Arcgroup[]=} params.arcgroups + */ +var Map = function (params) { + ns.SBGNBase.call(this, params); + var params = checkParams(params, ['id', 'language', 'version', 'glyphs', 'arcs', 'bbox', 'arcgroups']); + this.id = params.id; + this.language = params.language; + this.version = params.version; + this.bbox = params.bbox; + this.glyphs = params.glyphs || []; + this.arcs = params.arcs || []; + this.arcgroups = params.arcgroups || []; +}; + +Map.prototype = Object.create(ns.SBGNBase.prototype); +Map.prototype.constructor = Map; + +/** + * @param {Glyph} glyph + */ +Map.prototype.addGlyph = function (glyph) { + this.glyphs.push(glyph); +}; + +/** + * @param {Arc} arc + */ +Map.prototype.addArc = function (arc) { + this.arcs.push(arc); +}; + +/** + * @param {Bbox} bbox + */ +Map.prototype.setBbox = function (bbox) { + this.bbox = bbox; +}; + +/** + * @param {Arcgroup} arc + */ +Map.prototype.addArcgroup = function (arcgroup) { + this.arcgroups.push(arcgroup); +}; + +/** + * @param {string} class_ + * @return {Gyph[]} + */ +Map.prototype.getGlyphsByClass = function (class_) { + var resultGlyphs = []; + for(var i=0; i < this.glyphs.length; i++) { + var glyph = this.glyphs[i]; + if(glyph.class_ == class_) { + resultGlyphs.push(glyph); + } + } + return resultGlyphs; +}; + +/** + * @return {Object} - xml2js formatted object + */ +Map.prototype.buildJsObj = function () { + var mapObj = {}; + + // attributes + var attributes = {}; + if(this.id != null) { + attributes.id = this.id; + } + if(this.language != null) { + attributes.language = this.language; + } + if(this.version != null) { + attributes.version = this.version; + } + utils.addAttributes(mapObj, attributes); + + // children + this.baseToJsObj(mapObj); + if(this.bbox != null) { + mapObj.bbox = this.bbox.buildJsObj(); + } + for(var i=0; i < this.glyphs.length; i++) { + if (i==0) { + mapObj.glyph = []; + } + mapObj.glyph.push(this.glyphs[i].buildJsObj()); + } + for(var i=0; i < this.arcs.length; i++) { + if (i==0) { + mapObj.arc = []; + } + mapObj.arc.push(this.arcs[i].buildJsObj()); + } + for(var i=0; i < this.arcgroups.length; i++) { + if (i==0) { + mapObj.arcgroup = []; + } + mapObj.arcgroup.push(this.arcgroups[i].buildJsObj()); + } + return mapObj; +}; + +/** + * @return {string} + */ +Map.prototype.toXML = function () { + return utils.buildString({map: this.buildJsObj()}); +}; + +/** + * @param {String} string + * @return {Map} + */ +Map.fromXML = function (string) { + var map; + function fn (err, result) { + map = Map.fromObj(result); + }; + utils.parseString(string, fn); + return map; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {Map} + */ +Map.fromObj = function (jsObj) { + if (typeof jsObj.map == 'undefined') { + throw new Error("Bad XML provided, expected tagName map, got: " + Object.keys(jsObj)[0]); + } + + var map = new ns.Map(); + jsObj = jsObj.map; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return map; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + map.id = attributes.id || null; + map.language = attributes.language || null; + map.version = attributes.version || null; + } + + if(jsObj.bbox) { + var bbox = ns.Bbox.fromObj({bbox: jsObj.bbox[0]}); + map.setBbox(bbox); + } + if(jsObj.glyph) { + var glyphs = jsObj.glyph; + for (var i=0; i < glyphs.length; i++) { + var glyph = ns.Glyph.fromObj({glyph: glyphs[i]}); + map.addGlyph(glyph); + } + } + if(jsObj.arc) { + var arcs = jsObj.arc; + for (var i=0; i < arcs.length; i++) { + var arc = ns.Arc.fromObj({arc: arcs[i]}); + map.addArc(arc); + } + } + if(jsObj.arcgroup) { + var arcgroups = jsObj.arcgroup; + for (var i=0; i < arcgroups.length; i++) { + var arcgroup = ns.Arcgroup.fromObj({arcgroup: arcgroups[i]}); + map.addArcgroup(arcgroup); + } + } + + map.baseFromObj(jsObj); + return map; +}; + +ns.Map = Map; +// ------- END MAP ------- + +// ------- EXTENSION ------- +/** + * Represents the <extension> element. + * @class + */ +var Extension = function () { + // consider first order children, add them with their tagname as property of this object + // store string if no supported parsing (unrecognized extensions) + // else store instance of the extension + this.list = {}; +}; + +/** + * @param {String|render.RenderInformation|annot.Annotation} extension + */ +Extension.prototype.add = function (extension) { + if (extension instanceof renderExt.RenderInformation) { + this.list['renderInformation'] = extension; + } + else if (extension instanceof annotExt.Annotation) { + this.list['annotation'] = extension; + } + else if(typeof extension == "string") { + var parsedAsObj; + function fn (err, result) { + parsedAsObj = result; + }; + utils.parseString(extension, fn); + var name = Object.keys(parsedAsObj)[0]; + if(name == "renderInformation") { + var renderInformation = renderExt.RenderInformation.fromXML(extension); + this.list['renderInformation'] = renderInformation; + } + else if(name == "annotation") { + var annotation = annotExt.Annotation.fromXML(extension); + this.list['annotation'] = renderInformation; + } + else { + this.list[name] = extension; + } + } +}; + +/** + * @param {string} extensionName + * @return {boolean} + */ +Extension.prototype.has = function (extensionName) { + return this.list.hasOwnProperty(extensionName); +}; + +/** + * @param {string} extensionName + * @return {String|render.RenderInformation|annot.Annotation} + */ +Extension.prototype.get = function (extensionName) { + if (this.has(extensionName)) { + return this.list[extensionName]; + } + else { + return null; + } +}; + +/** + * @return {Object} - xml2js formatted object + */ +Extension.prototype.buildJsObj = function () { + var extensionObj = {}; + + for (var extInstance in this.list) { + if (extInstance == "renderInformation") { + extensionObj.renderInformation = this.get(extInstance).buildJsObj(); + } + else if (extInstance == "annotation") { + extensionObj.annotation = this.get(extInstance).buildJsObj(); + } + else { + // unsupported extensions are stored as is, as xml string + // we need to parse it to build the js object + var unsupportedExtObj; + function fn (err, result) { + unsupportedExtObj = result; + }; + utils.parseString(this.get(extInstance), fn); + extensionObj[extInstance] = unsupportedExtObj[extInstance]; + } + } + return extensionObj; +}; + +/** + * @return {string} + */ +Extension.prototype.toXML = function () { + return utils.buildString({extension: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {Extension} + */ +Extension.fromXML = function (string) { + var extension; + function fn (err, result) { + extension = Extension.fromObj(result); + }; + utils.parseString(string, fn); + return extension; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {Extension} + */ +Extension.fromObj = function (jsObj) { + if (typeof jsObj.extension == 'undefined') { + throw new Error("Bad XML provided, expected tagName extension, got: " + Object.keys(jsObj)[0]); + } + + var extension = new Extension(); + jsObj = jsObj.extension; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return extension; + } + + //var children = Object.keys(jsObj); + for (var extName in jsObj) { + //var extName = Object.keys(jsObj[i])[0]; + var extJsObj = jsObj[extName]; + + //extension.add(extInstance); + if (extName == 'renderInformation') { + var renderInformation = renderExt.RenderInformation.fromObj({renderInformation: extJsObj[0]}); + extension.add(renderInformation); + } + else if (extName == 'annotation') { + var annotation = annotExt.Annotation.fromObj({annotation: extJsObj[0]}); + extension.add(annotation); + } + else { // unsupported extension, we still store the data as is + var unsupportedExt = {}; + unsupportedExt[extName] = extJsObj[0]; // make extension serialisable + var stringExt = utils.buildString(unsupportedExt); // serialise to string + extension.add(stringExt); // save it + } + } + + return extension; +}; + +ns.Extension = Extension; +// ------- END EXTENSION ------- + +// ------- NOTES ------- +/** + * Represents the <notes> element. + * Its single content attribute stores xhtml elements as string. + * @class + */ +var Notes = function () { + this.content = ""; +}; + +/** + * Overwrite the content. + * @param {String} string + */ +Notes.prototype.setContent = function (string) { + this.content = string; +}; + +/** + * @param {String} string + */ +Notes.prototype.appendContent = function (string) { + this.content += string; +}; + +/** + * @return {Object} - xml2js formatted object + */ +Notes.prototype.buildJsObj = function () { + + var parsedContent = ""; + if(this.content != "") { // xml2js refuses to parse empty strings + utils.parseString(this.content, function (err, result) { + parsedContent = result; + }); + } + + return parsedContent; +}; + +/** + * @return {string} + */ +Notes.prototype.toXML = function () { + return utils.buildString({notes: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {Notes} + */ +Notes.fromXML = function (string) { + var notes; + function fn (err, result) { + notes = Notes.fromObj(result); + }; + utils.parseString(string, fn); + return notes; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {Notes} + */ +Notes.fromObj = function (jsObj) { + if (typeof jsObj.notes == 'undefined') { + throw new Error("Bad XML provided, expected tagName notes, got: " + Object.keys(jsObj)[0]); + } + + var notes = new Notes(); + jsObj = jsObj.notes; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return notes; + } + + var stringExt = utils.buildString({notes: jsObj}); // serialise to string + // xml2js does weird things when you just want to serialize the content + // need to include the root to get it properly, and then remove it in the result string. + stringExt = stringExt.replace('', ''); + stringExt = stringExt.replace('', ''); + notes.content = stringExt; // save it + + return notes; +}; + +ns.Notes = Notes; +// ------- END NOTES ------- + +// ------- GLYPH ------- +/** + * Represents the <glyph> element. + * @class Glyph + * @extends SBGNBase + * @param {Object} params + * @param {string=} params.id + * @param {string=} params.class_ + * @param {string=} params.compartmentRef + * @param {string|number=} params.compartmentOrder + * @param {string=} params.mapRef + * @param {string=} params.tagRef + * @param {string=} params.orientation + * @param {Label=} params.label + * @param {Bbox=} params.bbox + * @param {StateType=} params.state + * @param {CloneType=} params.clone + * @param {Callout=} params.callout + * @param {EntityType=} params.entity + * @param {Glyph[]=} params.glyphMembers + * @param {Port[]=} params.ports + */ +var Glyph = function (params) { + ns.SBGNBase.call(this, params); + var params = checkParams(params, ['id', 'class_', 'compartmentRef', 'compartmentOrder', 'mapRef', + 'tagRef', 'orientation', 'label', 'bbox', 'glyphMembers', 'ports', 'state', 'clone', 'entity', 'callout']); + this.id = params.id; + this.class_ = params.class_; + this.compartmentRef = params.compartmentRef; + this.compartmentOrder = parseFloat(params.compartmentOrder); + this.mapRef = params.mapRef; + this.tagRef = params.tagRef; + this.orientation = params.orientation; + + // children + this.label = params.label; + this.state = params.state; + this.clone = params.clone; + this.callout = params.callout; + this.entity = params.entity; + this.bbox = params.bbox; + this.glyphMembers = params.glyphMembers || []; // case of complex, can have arbitrary list of nested glyphs + this.ports = params.ports || []; +}; + +Glyph.prototype = Object.create(ns.SBGNBase.prototype); +Glyph.prototype.constructor = Glyph; + +/** + * @param {Label} label + */ +Glyph.prototype.setLabel = function (label) { + this.label = label; +}; + +/** + * @param {StateType} state + */ +Glyph.prototype.setState = function (state) { + this.state = state; +}; + +/** + * @param {Bbox} bbox + */ +Glyph.prototype.setBbox = function (bbox) { + this.bbox = bbox; +}; + +/** + * @param {CloneType} clone + */ +Glyph.prototype.setClone = function (clone) { + this.clone = clone; +}; + +/** + * @param {Callout} callout + */ +Glyph.prototype.setCallout = function (callout) { + this.callout = callout; +}; + +/** + * @param {EntityType} entity + */ +Glyph.prototype.setEntity = function (entity) { + this.entity = entity; +}; + +/** + * @param {Glyph} glyphMember + */ +Glyph.prototype.addGlyphMember = function (glyphMember) { + this.glyphMembers.push(glyphMember); +}; + +/** + * @param {Port} port + */ +Glyph.prototype.addPort = function (port) { + this.ports.push(port); +}; + +/** + * @return {Object} - xml2js formatted object + */ +Glyph.prototype.buildJsObj = function () { + var glyphObj = {}; + + // attributes + var attributes = {}; + if(this.id != null) { + attributes.id = this.id; + } + if(this.class_ != null) { + attributes.class = this.class_; + } + if(this.compartmentRef != null) { + attributes.compartmentRef = this.compartmentRef; + } + if(!isNaN(this.compartmentOrder)) { + attributes.compartmentOrder = this.compartmentOrder; + } + if(this.mapRef != null) { + attributes.mapRef = this.mapRef; + } + if(this.tagRef != null) { + attributes.tagRef = this.tagRef; + } + if(this.orientation != null) { + attributes.orientation = this.orientation; + } + utils.addAttributes(glyphObj, attributes); + + // children + this.baseToJsObj(glyphObj); + if(this.label != null) { + glyphObj.label = this.label.buildJsObj(); + } + if(this.state != null) { + glyphObj.state = this.state.buildJsObj(); + } + if(this.clone != null) { + glyphObj.clone = this.clone.buildJsObj(); + } + if(this.callout != null) { + glyphObj.callout = this.callout.buildJsObj(); + } + if(this.entity != null) { + glyphObj.entity = this.entity.buildJsObj(); + } + if(this.bbox != null) { + glyphObj.bbox = this.bbox.buildJsObj(); + } + for(var i=0; i < this.glyphMembers.length; i++) { + if (i==0) { + glyphObj.glyph = []; + } + glyphObj.glyph.push(this.glyphMembers[i].buildJsObj()); + } + for(var i=0; i < this.ports.length; i++) { + if (i==0) { + glyphObj.port = []; + } + glyphObj.port.push(this.ports[i].buildJsObj()); + } + return glyphObj; +}; + +/** + * @return {string} + */ +Glyph.prototype.toXML = function () { + return utils.buildString({glyph: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {Glyph} + */ +Glyph.fromXML = function (string) { + var glyph; + function fn (err, result) { + glyph = Glyph.fromObj(result); + }; + utils.parseString(string, fn); + return glyph; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {Glyph} + */ +Glyph.fromObj = function (jsObj) { + if (typeof jsObj.glyph == 'undefined') { + throw new Error("Bad XML provided, expected tagName glyph, got: " + Object.keys(jsObj)[0]); + } + + var glyph = new ns.Glyph(); + jsObj = jsObj.glyph; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return glyph; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + glyph.id = attributes.id || null; + glyph.class_ = attributes.class || null; + glyph.compartmentRef = attributes.compartmentRef || null; + glyph.compartmentOrder = parseFloat(attributes.compartmentOrder); + glyph.mapRef = attributes.mapRef || null; + glyph.tagRef = attributes.tagRef || null; + glyph.orientation = attributes.orientation || null; + } + + // children + if(jsObj.label) { + var label = ns.Label.fromObj({label: jsObj.label[0]}); + glyph.setLabel(label); + } + if(jsObj.state) { + var state = ns.StateType.fromObj({state: jsObj.state[0]}); + glyph.setState(state); + } + if(jsObj.clone) { + var clone = ns.CloneType.fromObj({clone: jsObj.clone[0]}); + glyph.setClone(clone); + } + if(jsObj.callout) { + var callout = ns.Callout.fromObj({callout: jsObj.callout[0]}); + glyph.setCallout(callout); + } + if(jsObj.entity) { + var entity = ns.EntityType.fromObj({entity: jsObj.entity[0]}); + glyph.setEntity(entity); + } + if(jsObj.bbox) { + var bbox = ns.Bbox.fromObj({bbox: jsObj.bbox[0]}); + glyph.setBbox(bbox); + } + + if(jsObj.glyph) { + var glyphs = jsObj.glyph; + for (var i=0; i < glyphs.length; i++) { + var glyphMember = ns.Glyph.fromObj({glyph: glyphs[i]}); + glyph.addGlyphMember(glyphMember); + } + } + if(jsObj.port) { + var ports = jsObj.port; + for (var i=0; i < ports.length; i++) { + var port = ns.Port.fromObj({port: ports[i]}); + glyph.addPort(port); + } + } + + glyph.baseFromObj(jsObj); + return glyph; +}; + +ns.Glyph = Glyph; +// ------- END GLYPH ------- + +// ------- LABEL ------- +/** + * Represents the <label> element. + * @class Label + * @extends SBGNBase + * @param {Object} params + * @param {string=} params.text + * @param {Bbox=} params.bbox + */ +var Label = function (params) { + ns.SBGNBase.call(this, params); + var params = checkParams(params, ['text', 'bbox']); + this.text = params.text; + this.bbox = params.bbox; +}; + +Label.prototype = Object.create(ns.SBGNBase.prototype); +Label.prototype.constructor = ns.Label; + +/** + * @param {Bbox} bbox + */ +Label.prototype.setBbox = function (bbox) { + this.bbox = bbox; +}; + +/** + * @return {Object} - xml2js formatted object + */ +Label.prototype.buildJsObj = function () { + var labelObj = {}; + + // attributes + var attributes = {}; + if(this.text != null) { + attributes.text = this.text; + } + else { // text is a required attribute + attributes.text = ""; + } + // ensure encoding of line breaks is always respected + //attributes.text = attributes.text.replace('\n', '\n'); //' '); + utils.addAttributes(labelObj, attributes); + + this.baseToJsObj(labelObj); + if(this.bbox != null) { + labelObj.bbox = this.bbox.buildJsObj(); + } + return labelObj; +}; + +/** + * @return {string} + */ +Label.prototype.toXML = function () { + return utils.buildString({label: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {Label} + */ +Label.fromXML = function (string) { + var label; + function fn (err, result) { + label = Label.fromObj(result); + }; + utils.parseString(string, fn); + return label; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {Label} + */ +Label.fromObj = function (jsObj) { + if (typeof jsObj.label == 'undefined') { + throw new Error("Bad XML provided, expected tagName label, got: " + Object.keys(jsObj)[0]); + } + + var label = new ns.Label(); + jsObj = jsObj.label; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return label; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + label.text = attributes.text || null; + } + + if(jsObj.bbox) { + var bbox = ns.Bbox.fromObj({bbox: jsObj.bbox[0]}); + label.setBbox(bbox); + } + label.baseFromObj(jsObj); + return label; +}; + +ns.Label = Label; +// ------- END LABEL ------- + +// ------- BBOX ------- +/** + * Represents the <bbox> element. + * @class Bbox + * @extends SBGNBase + * @param {Object} params + * @param {string|number=} params.x + * @param {string|number=} params.y + * @param {string|number=} params.w + * @param {string|number=} params.h + */ +var Bbox = function (params) { + ns.SBGNBase.call(this, params); + var params = checkParams(params, ['x', 'y', 'w', 'h']); + this.x = parseFloat(params.x); + this.y = parseFloat(params.y); + this.w = parseFloat(params.w); + this.h = parseFloat(params.h); +}; + +Bbox.prototype = Object.create(ns.SBGNBase.prototype); +Bbox.prototype.constructor = ns.Bbox; + +/** + * @return {Object} - xml2js formatted object + */ +Bbox.prototype.buildJsObj = function () { + var bboxObj = {}; + + // attributes + var attributes = {}; + if(!isNaN(this.x)) { + attributes.x = this.x; + } + if(!isNaN(this.y)) { + attributes.y = this.y; + } + if(!isNaN(this.w)) { + attributes.w = this.w; + } + if(!isNaN(this.h)) { + attributes.h = this.h; + } + utils.addAttributes(bboxObj, attributes); + this.baseToJsObj(bboxObj); + return bboxObj; +}; + +/** + * @return {string} + */ +Bbox.prototype.toXML = function () { + return utils.buildString({bbox: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {Bbox} + */ +Bbox.fromXML = function (string) { + var bbox; + function fn (err, result) { + bbox = Bbox.fromObj(result); + }; + utils.parseString(string, fn); + return bbox; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {Bbox} + */ +Bbox.fromObj = function (jsObj) { + if (typeof jsObj.bbox == 'undefined') { + throw new Error("Bad XML provided, expected tagName bbox, got: " + Object.keys(jsObj)[0]); + } + + var bbox = new ns.Bbox(); + jsObj = jsObj.bbox; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return bbox; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + bbox.x = parseFloat(attributes.x); + bbox.y = parseFloat(attributes.y); + bbox.w = parseFloat(attributes.w); + bbox.h = parseFloat(attributes.h); + } + bbox.baseFromObj(jsObj); + return bbox; +}; + +ns.Bbox = Bbox; +// ------- END BBOX ------- + +// ------- STATE ------- +/** + * Represents the <state> element. + * @class StateType + * @param {Object} params + * @param {string=} params.value + * @param {string=} params.variable + */ +var StateType = function (params) { + var params = checkParams(params, ['value', 'variable']); + this.value = params.value; + this.variable = params.variable; +}; + +/** + * @return {Object} - xml2js formatted object + */ +StateType.prototype.buildJsObj = function () { + var stateObj = {}; + + // attributes + var attributes = {}; + if(this.value != null) { + attributes.value = this.value; + } + if(this.variable != null) { + attributes.variable = this.variable; + } + utils.addAttributes(stateObj, attributes); + return stateObj; +}; + +/** + * @return {string} + */ +StateType.prototype.toXML = function () { + return utils.buildString({state: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {StateType} + */ +StateType.fromXML = function (string) { + var state; + function fn (err, result) { + state = StateType.fromObj(result); + }; + utils.parseString(string, fn); + return state; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {StateType} + */ +StateType.fromObj = function (jsObj) { + if (typeof jsObj.state == 'undefined') { + throw new Error("Bad XML provided, expected tagName state, got: " + Object.keys(jsObj)[0]); + } + + var state = new ns.StateType(); + jsObj = jsObj.state; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return state; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + state.value = attributes.value || null; + state.variable = attributes.variable || null; + } + return state; +}; + +ns.StateType = StateType; +// ------- END STATE ------- + +// ------- CLONE ------- +/** + * Represents the <clone> element. + * @class CloneType + * @param {Object} params + * @param {string=} params.label + */ +var CloneType = function (params) { + var params = checkParams(params, ['label']); + this.label = params.label; +}; + +/** + * @param {Label} label + */ +CloneType.prototype.setLabel = function (label) { + this.label = label; +}; + +/** + * @return {Object} - xml2js formatted object + */ +CloneType.prototype.buildJsObj = function () { + var cloneObj = {}; + + // children + if(this.label != null) { + cloneObj.label = this.label.buildJsObj(); + } + return cloneObj; +}; + +/** + * @return {string} + */ +CloneType.prototype.toXML = function () { + return utils.buildString({clone: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {CloneType} + */ +CloneType.fromXML = function (string) { + var clone; + function fn (err, result) { + clone = CloneType.fromObj(result); + }; + utils.parseString(string, fn); + return clone; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {CloneType} + */ +CloneType.fromObj = function (jsObj) { + if (typeof jsObj.clone == 'undefined') { + throw new Error("Bad XML provided, expected tagName clone, got: " + Object.keys(jsObj)[0]); + } + + var clone = new ns.CloneType(); + jsObj = jsObj.clone; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return clone; + } + + // children + if(jsObj.label) { + var label = ns.Label.fromObj({label: jsObj.label[0]}); + clone.setLabel(label); + } + return clone; +}; + +ns.CloneType = CloneType; +// ------- END CLONE ------- + +// ------- ENTITYTYPE ------- +/** + * Represents the <entity> element. + * @class EntityType + * @param {Object} params + * @param {string=} params.name + */ +var EntityType = function (params) { + var params = checkParams(params, ['name']); + this.name = params.name; +}; + +/** + * @return {Object} - xml2js formatted object + */ +EntityType.prototype.buildJsObj = function () { + var entityObj = {}; + + // attributes + var attributes = {}; + if(this.name != null) { + attributes.name = this.name; + } + utils.addAttributes(entityObj, attributes); + return entityObj; +}; + +/** + * @return {string} + */ +EntityType.prototype.toXML = function () { + return utils.buildString({entity: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {EntityType} + */ +EntityType.fromXML = function (string) { + var entity; + function fn (err, result) { + entity = EntityType.fromObj(result); + }; + utils.parseString(string, fn); + return entity; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {EntityType} + */ +EntityType.fromObj = function (jsObj) { + if (typeof jsObj.entity == 'undefined') { + throw new Error("Bad XML provided, expected tagName entity, got: " + Object.keys(jsObj)[0]); + } + + var entity = new ns.EntityType(); + jsObj = jsObj.entity; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return entity; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + entity.name = attributes.name || null; + } + return entity; +}; + +ns.EntityType = EntityType; +// ------- END ENTITYTYPE ------- + +// ------- PORT ------- +/** + * Represents the <port> element. + * @class Port + * @param {Object} params + * @param {string=} params.id + * @param {string|number=} params.x + * @param {string|number=} params.y + */ +var Port = function (params) { + ns.SBGNBase.call(this, params); + var params = checkParams(params, ['id', 'x', 'y']); + this.id = params.id; + this.x = parseFloat(params.x); + this.y = parseFloat(params.y); +}; + +Port.prototype = Object.create(ns.SBGNBase.prototype); +Port.prototype.constructor = ns.Port; + +/** + * @return {Object} - xml2js formatted object + */ +Port.prototype.buildJsObj = function () { + var portObj = {}; + + // attributes + var attributes = {}; + if(this.id != null) { + attributes.id = this.id; + } + if(!isNaN(this.x)) { + attributes.x = this.x; + } + if(!isNaN(this.y)) { + attributes.y = this.y; + } + utils.addAttributes(portObj, attributes); + this.baseToJsObj(portObj); + return portObj; +}; + +/** + * @return {string} + */ +Port.prototype.toXML = function () { + return utils.buildString({port: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {Port} + */ +Port.fromXML = function (string) { + var port; + function fn (err, result) { + port = Port.fromObj(result); + }; + utils.parseString(string, fn); + return port; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {Port} + */ +Port.fromObj = function (jsObj) { + if (typeof jsObj.port == 'undefined') { + throw new Error("Bad XML provided, expected tagName port, got: " + Object.keys(jsObj)[0]); + } + + var port = new ns.Port(); + jsObj = jsObj.port; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return port; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + port.x = parseFloat(attributes.x); + port.y = parseFloat(attributes.y); + port.id = attributes.id || null; + } + port.baseFromObj(jsObj); + return port; +}; + +ns.Port = Port; +// ------- END PORT ------- + +// ------- ARC ------- +/** + * Represents the <arc> element. + * @class Arc + * @param {Object} params + * @param {string=} params.id + * @param {string=} params.class_ + * @param {string=} params.source + * @param {string=} params.target + * @param {StartType=} params.start + * @param {EndType=} params.end + * @param {NextType=} params.nexts + * @param {Glyph[]=} params.glyphs The arc's cardinality. Possibility to have more than one glyph is left open. + */ +var Arc = function (params) { + ns.SBGNBase.call(this, params); + var params = checkParams(params, ['id', 'class_', 'source', 'target', 'start', 'end', 'nexts', 'glyphs']); + this.id = params.id; + this.class_ = params.class_; + this.source = params.source; + this.target = params.target; + + this.start = params.start; + this.end = params.end; + this.nexts = params.nexts || []; + this.glyphs = params.glyphs || []; +}; + +Arc.prototype = Object.create(ns.SBGNBase.prototype); +Arc.prototype.constructor = ns.Arc; + +/** + * @param {StartType} start + */ +Arc.prototype.setStart = function (start) { + this.start = start; +}; + +/** + * @param {EndType} end + */ +Arc.prototype.setEnd = function (end) { + this.end = end; +}; + +/** + * @param {NextType} next + */ +Arc.prototype.addNext = function (next) { + this.nexts.push(next); +}; + +/** + * @param {Glyph} glyph + */ +Arc.prototype.addGlyph = function (glyph) { + this.glyphs.push(glyph); +}; + +/** + * @return {Object} - xml2js formatted object + */ +Arc.prototype.buildJsObj = function () { + var arcObj = {}; + + // attributes + var attributes = {}; + if(this.id != null) { + attributes.id = this.id; + } + if(this.class_ != null) { + attributes.class = this.class_; + } + if(this.source != null) { + attributes.source = this.source; + } + if(this.target != null) { + attributes.target = this.target; + } + utils.addAttributes(arcObj, attributes); + + // children + this.baseToJsObj(arcObj); + for(var i=0; i < this.glyphs.length; i++) { + if (i==0) { + arcObj.glyph = []; + } + arcObj.glyph.push(this.glyphs[i].buildJsObj()); + } + if(this.start != null) { + arcObj.start = this.start.buildJsObj(); + } + if(this.state != null) { + arcObj.state = this.state.buildJsObj(); + } + for(var i=0; i < this.nexts.length; i++) { + if (i==0) { + arcObj.next = []; + } + arcObj.next.push(this.nexts[i].buildJsObj()); + } + if(this.end != null) { + arcObj.end = this.end.buildJsObj(); + } + return arcObj; +}; + +/** + * @return {string} + */ +Arc.prototype.toXML = function () { + return utils.buildString({arc: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {Arc} + */ +Arc.fromXML = function (string) { + var arc; + function fn (err, result) { + arc = Arc.fromObj(result); + }; + utils.parseString(string, fn); + return arc; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {Arc} + */ +Arc.fromObj = function (jsObj) { + if (typeof jsObj.arc == 'undefined') { + throw new Error("Bad XML provided, expected tagName arc, got: " + Object.keys(jsObj)[0]); + } + + var arc = new ns.Arc(); + jsObj = jsObj.arc; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return arc; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + arc.id = attributes.id || null; + arc.class_ = attributes.class || null; + arc.source = attributes.source || null; + arc.target = attributes.target || null; + } + + // children + if(jsObj.start) { + var start = ns.StartType.fromObj({start: jsObj.start[0]}); + arc.setStart(start); + } + if(jsObj.next) { + var nexts = jsObj.next; + for (var i=0; i < nexts.length; i++) { + var next = ns.NextType.fromObj({next: nexts[i]}); + arc.addNext(next); + } + } + if(jsObj.end) { + var end = ns.EndType.fromObj({end: jsObj.end[0]}); + arc.setEnd(end); + } + if(jsObj.glyph) { + var glyphs = jsObj.glyph; + for (var i=0; i < glyphs.length; i++) { + var glyph = ns.Glyph.fromObj({glyph: glyphs[i]}); + arc.addGlyph(glyph); + } + } + + arc.baseFromObj(jsObj); + return arc; +}; + +ns.Arc = Arc; +// ------- END ARC ------- + +// ------- STARTTYPE ------- +/** + * Represents the <start> element. + * @class StartType + * @param {Object} params + * @param {string|number=} params.x + * @param {string|number=} params.y + */ +var StartType = function (params) { + var params = checkParams(params, ['x', 'y']); + this.x = parseFloat(params.x); + this.y = parseFloat(params.y); +}; + +/** + * @return {Object} - xml2js formatted object + */ +StartType.prototype.buildJsObj = function () { + var startObj = {}; + + // attributes + var attributes = {}; + if(!isNaN(this.x)) { + attributes.x = this.x; + } + if(!isNaN(this.y)) { + attributes.y = this.y; + } + utils.addAttributes(startObj, attributes); + return startObj; +}; + +/** + * @return {string} + */ +StartType.prototype.toXML = function () { + return utils.buildString({start: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {StartType} + */ +StartType.fromXML = function (string) { + var start; + function fn (err, result) { + start = StartType.fromObj(result); + }; + utils.parseString(string, fn); + return start; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {StartType} + */ +StartType.fromObj = function (jsObj) { + if (typeof jsObj.start == 'undefined') { + throw new Error("Bad XML provided, expected tagName start, got: " + Object.keys(jsObj)[0]); + } + + var start = new ns.StartType(); + jsObj = jsObj.start; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return start; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + start.x = parseFloat(attributes.x); + start.y = parseFloat(attributes.y); + } + return start; +}; + +ns.StartType = StartType; +// ------- END STARTTYPE ------- + +// ------- ENDTYPE ------- +/** + * Represents the <end> element. + * @class EndType + * @param {Object} params + * @param {string|number=} params.x + * @param {string|number=} params.y + */ +var EndType = function (params) { + var params = checkParams(params, ['x', 'y']); + this.x = parseFloat(params.x); + this.y = parseFloat(params.y); +}; + +/** + * @return {Object} - xml2js formatted object + */ +EndType.prototype.buildJsObj = function () { + var endObj = {}; + + // attributes + var attributes = {}; + if(!isNaN(this.x)) { + attributes.x = this.x; + } + if(!isNaN(this.y)) { + attributes.y = this.y; + } + utils.addAttributes(endObj, attributes); + return endObj; +}; + +/** + * @return {string} + */ +EndType.prototype.toXML = function () { + return utils.buildString({end: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {EndType} + */ +EndType.fromXML = function (string) { + var end; + function fn (err, result) { + end = EndType.fromObj(result); + }; + utils.parseString(string, fn); + return end; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {EndType} + */ +EndType.fromObj = function (jsObj) { + if (typeof jsObj.end == 'undefined') { + throw new Error("Bad XML provided, expected tagName end, got: " + Object.keys(jsObj)[0]); + } + + var end = new ns.EndType(); + jsObj = jsObj.end; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return end; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + end.x = parseFloat(attributes.x); + end.y = parseFloat(attributes.y); + } + return end; +}; + +ns.EndType = EndType; +// ------- END ENDTYPE ------- + +// ------- NEXTTYPE ------- +/** + * Represents the <next> element. + * @class NextType + * @param {Object} params + * @param {string|number=} params.x + * @param {string|number=} params.y + */ +var NextType = function (params) { + var params = checkParams(params, ['x', 'y']); + this.x = parseFloat(params.x); + this.y = parseFloat(params.y); +}; + +/** + * @return {Object} - xml2js formatted object + */ +NextType.prototype.buildJsObj = function () { + var nextObj = {}; + + // attributes + var attributes = {}; + if(!isNaN(this.x)) { + attributes.x = this.x; + } + if(!isNaN(this.y)) { + attributes.y = this.y; + } + utils.addAttributes(nextObj, attributes); + return nextObj; +}; + +/** + * @return {string} + */ +NextType.prototype.toXML = function () { + return utils.buildString({next: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {NextType} + */ +NextType.fromXML = function (string) { + var next; + function fn (err, result) { + next = NextType.fromObj(result); + }; + utils.parseString(string, fn); + return next; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {NextType} + */ +NextType.fromObj = function (jsObj) { + if (typeof jsObj.next == 'undefined') { + throw new Error("Bad XML provided, expected tagName next, got: " + Object.keys(jsObj)[0]); + } + + var next = new ns.NextType(); + jsObj = jsObj.next; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return next; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + next.x = parseFloat(attributes.x); + next.y = parseFloat(attributes.y); + } + return next; +}; + +ns.NextType = NextType; +// ------- END NEXTTYPE ------- + +// ------- POINT ------- +/** + * Represents the <point> element. + * @class Point + * @param {Object} params + * @param {string|number=} params.x + * @param {string|number=} params.y + */ +var Point = function (params) { + ns.SBGNBase.call(this, params); + var params = checkParams(params, ['x', 'y']); + this.x = parseFloat(params.x); + this.y = parseFloat(params.y); +}; +Point.prototype = Object.create(ns.SBGNBase.prototype); +Point.prototype.constructor = Point; + +/** + * @return {Object} - xml2js formatted object + */ +Point.prototype.buildJsObj = function () { + var pointJsObj = {}; + + // attributes + var attributes = {}; + if(!isNaN(this.x)) { + attributes.x = this.x; + } + if(!isNaN(this.y)) { + attributes.y = this.y; + } + utils.addAttributes(pointJsObj, attributes); + this.baseToJsObj(pointJsObj); + return pointJsObj; +}; + +/** + * @return {string} + */ +Point.prototype.toXML = function () { + return utils.buildString({point: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {Point} + */ +Point.fromXML = function (string) { + var point; + function fn (err, result) { + point = Point.fromObj(result); + }; + utils.parseString(string, fn); + return point; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {Point} + */ +Point.fromObj = function (jsObj) { + if (typeof jsObj.point == 'undefined') { + throw new Error("Bad XML provided, expected tagName point, got: " + Object.keys(jsObj)[0]); + } + + var point = new ns.Point(); + jsObj = jsObj.point; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return point; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + point.x = parseFloat(attributes.x); + point.y = parseFloat(attributes.y); + } + point.baseFromObj(jsObj); + return point; +}; + +ns.Point = Point; +// ------- END POINT ------- + +// ------- CALLOUT ------- +/** + * Represents the <callout> element. + * @class Callout + * @param {Object} params + * @param {string=} params.target + * @param {Point=} params.point + */ +var Callout = function (params) { + var params = checkParams(params, ['target', 'point']); + this.target = params.target; + this.point = params.point; +}; + +/** + * @param {Point} point + */ +Callout.prototype.setPoint = function(point) { + this.point = point; +}; + +/** + * @return {Object} - xml2js formatted object + */ +Callout.prototype.buildJsObj = function () { + var calloutObj = {}; + + // attributes + var attributes = {}; + if(this.target != null) { + attributes.target = this.target; + } + utils.addAttributes(calloutObj, attributes); + + // children + if(this.point != null) { + calloutObj.point = this.point.buildJsObj(); + } + return calloutObj; +}; + +/** + * @return {string} + */ +Callout.prototype.toXML = function () { + return utils.buildString({callout: this.buildJsObj()}) +}; + +/** + * @param {String} string + * @return {Callout} + */ +Callout.fromXML = function (string) { + var callout; + function fn (err, result) { + callout = Callout.fromObj(result); + }; + utils.parseString(string, fn); + return callout; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {Callout} + */ +Callout.fromObj = function (jsObj) { + if (typeof jsObj.callout == 'undefined') { + throw new Error("Bad XML provided, expected tagName callout, got: " + Object.keys(jsObj)[0]); + } + + var callout = new ns.Callout(); + jsObj = jsObj.callout; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return callout; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + callout.target = attributes.target || null; + } + + // children + if(jsObj.point) { + var point = ns.Point.fromObj({point: jsObj.point[0]}); + callout.setPoint(point); + } + return callout; +}; + +ns.Callout = Callout; +// ------- END CALLOUT ------- + +// ------- ARCGROUP ------- +/** + * Represents the <arcgroup> element. + * @class + * @extends SBGNBase + * @param {Object} params + * @param {string=} params.class_ + * @param {Glyph[]=} params.glyphs + * @param {Arc[]=} params.arcs + */ +var Arcgroup = function (params) { + ns.SBGNBase.call(this, params); + var params = checkParams(params, ['class_', 'glyphs', 'arcs']); + this.class_ = params.class_; + this.glyphs = params.glyphs || []; + this.arcs = params.arcs || []; +}; + +Arcgroup.prototype = Object.create(ns.SBGNBase.prototype); +Arcgroup.prototype.constructor = Arcgroup; + +/** + * @param {Glyph} glyph + */ +Arcgroup.prototype.addGlyph = function (glyph) { + this.glyphs.push(glyph); +}; + +/** + * @param {Arc} arc + */ +Arcgroup.prototype.addArc = function (arc) { + this.arcs.push(arc); +}; + +/** + * @return {Object} - xml2js formatted object + */ +Arcgroup.prototype.buildJsObj = function () { + var arcgroupObj = {}; + + // attributes + var attributes = {}; + if(this.class_ != null) { + attributes.class = this.class_; + } + utils.addAttributes(arcgroupObj, attributes); + + // children + this.baseToJsObj(arcgroupObj); + for(var i=0; i < this.glyphs.length; i++) { + if (i==0) { + arcgroupObj.glyph = []; + } + arcgroupObj.glyph.push(this.glyphs[i].buildJsObj()); + } + for(var i=0; i < this.arcs.length; i++) { + if (i==0) { + arcgroupObj.arc = []; + } + arcgroupObj.arc.push(this.arcs[i].buildJsObj()); + } + return arcgroupObj; +}; + +/** + * @return {string} + */ +Arcgroup.prototype.toXML = function () { + return utils.buildString({arcgroup: this.buildJsObj()}); +}; + +/** + * @param {String} string + * @return {Arcgroup} + */ +Arcgroup.fromXML = function (string) { + var arcgroup; + function fn (err, result) { + arcgroup = Arcgroup.fromObj(result); + }; + utils.parseString(string, fn); + return arcgroup; +}; + +/** + * @param {Object} jsObj - xml2js formatted object + * @return {Arcgroup} + */ +Arcgroup.fromObj = function (jsObj) { + if (typeof jsObj.arcgroup == 'undefined') { + throw new Error("Bad XML provided, expected tagName arcgroup, got: " + Object.keys(jsObj)[0]); + } + + var arcgroup = new ns.Arcgroup(); + jsObj = jsObj.arcgroup; + if(typeof jsObj != 'object') { // nothing inside, empty xml + return arcgroup; + } + + if(jsObj.$) { // we have some attributes + var attributes = jsObj.$; + arcgroup.class_ = attributes.class || null; + } + + if(jsObj.glyph) { + var glyphs = jsObj.glyph; + for (var i=0; i < glyphs.length; i++) { + var glyph = ns.Glyph.fromObj({glyph: glyphs[i]}); + arcgroup.addGlyph(glyph); + } + } + if(jsObj.arc) { + var arcs = jsObj.arc; + for (var i=0; i < arcs.length; i++) { + var arc = ns.Arc.fromObj({arc: arcs[i]}); + arcgroup.addArc(arc); + } + } + + arcgroup.baseFromObj(jsObj); + return arcgroup; +}; + +ns.Arcgroup = Arcgroup; +// ------- END ARCGROUP ------- + +ns.render = renderExt; +ns.annot = annotExt; +module.exports = ns; +},{"./libsbgn-annotations":86,"./libsbgn-render":87,"./utilities":89,"xml2js":62}],89:[function(_dereq_,module,exports){ +var ns = {}; +var xml2js = _dereq_('xml2js'); + +/* + guarantees to return an object with given args being set to null if not present, other args returned as is +*/ +ns.checkParams = function (params, names) { + if (typeof params == "undefined" || params == null) { + params = {}; + } + if (typeof params != 'object') { + throw new Error("Bad params. Object with named parameters must be passed."); + } + for(var i=0; i < names.length; i++) { + var argName = names[i]; + if (typeof params[argName] == 'undefined') { + params[argName] = null; + } + } + return params; +} + +ns.getFirstLevelByName = function (xmlObj, localName) { + var result = []; + for(var i=0; i 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; + + customizer = (assigner.length > 3 && typeof customizer == 'function') + ? (length--, customizer) + : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + object = Object(object); + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, index, customizer); + } + } + return object; + }); +} + +module.exports = createAssigner; + +},{"./_baseRest":134,"./_isIterateeCall":166}],144:[function(_dereq_,module,exports){ +var isArrayLike = _dereq_('./isArrayLike'); + +/** + * Creates a `baseEach` or `baseEachRight` function. + * + * @private + * @param {Function} eachFunc The function to iterate over a collection. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ +function createBaseEach(eachFunc, fromRight) { + return function(collection, iteratee) { + if (collection == null) { + return collection; + } + if (!isArrayLike(collection)) { + return eachFunc(collection, iteratee); + } + var length = collection.length, + index = fromRight ? length : -1, + iterable = Object(collection); + + while ((fromRight ? index-- : ++index < length)) { + if (iteratee(iterable[index], index, iterable) === false) { + break; + } + } + return collection; + }; +} + +module.exports = createBaseEach; + +},{"./isArrayLike":215}],145:[function(_dereq_,module,exports){ +/** + * Creates a base function for methods like `_.forIn` and `_.forOwn`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ +function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var index = -1, + iterable = Object(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[fromRight ? length : ++index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; +} + +module.exports = createBaseFor; + +},{}],146:[function(_dereq_,module,exports){ +var getNative = _dereq_('./_getNative'); + +var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} +}()); + +module.exports = defineProperty; + +},{"./_getNative":154}],147:[function(_dereq_,module,exports){ +var SetCache = _dereq_('./_SetCache'), + arraySome = _dereq_('./_arraySome'), + cacheHas = _dereq_('./_cacheHas'); + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG = 1, + COMPARE_UNORDERED_FLAG = 2; + +/** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `array` and `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ +function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + arrLength = array.length, + othLength = other.length; + + if (arrLength != othLength && !(isPartial && othLength > arrLength)) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(array); + if (stacked && stack.get(other)) { + return stacked == other; + } + var index = -1, + result = true, + seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; + + stack.set(array, other); + stack.set(other, array); + + // Ignore non-index properties. + while (++index < arrLength) { + var arrValue = array[index], + othValue = other[index]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, arrValue, index, other, array, stack) + : customizer(arrValue, othValue, index, array, other, stack); + } + if (compared !== undefined) { + if (compared) { + continue; + } + result = false; + break; + } + // Recursively compare arrays (susceptible to call stack limits). + if (seen) { + if (!arraySome(other, function(othValue, othIndex) { + if (!cacheHas(seen, othIndex) && + (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { + return seen.push(othIndex); + } + })) { + result = false; + break; + } + } else if (!( + arrValue === othValue || + equalFunc(arrValue, othValue, bitmask, customizer, stack) + )) { + result = false; + break; + } + } + stack['delete'](array); + stack['delete'](other); + return result; +} + +module.exports = equalArrays; + +},{"./_SetCache":97,"./_arraySome":108,"./_cacheHas":139}],148:[function(_dereq_,module,exports){ +var Symbol = _dereq_('./_Symbol'), + Uint8Array = _dereq_('./_Uint8Array'), + eq = _dereq_('./eq'), + equalArrays = _dereq_('./_equalArrays'), + mapToArray = _dereq_('./_mapToArray'), + setToArray = _dereq_('./_setToArray'); + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG = 1, + COMPARE_UNORDERED_FLAG = 2; + +/** `Object#toString` result references. */ +var boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + mapTag = '[object Map]', + numberTag = '[object Number]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + symbolTag = '[object Symbol]'; + +var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]'; + +/** Used to convert symbols to primitives and strings. */ +var symbolProto = Symbol ? Symbol.prototype : undefined, + symbolValueOf = symbolProto ? symbolProto.valueOf : undefined; + +/** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { + switch (tag) { + case dataViewTag: + if ((object.byteLength != other.byteLength) || + (object.byteOffset != other.byteOffset)) { + return false; + } + object = object.buffer; + other = other.buffer; + + case arrayBufferTag: + if ((object.byteLength != other.byteLength) || + !equalFunc(new Uint8Array(object), new Uint8Array(other))) { + return false; + } + return true; + + case boolTag: + case dateTag: + case numberTag: + // Coerce booleans to `1` or `0` and dates to milliseconds. + // Invalid dates are coerced to `NaN`. + return eq(+object, +other); + + case errorTag: + return object.name == other.name && object.message == other.message; + + case regexpTag: + case stringTag: + // Coerce regexes to strings and treat strings, primitives and objects, + // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring + // for more details. + return object == (other + ''); + + case mapTag: + var convert = mapToArray; + + case setTag: + var isPartial = bitmask & COMPARE_PARTIAL_FLAG; + convert || (convert = setToArray); + + if (object.size != other.size && !isPartial) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked) { + return stacked == other; + } + bitmask |= COMPARE_UNORDERED_FLAG; + + // Recursively compare objects (susceptible to call stack limits). + stack.set(object, other); + var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); + stack['delete'](object); + return result; + + case symbolTag: + if (symbolValueOf) { + return symbolValueOf.call(object) == symbolValueOf.call(other); + } + } + return false; +} + +module.exports = equalByTag; + +},{"./_Symbol":99,"./_Uint8Array":100,"./_equalArrays":147,"./_mapToArray":182,"./_setToArray":194,"./eq":208}],149:[function(_dereq_,module,exports){ +var getAllKeys = _dereq_('./_getAllKeys'); + +/** Used to compose bitmasks for value comparisons. */ +var COMPARE_PARTIAL_FLAG = 1; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ +function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + objProps = getAllKeys(object), + objLength = objProps.length, + othProps = getAllKeys(other), + othLength = othProps.length; + + if (objLength != othLength && !isPartial) { + return false; + } + var index = objLength; + while (index--) { + var key = objProps[index]; + if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { + return false; + } + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked && stack.get(other)) { + return stacked == other; + } + var result = true; + stack.set(object, other); + stack.set(other, object); + + var skipCtor = isPartial; + while (++index < objLength) { + key = objProps[index]; + var objValue = object[key], + othValue = other[key]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, objValue, key, other, object, stack) + : customizer(objValue, othValue, key, object, other, stack); + } + // Recursively compare objects (susceptible to call stack limits). + if (!(compared === undefined + ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) + : compared + )) { + result = false; + break; + } + skipCtor || (skipCtor = key == 'constructor'); + } + if (result && !skipCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && + ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && + typeof othCtor == 'function' && othCtor instanceof othCtor)) { + result = false; + } + } + stack['delete'](object); + stack['delete'](other); + return result; +} + +module.exports = equalObjects; + +},{"./_getAllKeys":151}],150:[function(_dereq_,module,exports){ +(function (global){ +/** Detect free variable `global` from Node.js. */ +var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + +module.exports = freeGlobal; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + +},{}],151:[function(_dereq_,module,exports){ +var baseGetAllKeys = _dereq_('./_baseGetAllKeys'), + getSymbols = _dereq_('./_getSymbols'), + keys = _dereq_('./keys'); + +/** + * Creates an array of own enumerable property names and symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ +function getAllKeys(object) { + return baseGetAllKeys(object, keys, getSymbols); +} + +module.exports = getAllKeys; + +},{"./_baseGetAllKeys":119,"./_getSymbols":156,"./keys":224}],152:[function(_dereq_,module,exports){ +var isKeyable = _dereq_('./_isKeyable'); + +/** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ +function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; +} + +module.exports = getMapData; + +},{"./_isKeyable":168}],153:[function(_dereq_,module,exports){ +var isStrictComparable = _dereq_('./_isStrictComparable'), + keys = _dereq_('./keys'); + +/** + * Gets the property names, values, and compare flags of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the match data of `object`. + */ +function getMatchData(object) { + var result = keys(object), + length = result.length; + + while (length--) { + var key = result[length], + value = object[key]; + + result[length] = [key, value, isStrictComparable(value)]; + } + return result; +} + +module.exports = getMatchData; + +},{"./_isStrictComparable":171,"./keys":224}],154:[function(_dereq_,module,exports){ +var baseIsNative = _dereq_('./_baseIsNative'), + getValue = _dereq_('./_getValue'); + +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; +} + +module.exports = getNative; + +},{"./_baseIsNative":126,"./_getValue":158}],155:[function(_dereq_,module,exports){ +var Symbol = _dereq_('./_Symbol'); + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto.toString; + +/** Built-in value references. */ +var symToStringTag = Symbol ? Symbol.toStringTag : undefined; + +/** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ +function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; +} + +module.exports = getRawTag; + +},{"./_Symbol":99}],156:[function(_dereq_,module,exports){ +var arrayFilter = _dereq_('./_arrayFilter'), + stubArray = _dereq_('./stubArray'); + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Built-in value references. */ +var propertyIsEnumerable = objectProto.propertyIsEnumerable; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeGetSymbols = Object.getOwnPropertySymbols; + +/** + * Creates an array of the own enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ +var getSymbols = !nativeGetSymbols ? stubArray : function(object) { + if (object == null) { + return []; + } + object = Object(object); + return arrayFilter(nativeGetSymbols(object), function(symbol) { + return propertyIsEnumerable.call(object, symbol); + }); +}; + +module.exports = getSymbols; + +},{"./_arrayFilter":104,"./stubArray":227}],157:[function(_dereq_,module,exports){ +var DataView = _dereq_('./_DataView'), + Map = _dereq_('./_Map'), + Promise = _dereq_('./_Promise'), + Set = _dereq_('./_Set'), + WeakMap = _dereq_('./_WeakMap'), + baseGetTag = _dereq_('./_baseGetTag'), + toSource = _dereq_('./_toSource'); + +/** `Object#toString` result references. */ +var mapTag = '[object Map]', + objectTag = '[object Object]', + promiseTag = '[object Promise]', + setTag = '[object Set]', + weakMapTag = '[object WeakMap]'; + +var dataViewTag = '[object DataView]'; + +/** Used to detect maps, sets, and weakmaps. */ +var dataViewCtorString = toSource(DataView), + mapCtorString = toSource(Map), + promiseCtorString = toSource(Promise), + setCtorString = toSource(Set), + weakMapCtorString = toSource(WeakMap); + +/** + * Gets the `toStringTag` of `value`. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +var getTag = baseGetTag; + +// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. +if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || + (Map && getTag(new Map) != mapTag) || + (Promise && getTag(Promise.resolve()) != promiseTag) || + (Set && getTag(new Set) != setTag) || + (WeakMap && getTag(new WeakMap) != weakMapTag)) { + getTag = function(value) { + var result = baseGetTag(value), + Ctor = result == objectTag ? value.constructor : undefined, + ctorString = Ctor ? toSource(Ctor) : ''; + + if (ctorString) { + switch (ctorString) { + case dataViewCtorString: return dataViewTag; + case mapCtorString: return mapTag; + case promiseCtorString: return promiseTag; + case setCtorString: return setTag; + case weakMapCtorString: return weakMapTag; + } + } + return result; + }; +} + +module.exports = getTag; + +},{"./_DataView":90,"./_Map":93,"./_Promise":95,"./_Set":96,"./_WeakMap":101,"./_baseGetTag":120,"./_toSource":204}],158:[function(_dereq_,module,exports){ +/** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ +function getValue(object, key) { + return object == null ? undefined : object[key]; +} + +module.exports = getValue; + +},{}],159:[function(_dereq_,module,exports){ +var castPath = _dereq_('./_castPath'), + isArguments = _dereq_('./isArguments'), + isArray = _dereq_('./isArray'), + isIndex = _dereq_('./_isIndex'), + isLength = _dereq_('./isLength'), + toKey = _dereq_('./_toKey'); + +/** + * Checks if `path` exists on `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @param {Function} hasFunc The function to check properties. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + */ +function hasPath(object, path, hasFunc) { + path = castPath(path, object); + + var index = -1, + length = path.length, + result = false; + + while (++index < length) { + var key = toKey(path[index]); + if (!(result = object != null && hasFunc(object, key))) { + break; + } + object = object[key]; + } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return !!length && isLength(length) && isIndex(key, length) && + (isArray(object) || isArguments(object)); +} + +module.exports = hasPath; + +},{"./_castPath":140,"./_isIndex":165,"./_toKey":203,"./isArguments":213,"./isArray":214,"./isLength":219}],160:[function(_dereq_,module,exports){ +var nativeCreate = _dereq_('./_nativeCreate'); + +/** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ +function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; +} + +module.exports = hashClear; + +},{"./_nativeCreate":185}],161:[function(_dereq_,module,exports){ +/** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; +} + +module.exports = hashDelete; + +},{}],162:[function(_dereq_,module,exports){ +var nativeCreate = _dereq_('./_nativeCreate'); + +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED = '__lodash_hash_undefined__'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; + } + return hasOwnProperty.call(data, key) ? data[key] : undefined; +} + +module.exports = hashGet; + +},{"./_nativeCreate":185}],163:[function(_dereq_,module,exports){ +var nativeCreate = _dereq_('./_nativeCreate'); + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); +} + +module.exports = hashHas; + +},{"./_nativeCreate":185}],164:[function(_dereq_,module,exports){ +var nativeCreate = _dereq_('./_nativeCreate'); + +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED = '__lodash_hash_undefined__'; + +/** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ +function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + return this; +} + +module.exports = hashSet; + +},{"./_nativeCreate":185}],165:[function(_dereq_,module,exports){ +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** Used to detect unsigned integer values. */ +var reIsUint = /^(?:0|[1-9]\d*)$/; + +/** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ +function isIndex(value, length) { + length = length == null ? MAX_SAFE_INTEGER : length; + return !!length && + (typeof value == 'number' || reIsUint.test(value)) && + (value > -1 && value % 1 == 0 && value < length); +} + +module.exports = isIndex; + +},{}],166:[function(_dereq_,module,exports){ +var eq = _dereq_('./eq'), + isArrayLike = _dereq_('./isArrayLike'), + isIndex = _dereq_('./_isIndex'), + isObject = _dereq_('./isObject'); + +/** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ +function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); + } + return false; +} + +module.exports = isIterateeCall; + +},{"./_isIndex":165,"./eq":208,"./isArrayLike":215,"./isObject":220}],167:[function(_dereq_,module,exports){ +var isArray = _dereq_('./isArray'), + isSymbol = _dereq_('./isSymbol'); + +/** Used to match property names within property paths. */ +var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/; + +/** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ +function isKey(value, object) { + if (isArray(value)) { + return false; + } + var type = typeof value; + if (type == 'number' || type == 'symbol' || type == 'boolean' || + value == null || isSymbol(value)) { + return true; + } + return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || + (object != null && value in Object(object)); +} + +module.exports = isKey; + +},{"./isArray":214,"./isSymbol":222}],168:[function(_dereq_,module,exports){ +/** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ +function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); +} + +module.exports = isKeyable; + +},{}],169:[function(_dereq_,module,exports){ +var coreJsData = _dereq_('./_coreJsData'); + +/** Used to detect methods masquerading as native. */ +var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; +}()); + +/** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ +function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); +} + +module.exports = isMasked; + +},{"./_coreJsData":142}],170:[function(_dereq_,module,exports){ +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ +function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; + + return value === proto; +} + +module.exports = isPrototype; + +},{}],171:[function(_dereq_,module,exports){ +var isObject = _dereq_('./isObject'); + +/** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ +function isStrictComparable(value) { + return value === value && !isObject(value); +} + +module.exports = isStrictComparable; + +},{"./isObject":220}],172:[function(_dereq_,module,exports){ +/** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ +function listCacheClear() { + this.__data__ = []; + this.size = 0; +} + +module.exports = listCacheClear; + +},{}],173:[function(_dereq_,module,exports){ +var assocIndexOf = _dereq_('./_assocIndexOf'); + +/** Used for built-in method references. */ +var arrayProto = Array.prototype; + +/** Built-in value references. */ +var splice = arrayProto.splice; + +/** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; +} + +module.exports = listCacheDelete; + +},{"./_assocIndexOf":110}],174:[function(_dereq_,module,exports){ +var assocIndexOf = _dereq_('./_assocIndexOf'); + +/** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; +} + +module.exports = listCacheGet; + +},{"./_assocIndexOf":110}],175:[function(_dereq_,module,exports){ +var assocIndexOf = _dereq_('./_assocIndexOf'); + +/** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; +} + +module.exports = listCacheHas; + +},{"./_assocIndexOf":110}],176:[function(_dereq_,module,exports){ +var assocIndexOf = _dereq_('./_assocIndexOf'); + +/** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ +function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; +} + +module.exports = listCacheSet; + +},{"./_assocIndexOf":110}],177:[function(_dereq_,module,exports){ +var Hash = _dereq_('./_Hash'), + ListCache = _dereq_('./_ListCache'), + Map = _dereq_('./_Map'); + +/** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ +function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map || ListCache), + 'string': new Hash + }; +} + +module.exports = mapCacheClear; + +},{"./_Hash":91,"./_ListCache":92,"./_Map":93}],178:[function(_dereq_,module,exports){ +var getMapData = _dereq_('./_getMapData'); + +/** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; +} + +module.exports = mapCacheDelete; + +},{"./_getMapData":152}],179:[function(_dereq_,module,exports){ +var getMapData = _dereq_('./_getMapData'); + +/** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function mapCacheGet(key) { + return getMapData(this, key).get(key); +} + +module.exports = mapCacheGet; + +},{"./_getMapData":152}],180:[function(_dereq_,module,exports){ +var getMapData = _dereq_('./_getMapData'); + +/** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function mapCacheHas(key) { + return getMapData(this, key).has(key); +} + +module.exports = mapCacheHas; + +},{"./_getMapData":152}],181:[function(_dereq_,module,exports){ +var getMapData = _dereq_('./_getMapData'); + +/** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ +function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; +} + +module.exports = mapCacheSet; + +},{"./_getMapData":152}],182:[function(_dereq_,module,exports){ +/** + * Converts `map` to its key-value pairs. + * + * @private + * @param {Object} map The map to convert. + * @returns {Array} Returns the key-value pairs. + */ +function mapToArray(map) { + var index = -1, + result = Array(map.size); + + map.forEach(function(value, key) { + result[++index] = [key, value]; + }); + return result; +} + +module.exports = mapToArray; + +},{}],183:[function(_dereq_,module,exports){ +/** + * A specialized version of `matchesProperty` for source values suitable + * for strict equality comparisons, i.e. `===`. + * + * @private + * @param {string} key The key of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ +function matchesStrictComparable(key, srcValue) { + return function(object) { + if (object == null) { + return false; + } + return object[key] === srcValue && + (srcValue !== undefined || (key in Object(object))); + }; +} + +module.exports = matchesStrictComparable; + +},{}],184:[function(_dereq_,module,exports){ +var memoize = _dereq_('./memoize'); + +/** Used as the maximum memoize cache size. */ +var MAX_MEMOIZE_SIZE = 500; + +/** + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * + * @private + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. + */ +function memoizeCapped(func) { + var result = memoize(func, function(key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); + } + return key; + }); + + var cache = result.cache; + return result; +} + +module.exports = memoizeCapped; + +},{"./memoize":225}],185:[function(_dereq_,module,exports){ +var getNative = _dereq_('./_getNative'); + +/* Built-in method references that are verified to be native. */ +var nativeCreate = getNative(Object, 'create'); + +module.exports = nativeCreate; + +},{"./_getNative":154}],186:[function(_dereq_,module,exports){ +var overArg = _dereq_('./_overArg'); + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeKeys = overArg(Object.keys, Object); + +module.exports = nativeKeys; + +},{"./_overArg":189}],187:[function(_dereq_,module,exports){ +var freeGlobal = _dereq_('./_freeGlobal'); + +/** Detect free variable `exports`. */ +var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports = freeModule && freeModule.exports === freeExports; + +/** Detect free variable `process` from Node.js. */ +var freeProcess = moduleExports && freeGlobal.process; + +/** Used to access faster Node.js helpers. */ +var nodeUtil = (function() { + try { + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} +}()); + +module.exports = nodeUtil; + +},{"./_freeGlobal":150}],188:[function(_dereq_,module,exports){ +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto.toString; + +/** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ +function objectToString(value) { + return nativeObjectToString.call(value); +} + +module.exports = objectToString; + +},{}],189:[function(_dereq_,module,exports){ +/** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ +function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; +} + +module.exports = overArg; + +},{}],190:[function(_dereq_,module,exports){ +var apply = _dereq_('./_apply'); + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeMax = Math.max; + +/** + * A specialized version of `baseRest` which transforms the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. + */ +function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); + + while (++index < length) { + array[index] = args[start + index]; + } + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); + }; +} + +module.exports = overRest; + +},{"./_apply":102}],191:[function(_dereq_,module,exports){ +var freeGlobal = _dereq_('./_freeGlobal'); + +/** Detect free variable `self`. */ +var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + +/** Used as a reference to the global object. */ +var root = freeGlobal || freeSelf || Function('return this')(); + +module.exports = root; + +},{"./_freeGlobal":150}],192:[function(_dereq_,module,exports){ +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED = '__lodash_hash_undefined__'; + +/** + * Adds `value` to the array cache. + * + * @private + * @name add + * @memberOf SetCache + * @alias push + * @param {*} value The value to cache. + * @returns {Object} Returns the cache instance. + */ +function setCacheAdd(value) { + this.__data__.set(value, HASH_UNDEFINED); + return this; +} + +module.exports = setCacheAdd; + +},{}],193:[function(_dereq_,module,exports){ +/** + * Checks if `value` is in the array cache. + * + * @private + * @name has + * @memberOf SetCache + * @param {*} value The value to search for. + * @returns {number} Returns `true` if `value` is found, else `false`. + */ +function setCacheHas(value) { + return this.__data__.has(value); +} + +module.exports = setCacheHas; + +},{}],194:[function(_dereq_,module,exports){ +/** + * Converts `set` to an array of its values. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the values. + */ +function setToArray(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = value; + }); + return result; +} + +module.exports = setToArray; + +},{}],195:[function(_dereq_,module,exports){ +var baseSetToString = _dereq_('./_baseSetToString'), + shortOut = _dereq_('./_shortOut'); + +/** + * Sets the `toString` method of `func` to return `string`. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ +var setToString = shortOut(baseSetToString); + +module.exports = setToString; + +},{"./_baseSetToString":135,"./_shortOut":196}],196:[function(_dereq_,module,exports){ +/** Used to detect hot functions by number of calls within a span of milliseconds. */ +var HOT_COUNT = 800, + HOT_SPAN = 16; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeNow = Date.now; + +/** + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. + * + * @private + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. + */ +function shortOut(func) { + var count = 0, + lastCalled = 0; + + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; +} + +module.exports = shortOut; + +},{}],197:[function(_dereq_,module,exports){ +var ListCache = _dereq_('./_ListCache'); + +/** + * Removes all key-value entries from the stack. + * + * @private + * @name clear + * @memberOf Stack + */ +function stackClear() { + this.__data__ = new ListCache; + this.size = 0; +} + +module.exports = stackClear; + +},{"./_ListCache":92}],198:[function(_dereq_,module,exports){ +/** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ +function stackDelete(key) { + var data = this.__data__, + result = data['delete'](key); + + this.size = data.size; + return result; +} + +module.exports = stackDelete; + +},{}],199:[function(_dereq_,module,exports){ +/** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ +function stackGet(key) { + return this.__data__.get(key); +} + +module.exports = stackGet; + +},{}],200:[function(_dereq_,module,exports){ +/** + * Checks if a stack value for `key` exists. + * + * @private + * @name has + * @memberOf Stack + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ +function stackHas(key) { + return this.__data__.has(key); +} + +module.exports = stackHas; + +},{}],201:[function(_dereq_,module,exports){ +var ListCache = _dereq_('./_ListCache'), + Map = _dereq_('./_Map'), + MapCache = _dereq_('./_MapCache'); + +/** Used as the size to enable large array optimizations. */ +var LARGE_ARRAY_SIZE = 200; + +/** + * Sets the stack `key` to `value`. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the stack cache instance. + */ +function stackSet(key, value) { + var data = this.__data__; + if (data instanceof ListCache) { + var pairs = data.__data__; + if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { + pairs.push([key, value]); + this.size = ++data.size; + return this; + } + data = this.__data__ = new MapCache(pairs); + } + data.set(key, value); + this.size = data.size; + return this; +} + +module.exports = stackSet; + +},{"./_ListCache":92,"./_Map":93,"./_MapCache":94}],202:[function(_dereq_,module,exports){ +var memoizeCapped = _dereq_('./_memoizeCapped'); + +/** Used to match property names within property paths. */ +var reLeadingDot = /^\./, + rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; + +/** Used to match backslashes in property paths. */ +var reEscapeChar = /\\(\\)?/g; + +/** + * Converts `string` to a property path array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. + */ +var stringToPath = memoizeCapped(function(string) { + var result = []; + if (reLeadingDot.test(string)) { + result.push(''); + } + string.replace(rePropName, function(match, number, quote, string) { + result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; +}); + +module.exports = stringToPath; + +},{"./_memoizeCapped":184}],203:[function(_dereq_,module,exports){ +var isSymbol = _dereq_('./isSymbol'); + +/** Used as references for various `Number` constants. */ +var INFINITY = 1 / 0; + +/** + * Converts `value` to a string key if it's not a string or symbol. + * + * @private + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. + */ +function toKey(value) { + if (typeof value == 'string' || isSymbol(value)) { + return value; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; +} + +module.exports = toKey; + +},{"./isSymbol":222}],204:[function(_dereq_,module,exports){ +/** Used for built-in method references. */ +var funcProto = Function.prototype; + +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; + +/** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ +function toSource(func) { + if (func != null) { + try { + return funcToString.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; +} + +module.exports = toSource; + +},{}],205:[function(_dereq_,module,exports){ +var assignValue = _dereq_('./_assignValue'), + copyObject = _dereq_('./_copyObject'), + createAssigner = _dereq_('./_createAssigner'), + isArrayLike = _dereq_('./isArrayLike'), + isPrototype = _dereq_('./_isPrototype'), + keys = _dereq_('./keys'); + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Assigns own enumerable string keyed properties of source objects to the + * destination object. Source objects are applied from left to right. + * Subsequent sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object` and is loosely based on + * [`Object.assign`](https://mdn.io/Object/assign). + * + * @static + * @memberOf _ + * @since 0.10.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.assignIn + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * function Bar() { + * this.c = 3; + * } + * + * Foo.prototype.b = 2; + * Bar.prototype.d = 4; + * + * _.assign({ 'a': 0 }, new Foo, new Bar); + * // => { 'a': 1, 'c': 3 } + */ +var assign = createAssigner(function(object, source) { + if (isPrototype(source) || isArrayLike(source)) { + copyObject(source, keys(source), object); + return; + } + for (var key in source) { + if (hasOwnProperty.call(source, key)) { + assignValue(object, key, source[key]); + } + } +}); + +module.exports = assign; + +},{"./_assignValue":109,"./_copyObject":141,"./_createAssigner":143,"./_isPrototype":170,"./isArrayLike":215,"./keys":224}],206:[function(_dereq_,module,exports){ +/** + * Creates a function that returns `value`. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Util + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new constant function. + * @example + * + * var objects = _.times(2, _.constant({ 'a': 1 })); + * + * console.log(objects); + * // => [{ 'a': 1 }, { 'a': 1 }] + * + * console.log(objects[0] === objects[1]); + * // => true + */ +function constant(value) { + return function() { + return value; + }; +} + +module.exports = constant; + +},{}],207:[function(_dereq_,module,exports){ +var baseAssign = _dereq_('./_baseAssign'), + baseCreate = _dereq_('./_baseCreate'); + +/** + * Creates an object that inherits from the `prototype` object. If a + * `properties` object is given, its own enumerable string keyed properties + * are assigned to the created object. + * + * @static + * @memberOf _ + * @since 2.3.0 + * @category Object + * @param {Object} prototype The object to inherit from. + * @param {Object} [properties] The properties to assign to the object. + * @returns {Object} Returns the new object. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * function Circle() { + * Shape.call(this); + * } + * + * Circle.prototype = _.create(Shape.prototype, { + * 'constructor': Circle + * }); + * + * var circle = new Circle; + * circle instanceof Circle; + * // => true + * + * circle instanceof Shape; + * // => true + */ +function create(prototype, properties) { + var result = baseCreate(prototype); + return properties == null ? result : baseAssign(result, properties); +} + +module.exports = create; + +},{"./_baseAssign":111,"./_baseCreate":113}],208:[function(_dereq_,module,exports){ +/** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ +function eq(value, other) { + return value === other || (value !== value && other !== other); +} + +module.exports = eq; + +},{}],209:[function(_dereq_,module,exports){ +var arrayEvery = _dereq_('./_arrayEvery'), + baseEvery = _dereq_('./_baseEvery'), + baseIteratee = _dereq_('./_baseIteratee'), + isArray = _dereq_('./isArray'), + isIterateeCall = _dereq_('./_isIterateeCall'); + +/** + * Checks if `predicate` returns truthy for **all** elements of `collection`. + * Iteration is stopped once `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index|key, collection). + * + * **Note:** This method returns `true` for + * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because + * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of + * elements of empty collections. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * _.every([true, 1, null, 'yes'], Boolean); + * // => false + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.every(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // The `_.matchesProperty` iteratee shorthand. + * _.every(users, ['active', false]); + * // => true + * + * // The `_.property` iteratee shorthand. + * _.every(users, 'active'); + * // => false + */ +function every(collection, predicate, guard) { + var func = isArray(collection) ? arrayEvery : baseEvery; + if (guard && isIterateeCall(collection, predicate, guard)) { + predicate = undefined; + } + return func(collection, baseIteratee(predicate, 3)); +} + +module.exports = every; + +},{"./_arrayEvery":103,"./_baseEvery":115,"./_baseIteratee":128,"./_isIterateeCall":166,"./isArray":214}],210:[function(_dereq_,module,exports){ +var baseGet = _dereq_('./_baseGet'); + +/** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.get(object, 'a[0].b.c'); + * // => 3 + * + * _.get(object, ['a', '0', 'b', 'c']); + * // => 3 + * + * _.get(object, 'a.b.c', 'default'); + * // => 'default' + */ +function get(object, path, defaultValue) { + var result = object == null ? undefined : baseGet(object, path); + return result === undefined ? defaultValue : result; +} + +module.exports = get; + +},{"./_baseGet":118}],211:[function(_dereq_,module,exports){ +var baseHasIn = _dereq_('./_baseHasIn'), + hasPath = _dereq_('./_hasPath'); + +/** + * Checks if `path` is a direct or inherited property of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.hasIn(object, 'a'); + * // => true + * + * _.hasIn(object, 'a.b'); + * // => true + * + * _.hasIn(object, ['a', 'b']); + * // => true + * + * _.hasIn(object, 'b'); + * // => false + */ +function hasIn(object, path) { + return object != null && hasPath(object, path, baseHasIn); +} + +module.exports = hasIn; + +},{"./_baseHasIn":121,"./_hasPath":159}],212:[function(_dereq_,module,exports){ +/** + * This method returns the first argument it receives. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'a': 1 }; + * + * console.log(_.identity(object) === object); + * // => true + */ +function identity(value) { + return value; +} + +module.exports = identity; + +},{}],213:[function(_dereq_,module,exports){ +var baseIsArguments = _dereq_('./_baseIsArguments'), + isObjectLike = _dereq_('./isObjectLike'); + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** Built-in value references. */ +var propertyIsEnumerable = objectProto.propertyIsEnumerable; + +/** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ +var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); +}; + +module.exports = isArguments; + +},{"./_baseIsArguments":122,"./isObjectLike":221}],214:[function(_dereq_,module,exports){ +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ +var isArray = Array.isArray; + +module.exports = isArray; + +},{}],215:[function(_dereq_,module,exports){ +var isFunction = _dereq_('./isFunction'), + isLength = _dereq_('./isLength'); + +/** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ +function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); +} + +module.exports = isArrayLike; + +},{"./isFunction":218,"./isLength":219}],216:[function(_dereq_,module,exports){ +var root = _dereq_('./_root'), + stubFalse = _dereq_('./stubFalse'); + +/** Detect free variable `exports`. */ +var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports = freeModule && freeModule.exports === freeExports; + +/** Built-in value references. */ +var Buffer = moduleExports ? root.Buffer : undefined; + +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined; + +/** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ +var isBuffer = nativeIsBuffer || stubFalse; + +module.exports = isBuffer; + +},{"./_root":191,"./stubFalse":228}],217:[function(_dereq_,module,exports){ +var baseKeys = _dereq_('./_baseKeys'), + getTag = _dereq_('./_getTag'), + isArguments = _dereq_('./isArguments'), + isArray = _dereq_('./isArray'), + isArrayLike = _dereq_('./isArrayLike'), + isBuffer = _dereq_('./isBuffer'), + isPrototype = _dereq_('./_isPrototype'), + isTypedArray = _dereq_('./isTypedArray'); + +/** `Object#toString` result references. */ +var mapTag = '[object Map]', + setTag = '[object Set]'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Checks if `value` is an empty object, collection, map, or set. + * + * Objects are considered empty if they have no own enumerable string keyed + * properties. + * + * Array-like values such as `arguments` objects, arrays, buffers, strings, or + * jQuery-like collections are considered empty if they have a `length` of `0`. + * Similarly, maps and sets are considered empty if they have a `size` of `0`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is empty, else `false`. + * @example + * + * _.isEmpty(null); + * // => true + * + * _.isEmpty(true); + * // => true + * + * _.isEmpty(1); + * // => true + * + * _.isEmpty([1, 2, 3]); + * // => false + * + * _.isEmpty({ 'a': 1 }); + * // => false + */ +function isEmpty(value) { + if (value == null) { + return true; + } + if (isArrayLike(value) && + (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || + isBuffer(value) || isTypedArray(value) || isArguments(value))) { + return !value.length; + } + var tag = getTag(value); + if (tag == mapTag || tag == setTag) { + return !value.size; + } + if (isPrototype(value)) { + return !baseKeys(value).length; + } + for (var key in value) { + if (hasOwnProperty.call(value, key)) { + return false; + } + } + return true; +} + +module.exports = isEmpty; + +},{"./_baseKeys":129,"./_getTag":157,"./_isPrototype":170,"./isArguments":213,"./isArray":214,"./isArrayLike":215,"./isBuffer":216,"./isTypedArray":223}],218:[function(_dereq_,module,exports){ +var baseGetTag = _dereq_('./_baseGetTag'), + isObject = _dereq_('./isObject'); + +/** `Object#toString` result references. */ +var asyncTag = '[object AsyncFunction]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + proxyTag = '[object Proxy]'; + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; +} + +module.exports = isFunction; + +},{"./_baseGetTag":120,"./isObject":220}],219:[function(_dereq_,module,exports){ +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ +function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +module.exports = isLength; + +},{}],220:[function(_dereq_,module,exports){ +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); +} + +module.exports = isObject; + +},{}],221:[function(_dereq_,module,exports){ +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { + return value != null && typeof value == 'object'; +} + +module.exports = isObjectLike; + +},{}],222:[function(_dereq_,module,exports){ +var baseGetTag = _dereq_('./_baseGetTag'), + isObjectLike = _dereq_('./isObjectLike'); + +/** `Object#toString` result references. */ +var symbolTag = '[object Symbol]'; + +/** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ +function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); +} + +module.exports = isSymbol; + +},{"./_baseGetTag":120,"./isObjectLike":221}],223:[function(_dereq_,module,exports){ +var baseIsTypedArray = _dereq_('./_baseIsTypedArray'), + baseUnary = _dereq_('./_baseUnary'), + nodeUtil = _dereq_('./_nodeUtil'); + +/* Node.js helper references. */ +var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + +/** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ +var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + +module.exports = isTypedArray; + +},{"./_baseIsTypedArray":127,"./_baseUnary":138,"./_nodeUtil":187}],224:[function(_dereq_,module,exports){ +var arrayLikeKeys = _dereq_('./_arrayLikeKeys'), + baseKeys = _dereq_('./_baseKeys'), + isArrayLike = _dereq_('./isArrayLike'); + +/** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * for more details. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ +function keys(object) { + return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); +} + +module.exports = keys; + +},{"./_arrayLikeKeys":105,"./_baseKeys":129,"./isArrayLike":215}],225:[function(_dereq_,module,exports){ +var MapCache = _dereq_('./_MapCache'); + +/** Error message constants. */ +var FUNC_ERROR_TEXT = 'Expected a function'; + +/** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided, it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is used as the map cache key. The `func` + * is invoked with the `this` binding of the memoized function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the + * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoized function. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * var other = { 'c': 3, 'd': 4 }; + * + * var values = _.memoize(_.values); + * values(object); + * // => [1, 2] + * + * values(other); + * // => [3, 4] + * + * object.a = 2; + * values(object); + * // => [1, 2] + * + * // Modify the result cache. + * values.cache.set(object, ['a', 'b']); + * values(object); + * // => ['a', 'b'] + * + * // Replace `_.memoize.Cache`. + * _.memoize.Cache = WeakMap; + */ +function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var args = arguments, + key = resolver ? resolver.apply(this, args) : args[0], + cache = memoized.cache; + + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, args); + memoized.cache = cache.set(key, result) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || MapCache); + return memoized; +} + +// Expose `MapCache`. +memoize.Cache = MapCache; + +module.exports = memoize; + +},{"./_MapCache":94}],226:[function(_dereq_,module,exports){ +var baseProperty = _dereq_('./_baseProperty'), + basePropertyDeep = _dereq_('./_basePropertyDeep'), + isKey = _dereq_('./_isKey'), + toKey = _dereq_('./_toKey'); + +/** + * Creates a function that returns the value at `path` of a given object. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Util + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + * @example + * + * var objects = [ + * { 'a': { 'b': 2 } }, + * { 'a': { 'b': 1 } } + * ]; + * + * _.map(objects, _.property('a.b')); + * // => [2, 1] + * + * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b'); + * // => [1, 2] + */ +function property(path) { + return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path); +} + +module.exports = property; + +},{"./_baseProperty":132,"./_basePropertyDeep":133,"./_isKey":167,"./_toKey":203}],227:[function(_dereq_,module,exports){ +/** + * This method returns a new empty array. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {Array} Returns the new empty array. + * @example + * + * var arrays = _.times(2, _.stubArray); + * + * console.log(arrays); + * // => [[], []] + * + * console.log(arrays[0] === arrays[1]); + * // => false + */ +function stubArray() { + return []; +} + +module.exports = stubArray; + +},{}],228:[function(_dereq_,module,exports){ +/** + * This method returns `false`. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {boolean} Returns `false`. + * @example + * + * _.times(2, _.stubFalse); + * // => [false, false] + */ +function stubFalse() { + return false; +} + +module.exports = stubFalse; + +},{}],229:[function(_dereq_,module,exports){ +var baseToString = _dereq_('./_baseToString'); + +/** + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' + */ +function toString(value) { + return value == null ? '' : baseToString(value); +} + +module.exports = toString; + +},{"./_baseToString":137}],230:[function(_dereq_,module,exports){ +// Replace local require by a lazy loader +var globalRequire = _dereq_; +_dereq_ = function () {}; + +// Expose submodules +var exports = module.exports = { + Lexer: _dereq_('./lib/N3Lexer'), + Parser: _dereq_('./lib/N3Parser'), + Writer: _dereq_('./lib/N3Writer'), + Store: _dereq_('./lib/N3Store'), + StreamParser: _dereq_('./lib/N3StreamParser'), + StreamWriter: _dereq_('./lib/N3StreamWriter'), + Util: _dereq_('./lib/N3Util'), +}; + +// Load submodules on first access +Object.keys(exports).forEach(function (submodule) { + Object.defineProperty(exports, submodule, { + configurable: true, + enumerable: true, + get: function () { + delete exports[submodule]; + return exports[submodule] = globalRequire('./lib/N3' + submodule); + }, + }); +}); + +},{"./lib/N3Lexer":231,"./lib/N3Parser":232,"./lib/N3Store":233,"./lib/N3StreamParser":234,"./lib/N3StreamWriter":235,"./lib/N3Util":236,"./lib/N3Writer":237}],231:[function(_dereq_,module,exports){ +// **N3Lexer** tokenizes N3 documents. +var fromCharCode = String.fromCharCode; +var immediately = typeof setImmediate === 'function' ? setImmediate : + function setImmediate(func) { setTimeout(func, 0); }; + +// Regular expression and replacement string to escape N3 strings. +// Note how we catch invalid unicode sequences separately (they will trigger an error). +var escapeSequence = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{8})|\\[uU]|\\(.)/g; +var escapeReplacements = { + '\\': '\\', "'": "'", '"': '"', + 'n': '\n', 'r': '\r', 't': '\t', 'f': '\f', 'b': '\b', + '_': '_', '~': '~', '.': '.', '-': '-', '!': '!', '$': '$', '&': '&', + '(': '(', ')': ')', '*': '*', '+': '+', ',': ',', ';': ';', '=': '=', + '/': '/', '?': '?', '#': '#', '@': '@', '%': '%', +}; +var illegalIriChars = /[\x00-\x20<>\\"\{\}\|\^\`]/; + +// ## Constructor +function N3Lexer(options) { + if (!(this instanceof N3Lexer)) + return new N3Lexer(options); + options = options || {}; + + // In line mode (N-Triples or N-Quads), only simple features may be parsed + if (options.lineMode) { + // Don't tokenize special literals + this._tripleQuotedString = this._number = this._boolean = /$0^/; + // Swap the tokenize method for a restricted version + var self = this; + this._tokenize = this.tokenize; + this.tokenize = function (input, callback) { + this._tokenize(input, function (error, token) { + if (!error && /^(?:IRI|blank|literal|langcode|typeIRI|\.|eof)$/.test(token.type)) + callback && callback(error, token); + else + callback && callback(error || self._syntaxError(token.type, callback = null)); + }); + }; + } + // Enable N3 functionality by default + this._n3Mode = options.n3 !== false; + // Disable comment tokens by default + this._comments = !!options.comments; +} + +N3Lexer.prototype = { + // ## Regular expressions + // It's slightly faster to have these as properties than as in-scope variables + + _iri: /^<((?:[^ <>{}\\]|\\[uU])+)>[ \t]*/, // IRI with escape sequences; needs sanity check after unescaping + _unescapedIri: /^<([^\x00-\x20<>\\"\{\}\|\^\`]*)>[ \t]*/, // IRI without escape sequences; no unescaping + _unescapedString: /^"[^"\\\r\n]+"/, // non-empty string without escape sequences + _singleQuotedString: /^"(?:[^"\\\r\n]|\\.)*"(?=[^"])|^'(?:[^'\\\r\n]|\\.)*'(?=[^'])/, + _tripleQuotedString: /^""("[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*")""|^''('[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*')''/, + _langcode: /^@([a-z]+(?:-[a-z0-9]+)*)(?=[^a-z0-9\-])/i, + _prefix: /^((?:[A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:(?=[#\s<])/, + _prefixed: /^((?:[A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:((?:(?:[0-:A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])(?:(?:[\.\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])*(?:[\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~]))?)?)(?:[ \t]+|(?=\.?[,;!\^\s#()\[\]\{\}"'<]))/, + _variable: /^\?(?:(?:[A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:[\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)(?=[.,;!\^\s#()\[\]\{\}"'<])/, + _blank: /^_:((?:[0-9A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)(?:[ \t]+|(?=\.?[,;:\s#()\[\]\{\}"'<]))/, + _number: /^[\-+]?(?:\d+\.?\d*([eE](?:[\-\+])?\d+)|\d*\.?\d+)(?=\.?[,;:\s#()\[\]\{\}"'<])/, + _boolean: /^(?:true|false)(?=[.,;\s#()\[\]\{\}"'<])/, + _keyword: /^@[a-z]+(?=[\s#<:])/i, + _sparqlKeyword: /^(?:PREFIX|BASE|GRAPH)(?=[\s#<])/i, + _shortPredicates: /^a(?=\s+|<)/, + _newline: /^[ \t]*(?:#[^\n\r]*)?(?:\r\n|\n|\r)[ \t]*/, + _comment: /#([^\n\r]*)/, + _whitespace: /^[ \t]+/, + _endOfFile: /^(?:#[^\n\r]*)?$/, + + // ## Private methods + + // ### `_tokenizeToEnd` tokenizes as for as possible, emitting tokens through the callback + _tokenizeToEnd: function (callback, inputFinished) { + // Continue parsing as far as possible; the loop will return eventually + var input = this._input, outputComments = this._comments; + while (true) { + // Count and skip whitespace lines + var whiteSpaceMatch, comment; + while (whiteSpaceMatch = this._newline.exec(input)) { + // Try to find a comment + if (outputComments && (comment = this._comment.exec(whiteSpaceMatch[0]))) + callback(null, { line: this._line, type: 'comment', value: comment[1], prefix: '' }); + // Advance the input + input = input.substr(whiteSpaceMatch[0].length, input.length); + this._line++; + } + // Skip whitespace on current line + if (whiteSpaceMatch = this._whitespace.exec(input)) + input = input.substr(whiteSpaceMatch[0].length, input.length); + + // Stop for now if we're at the end + if (this._endOfFile.test(input)) { + // If the input is finished, emit EOF + if (inputFinished) { + // Try to find a final comment + if (outputComments && (comment = this._comment.exec(input))) + callback(null, { line: this._line, type: 'comment', value: comment[1], prefix: '' }); + callback(input = null, { line: this._line, type: 'eof', value: '', prefix: '' }); + } + return this._input = input; + } + + // Look for specific token types based on the first character + var line = this._line, type = '', value = '', prefix = '', + firstChar = input[0], match = null, matchLength = 0, unescaped, inconclusive = false; + switch (firstChar) { + case '^': + // We need at least 3 tokens lookahead to distinguish ^^ and ^^pre:fixed + if (input.length < 3) + break; + // Try to match a type + else if (input[1] === '^') { + this._previousMarker = '^^'; + // Move to type IRI or prefixed name + input = input.substr(2); + if (input[0] !== '<') { + inconclusive = true; + break; + } + } + // If no type, it must be a path expression + else { + if (this._n3Mode) { + matchLength = 1; + type = '^'; + } + break; + } + // Fall through in case the type is an IRI + case '<': + // Try to find a full IRI without escape sequences + if (match = this._unescapedIri.exec(input)) + type = 'IRI', value = match[1]; + // Try to find a full IRI with escape sequences + else if (match = this._iri.exec(input)) { + unescaped = this._unescape(match[1]); + if (unescaped === null || illegalIriChars.test(unescaped)) + return reportSyntaxError(this); + type = 'IRI', value = unescaped; + } + // Try to find a backwards implication arrow + else if (this._n3Mode && input.length > 1 && input[1] === '=') + type = 'inverse', matchLength = 2, value = 'http://www.w3.org/2000/10/swap/log#implies'; + break; + + case '_': + // Try to find a blank node. Since it can contain (but not end with) a dot, + // we always need a non-dot character before deciding it is a blank node. + // Therefore, try inserting a space if we're at the end of the input. + if ((match = this._blank.exec(input)) || + inputFinished && (match = this._blank.exec(input + ' '))) + type = 'blank', prefix = '_', value = match[1]; + break; + + case '"': + case "'": + // Try to find a non-empty double-quoted literal without escape sequences + if (match = this._unescapedString.exec(input)) + type = 'literal', value = match[0]; + // Try to find any other literal wrapped in a pair of single or double quotes + else if (match = this._singleQuotedString.exec(input)) { + unescaped = this._unescape(match[0]); + if (unescaped === null) + return reportSyntaxError(this); + type = 'literal', value = unescaped.replace(/^'|'$/g, '"'); + } + // Try to find a literal wrapped in three pairs of single or double quotes + else if (match = this._tripleQuotedString.exec(input)) { + unescaped = match[1] || match[2]; + // Count the newlines and advance line counter + this._line += unescaped.split(/\r\n|\r|\n/).length - 1; + unescaped = this._unescape(unescaped); + if (unescaped === null) + return reportSyntaxError(this); + type = 'literal', value = unescaped.replace(/^'|'$/g, '"'); + } + break; + + case '?': + // Try to find a variable + if (this._n3Mode && (match = this._variable.exec(input))) + type = 'var', value = match[0]; + break; + + case '@': + // Try to find a language code + if (this._previousMarker === 'literal' && (match = this._langcode.exec(input))) + type = 'langcode', value = match[1]; + // Try to find a keyword + else if (match = this._keyword.exec(input)) + type = match[0]; + break; + + case '.': + // Try to find a dot as punctuation + if (input.length === 1 ? inputFinished : (input[1] < '0' || input[1] > '9')) { + type = '.'; + matchLength = 1; + break; + } + // Fall through to numerical case (could be a decimal dot) + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + // Try to find a number. Since it can contain (but not end with) a dot, + // we always need a non-dot character before deciding it is a number. + // Therefore, try inserting a space if we're at the end of the input. + if (match = this._number.exec(input) || + inputFinished && (match = this._number.exec(input + ' '))) { + type = 'literal'; + value = '"' + match[0] + '"^^http://www.w3.org/2001/XMLSchema#' + + (match[1] ? 'double' : (/^[+\-]?\d+$/.test(match[0]) ? 'integer' : 'decimal')); + } + break; + + case 'B': + case 'b': + case 'p': + case 'P': + case 'G': + case 'g': + // Try to find a SPARQL-style keyword + if (match = this._sparqlKeyword.exec(input)) + type = match[0].toUpperCase(); + else + inconclusive = true; + break; + + case 'f': + case 't': + // Try to match a boolean + if (match = this._boolean.exec(input)) + type = 'literal', value = '"' + match[0] + '"^^http://www.w3.org/2001/XMLSchema#boolean'; + else + inconclusive = true; + break; + + case 'a': + // Try to find an abbreviated predicate + if (match = this._shortPredicates.exec(input)) + type = 'abbreviation', value = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; + else + inconclusive = true; + break; + + case '=': + // Try to find an implication arrow or equals sign + if (this._n3Mode && input.length > 1) { + type = 'abbreviation'; + if (input[1] !== '>') + matchLength = 1, value = 'http://www.w3.org/2002/07/owl#sameAs'; + else + matchLength = 2, value = 'http://www.w3.org/2000/10/swap/log#implies'; + } + break; + + case '!': + if (!this._n3Mode) + break; + case ',': + case ';': + case '[': + case ']': + case '(': + case ')': + case '{': + case '}': + // The next token is punctuation + matchLength = 1; + type = firstChar; + break; + + default: + inconclusive = true; + } + + // Some first characters do not allow an immediate decision, so inspect more + if (inconclusive) { + // Try to find a prefix + if ((this._previousMarker === '@prefix' || this._previousMarker === 'PREFIX') && + (match = this._prefix.exec(input))) + type = 'prefix', value = match[1] || ''; + // Try to find a prefixed name. Since it can contain (but not end with) a dot, + // we always need a non-dot character before deciding it is a prefixed name. + // Therefore, try inserting a space if we're at the end of the input. + else if ((match = this._prefixed.exec(input)) || + inputFinished && (match = this._prefixed.exec(input + ' '))) + type = 'prefixed', prefix = match[1] || '', value = this._unescape(match[2]); + } + + // A type token is special: it can only be emitted after an IRI or prefixed name is read + if (this._previousMarker === '^^') { + switch (type) { + case 'prefixed': type = 'type'; break; + case 'IRI': type = 'typeIRI'; break; + default: type = ''; + } + } + + // What if nothing of the above was found? + if (!type) { + // We could be in streaming mode, and then we just wait for more input to arrive. + // Otherwise, a syntax error has occurred in the input. + // One exception: error on an unaccounted linebreak (= not inside a triple-quoted literal). + if (inputFinished || (!/^'''|^"""/.test(input) && /\n|\r/.test(input))) + return reportSyntaxError(this); + else + return this._input = input; + } + + // Emit the parsed token + var token = { line: line, type: type, value: value, prefix: prefix }; + callback(null, token); + this.previousToken = token; + this._previousMarker = type; + // Advance to next part to tokenize + input = input.substr(matchLength || match[0].length, input.length); + } + + // Signals the syntax error through the callback + function reportSyntaxError(self) { callback(self._syntaxError(/^\S*/.exec(input)[0])); } + }, + + // ### `_unescape` replaces N3 escape codes by their corresponding characters + _unescape: function (item) { + try { + return item.replace(escapeSequence, function (sequence, unicode4, unicode8, escapedChar) { + var charCode; + if (unicode4) { + charCode = parseInt(unicode4, 16); + if (isNaN(charCode)) throw new Error(); // can never happen (regex), but helps performance + return fromCharCode(charCode); + } + else if (unicode8) { + charCode = parseInt(unicode8, 16); + if (isNaN(charCode)) throw new Error(); // can never happen (regex), but helps performance + if (charCode <= 0xFFFF) return fromCharCode(charCode); + return fromCharCode(0xD800 + ((charCode -= 0x10000) / 0x400), 0xDC00 + (charCode & 0x3FF)); + } + else { + var replacement = escapeReplacements[escapedChar]; + if (!replacement) + throw new Error(); + return replacement; + } + }); + } + catch (error) { return null; } + }, + + // ### `_syntaxError` creates a syntax error for the given issue + _syntaxError: function (issue) { + this._input = null; + var err = new Error('Unexpected "' + issue + '" on line ' + this._line + '.'); + err.context = { + token: undefined, + line: this._line, + previousToken: this.previousToken, + }; + return err; + }, + + + // ## Public methods + + // ### `tokenize` starts the transformation of an N3 document into an array of tokens. + // The input can be a string or a stream. + tokenize: function (input, callback) { + var self = this; + this._line = 1; + + // If the input is a string, continuously emit tokens through the callback until the end + if (typeof input === 'string') { + this._input = input; + // If a callback was passed, asynchronously call it + if (typeof callback === 'function') + immediately(function () { self._tokenizeToEnd(callback, true); }); + // If no callback was passed, tokenize synchronously and return + else { + var tokens = [], error; + this._tokenizeToEnd(function (e, t) { e ? (error = e) : tokens.push(t); }, true); + if (error) throw error; + return tokens; + } + } + // Otherwise, the input must be a stream + else { + this._input = ''; + if (typeof input.setEncoding === 'function') + input.setEncoding('utf8'); + // Adds the data chunk to the buffer and parses as far as possible + input.on('data', function (data) { + if (self._input !== null) { + self._input += data; + self._tokenizeToEnd(callback, false); + } + }); + // Parses until the end + input.on('end', function () { + if (self._input !== null) + self._tokenizeToEnd(callback, true); + }); + input.on('error', callback); + } + }, +}; + +// ## Exports +module.exports = N3Lexer; + +},{}],232:[function(_dereq_,module,exports){ +// **N3Parser** parses N3 documents. +var N3Lexer = _dereq_('./N3Lexer'); + +var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', + RDF_NIL = RDF_PREFIX + 'nil', + RDF_FIRST = RDF_PREFIX + 'first', + RDF_REST = RDF_PREFIX + 'rest'; + +var QUANTIFIERS_GRAPH = 'urn:n3:quantifiers'; + +var absoluteIRI = /^[a-z][a-z0-9+.-]*:/i, + schemeAuthority = /^(?:([a-z][a-z0-9+.-]*:))?(?:\/\/[^\/]*)?/i, + dotSegments = /(?:^|\/)\.\.?(?:$|[\/#?])/; + +// The next ID for new blank nodes +var blankNodePrefix = 0, blankNodeCount = 0; + +// ## Constructor +function N3Parser(options) { + if (!(this instanceof N3Parser)) + return new N3Parser(options); + this._contextStack = []; + this._graph = null; + + // Set the document IRI + options = options || {}; + this._setBase(options.documentIRI); + + // Set supported features depending on the format + var format = (typeof options.format === 'string') ? + options.format.match(/\w*$/)[0].toLowerCase() : '', + isTurtle = format === 'turtle', isTriG = format === 'trig', + isNTriples = /triple/.test(format), isNQuads = /quad/.test(format), + isN3 = this._n3Mode = /n3/.test(format), + isLineMode = isNTriples || isNQuads; + if (!(this._supportsNamedGraphs = !(isTurtle || isN3))) + this._readPredicateOrNamedGraph = this._readPredicate; + this._supportsQuads = !(isTurtle || isTriG || isNTriples || isN3); + // Disable relative IRIs in N-Triples or N-Quads mode + if (isLineMode) { + this._base = ''; + this._resolveIRI = function (token) { + this._error('Disallowed relative IRI', token); + return this._callback = noop, this._subject = null; + }; + } + this._blankNodePrefix = typeof options.blankNodePrefix !== 'string' ? '' : + '_:' + options.blankNodePrefix.replace(/^_:/, ''); + this._lexer = options.lexer || new N3Lexer({ lineMode: isLineMode, n3: isN3 }); + // Disable explicit quantifiers by default + this._explicitQuantifiers = !!options.explicitQuantifiers; +} + +// ## Private class methods + +// ### `_resetBlankNodeIds` restarts blank node identification +N3Parser._resetBlankNodeIds = function () { + blankNodePrefix = blankNodeCount = 0; +}; + +N3Parser.prototype = { + // ## Private methods + + // ### `_setBase` sets the base IRI to resolve relative IRIs + _setBase: function (baseIRI) { + if (!baseIRI) + this._base = null; + else { + // Remove fragment if present + var fragmentPos = baseIRI.indexOf('#'); + if (fragmentPos >= 0) + baseIRI = baseIRI.substr(0, fragmentPos); + // Set base IRI and its components + this._base = baseIRI; + this._basePath = baseIRI.indexOf('/') < 0 ? baseIRI : + baseIRI.replace(/[^\/?]*(?:\?.*)?$/, ''); + baseIRI = baseIRI.match(schemeAuthority); + this._baseRoot = baseIRI[0]; + this._baseScheme = baseIRI[1]; + } + }, + + // ### `_saveContext` stores the current parsing context + // when entering a new scope (list, blank node, formula) + _saveContext: function (type, graph, subject, predicate, object) { + var n3Mode = this._n3Mode; + this._contextStack.push({ + subject: subject, predicate: predicate, object: object, + graph: graph, type: type, + inverse: n3Mode ? this._inversePredicate : false, + blankPrefix: n3Mode ? this._prefixes._ : '', + quantified: n3Mode ? this._quantified : null, + }); + // The settings below only apply to N3 streams + if (n3Mode) { + // Every new scope resets the predicate direction + this._inversePredicate = false; + // In N3, blank nodes are scoped to a formula + // (using a dot as separator, as a blank node label cannot start with it) + this._prefixes._ = this._graph + '.'; + // Quantifiers are scoped to a formula + this._quantified = Object.create(this._quantified); + } + }, + + // ### `_restoreContext` restores the parent context + // when leaving a scope (list, blank node, formula) + _restoreContext: function () { + var context = this._contextStack.pop(), n3Mode = this._n3Mode; + this._subject = context.subject; + this._predicate = context.predicate; + this._object = context.object; + this._graph = context.graph; + // The settings below only apply to N3 streams + if (n3Mode) { + this._inversePredicate = context.inverse; + this._prefixes._ = context.blankPrefix; + this._quantified = context.quantified; + } + }, + + // ### `_readInTopContext` reads a token when in the top context + _readInTopContext: function (token) { + switch (token.type) { + // If an EOF token arrives in the top context, signal that we're done + case 'eof': + if (this._graph !== null) + return this._error('Unclosed graph', token); + delete this._prefixes._; + return this._callback(null, null, this._prefixes); + // It could be a prefix declaration + case 'PREFIX': + this._sparqlStyle = true; + case '@prefix': + return this._readPrefix; + // It could be a base declaration + case 'BASE': + this._sparqlStyle = true; + case '@base': + return this._readBaseIRI; + // It could be a graph + case '{': + if (this._supportsNamedGraphs) { + this._graph = ''; + this._subject = null; + return this._readSubject; + } + case 'GRAPH': + if (this._supportsNamedGraphs) + return this._readNamedGraphLabel; + // Otherwise, the next token must be a subject + default: + return this._readSubject(token); + } + }, + + // ### `_readEntity` reads an IRI, prefixed name, blank node, or variable + _readEntity: function (token, quantifier) { + var value; + switch (token.type) { + // Read a relative or absolute IRI + case 'IRI': + case 'typeIRI': + value = (this._base === null || absoluteIRI.test(token.value)) ? + token.value : this._resolveIRI(token); + break; + // Read a blank node or prefixed name + case 'type': + case 'blank': + case 'prefixed': + var prefix = this._prefixes[token.prefix]; + if (prefix === undefined) + return this._error('Undefined prefix "' + token.prefix + ':"', token); + value = prefix + token.value; + break; + // Read a variable + case 'var': + return token.value; + // Everything else is not an entity + default: + return this._error('Expected entity but got ' + token.type, token); + } + // In N3 mode, replace the entity if it is quantified + if (!quantifier && this._n3Mode && (value in this._quantified)) + value = this._quantified[value]; + return value; + }, + + // ### `_readSubject` reads a triple's subject + _readSubject: function (token) { + this._predicate = null; + switch (token.type) { + case '[': + // Start a new triple with a new blank node as subject + this._saveContext('blank', this._graph, + this._subject = '_:b' + blankNodeCount++, null, null); + return this._readBlankNodeHead; + case '(': + // Start a new list + this._saveContext('list', this._graph, RDF_NIL, null, null); + this._subject = null; + return this._readListItem; + case '{': + // Start a new formula + if (!this._n3Mode) + return this._error('Unexpected graph', token); + this._saveContext('formula', this._graph, + this._graph = '_:b' + blankNodeCount++, null, null); + return this._readSubject; + case '}': + // No subject; the graph in which we are reading is closed instead + return this._readPunctuation(token); + case '@forSome': + if (!this._n3Mode) + return this._error('Unexpected "@forSome"', token); + this._subject = null; + this._predicate = 'http://www.w3.org/2000/10/swap/reify#forSome'; + this._quantifiedPrefix = '_:b'; + return this._readQuantifierList; + case '@forAll': + if (!this._n3Mode) + return this._error('Unexpected "@forAll"', token); + this._subject = null; + this._predicate = 'http://www.w3.org/2000/10/swap/reify#forAll'; + this._quantifiedPrefix = '?b-'; + return this._readQuantifierList; + default: + // Read the subject entity + if ((this._subject = this._readEntity(token)) === undefined) + return; + // In N3 mode, the subject might be a path + if (this._n3Mode) + return this._getPathReader(this._readPredicateOrNamedGraph); + } + + // The next token must be a predicate, + // or, if the subject was actually a graph IRI, a named graph + return this._readPredicateOrNamedGraph; + }, + + // ### `_readPredicate` reads a triple's predicate + _readPredicate: function (token) { + var type = token.type; + switch (type) { + case 'inverse': + this._inversePredicate = true; + case 'abbreviation': + this._predicate = token.value; + break; + case '.': + case ']': + case '}': + // Expected predicate didn't come, must have been trailing semicolon + if (this._predicate === null) + return this._error('Unexpected ' + type, token); + this._subject = null; + return type === ']' ? this._readBlankNodeTail(token) : this._readPunctuation(token); + case ';': + // Extra semicolons can be safely ignored + return this._readPredicate; + case 'blank': + if (!this._n3Mode) + return this._error('Disallowed blank node as predicate', token); + default: + if ((this._predicate = this._readEntity(token)) === undefined) + return; + } + // The next token must be an object + return this._readObject; + }, + + // ### `_readObject` reads a triple's object + _readObject: function (token) { + switch (token.type) { + case 'literal': + this._object = token.value; + return this._readDataTypeOrLang; + case '[': + // Start a new triple with a new blank node as subject + this._saveContext('blank', this._graph, this._subject, this._predicate, + this._subject = '_:b' + blankNodeCount++); + return this._readBlankNodeHead; + case '(': + // Start a new list + this._saveContext('list', this._graph, this._subject, this._predicate, RDF_NIL); + this._subject = null; + return this._readListItem; + case '{': + // Start a new formula + if (!this._n3Mode) + return this._error('Unexpected graph', token); + this._saveContext('formula', this._graph, this._subject, this._predicate, + this._graph = '_:b' + blankNodeCount++); + return this._readSubject; + default: + // Read the object entity + if ((this._object = this._readEntity(token)) === undefined) + return; + // In N3 mode, the object might be a path + if (this._n3Mode) + return this._getPathReader(this._getContextEndReader()); + } + return this._getContextEndReader(); + }, + + // ### `_readPredicateOrNamedGraph` reads a triple's predicate, or a named graph + _readPredicateOrNamedGraph: function (token) { + return token.type === '{' ? this._readGraph(token) : this._readPredicate(token); + }, + + // ### `_readGraph` reads a graph + _readGraph: function (token) { + if (token.type !== '{') + return this._error('Expected graph but got ' + token.type, token); + // The "subject" we read is actually the GRAPH's label + this._graph = this._subject, this._subject = null; + return this._readSubject; + }, + + // ### `_readBlankNodeHead` reads the head of a blank node + _readBlankNodeHead: function (token) { + if (token.type === ']') { + this._subject = null; + return this._readBlankNodeTail(token); + } + else { + this._predicate = null; + return this._readPredicate(token); + } + }, + + // ### `_readBlankNodeTail` reads the end of a blank node + _readBlankNodeTail: function (token) { + if (token.type !== ']') + return this._readBlankNodePunctuation(token); + + // Store blank node triple + if (this._subject !== null) + this._triple(this._subject, this._predicate, this._object, this._graph); + + // Restore the parent context containing this blank node + var empty = this._predicate === null; + this._restoreContext(); + // If the blank node was the subject, continue reading the predicate + if (this._object === null) + // If the blank node was empty, it could be a named graph label + return empty ? this._readPredicateOrNamedGraph : this._readPredicateAfterBlank; + // If the blank node was the object, restore previous context and read punctuation + else + return this._getContextEndReader(); + }, + + // ### `_readPredicateAfterBlank` reads a predicate after an anonymous blank node + _readPredicateAfterBlank: function (token) { + // If a dot follows a blank node in top context, there is no predicate + if (token.type === '.' && !this._contextStack.length) { + this._subject = null; // cancel the current triple + return this._readPunctuation(token); + } + return this._readPredicate(token); + }, + + // ### `_readListItem` reads items from a list + _readListItem: function (token) { + var item = null, // The item of the list + list = null, // The list itself + prevList = this._subject, // The previous list that contains this list + stack = this._contextStack, // The stack of parent contexts + parent = stack[stack.length - 1], // The parent containing the current list + next = this._readListItem, // The next function to execute + itemComplete = true; // Whether the item has been read fully + + switch (token.type) { + case '[': + // Stack the current list triple and start a new triple with a blank node as subject + this._saveContext('blank', this._graph, list = '_:b' + blankNodeCount++, + RDF_FIRST, this._subject = item = '_:b' + blankNodeCount++); + next = this._readBlankNodeHead; + break; + case '(': + // Stack the current list triple and start a new list + this._saveContext('list', this._graph, list = '_:b' + blankNodeCount++, + RDF_FIRST, RDF_NIL); + this._subject = null; + break; + case ')': + // Closing the list; restore the parent context + this._restoreContext(); + // If this list is contained within a parent list, return the membership triple here. + // This will be ` rdf:first .`. + if (stack.length !== 0 && stack[stack.length - 1].type === 'list') + this._triple(this._subject, this._predicate, this._object, this._graph); + // Was this list the parent's subject? + if (this._predicate === null) { + // The next token is the predicate + next = this._readPredicate; + // No list tail if this was an empty list + if (this._subject === RDF_NIL) + return next; + } + // The list was in the parent context's object + else { + next = this._getContextEndReader(); + // No list tail if this was an empty list + if (this._object === RDF_NIL) + return next; + } + // Close the list by making the head nil + list = RDF_NIL; + break; + case 'literal': + item = token.value; + itemComplete = false; // Can still have a datatype or language + next = this._readListItemDataTypeOrLang; + break; + default: + if ((item = this._readEntity(token)) === undefined) + return; + } + + // Create a new blank node if no item head was assigned yet + if (list === null) + this._subject = list = '_:b' + blankNodeCount++; + + // Is this the first element of the list? + if (prevList === null) { + // This list is either the subject or the object of its parent + if (parent.predicate === null) + parent.subject = list; + else + parent.object = list; + } + else { + // Continue the previous list with the current list + this._triple(prevList, RDF_REST, list, this._graph); + } + // Add the item's value + if (item !== null) { + // In N3 mode, the item might be a path + if (this._n3Mode && (token.type === 'IRI' || token.type === 'prefixed')) { + // Create a new context to add the item's path + this._saveContext('item', this._graph, list, RDF_FIRST, item); + this._subject = item, this._predicate = null; + // _readPath will restore the context and output the item + return this._getPathReader(this._readListItem); + } + // Output the item if it is complete + if (itemComplete) + this._triple(list, RDF_FIRST, item, this._graph); + // Otherwise, save it for completion + else + this._object = item; + } + return next; + }, + + // ### `_readDataTypeOrLang` reads an _optional_ data type or language + _readDataTypeOrLang: function (token) { + return this._completeLiteral(token, false); + }, + + // ### `_readListItemDataTypeOrLang` reads an _optional_ data type or language in a list + _readListItemDataTypeOrLang: function (token) { + return this._completeLiteral(token, true); + }, + + // ### `_completeLiteral` completes the object with a data type or language + _completeLiteral: function (token, listItem) { + var suffix = false; + switch (token.type) { + // Add a "^^type" suffix for types (IRIs and blank nodes) + case 'type': + case 'typeIRI': + suffix = true; + this._object += '^^' + this._readEntity(token); + break; + // Add an "@lang" suffix for language tags + case 'langcode': + suffix = true; + this._object += '@' + token.value.toLowerCase(); + break; + } + // If this literal was part of a list, write the item + // (we could also check the context stack, but passing in a flag is faster) + if (listItem) + this._triple(this._subject, RDF_FIRST, this._object, this._graph); + // Continue with the rest of the input + if (suffix) + return this._getContextEndReader(); + else { + this._readCallback = this._getContextEndReader(); + return this._readCallback(token); + } + }, + + // ### `_readFormulaTail` reads the end of a formula + _readFormulaTail: function (token) { + if (token.type !== '}') + return this._readPunctuation(token); + + // Store the last triple of the formula + if (this._subject !== null) + this._triple(this._subject, this._predicate, this._object, this._graph); + + // Restore the parent context containing this formula + this._restoreContext(); + // If the formula was the subject, continue reading the predicate. + // If the formula was the object, read punctuation. + return this._object === null ? this._readPredicate : this._getContextEndReader(); + }, + + // ### `_readPunctuation` reads punctuation between triples or triple parts + _readPunctuation: function (token) { + var next, subject = this._subject, graph = this._graph, + inversePredicate = this._inversePredicate; + switch (token.type) { + // A closing brace ends a graph + case '}': + if (this._graph === null) + return this._error('Unexpected graph closing', token); + if (this._n3Mode) + return this._readFormulaTail(token); + this._graph = null; + // A dot just ends the statement, without sharing anything with the next + case '.': + this._subject = null; + next = this._contextStack.length ? this._readSubject : this._readInTopContext; + if (inversePredicate) this._inversePredicate = false; + break; + // Semicolon means the subject is shared; predicate and object are different + case ';': + next = this._readPredicate; + break; + // Comma means both the subject and predicate are shared; the object is different + case ',': + next = this._readObject; + break; + default: + // An entity means this is a quad (only allowed if not already inside a graph) + if (this._supportsQuads && this._graph === null && (graph = this._readEntity(token)) !== undefined) { + next = this._readQuadPunctuation; + break; + } + return this._error('Expected punctuation to follow "' + this._object + '"', token); + } + // A triple has been completed now, so return it + if (subject !== null) { + var predicate = this._predicate, object = this._object; + if (!inversePredicate) + this._triple(subject, predicate, object, graph); + else + this._triple(object, predicate, subject, graph); + } + return next; + }, + + // ### `_readBlankNodePunctuation` reads punctuation in a blank node + _readBlankNodePunctuation: function (token) { + var next; + switch (token.type) { + // Semicolon means the subject is shared; predicate and object are different + case ';': + next = this._readPredicate; + break; + // Comma means both the subject and predicate are shared; the object is different + case ',': + next = this._readObject; + break; + default: + return this._error('Expected punctuation to follow "' + this._object + '"', token); + } + // A triple has been completed now, so return it + this._triple(this._subject, this._predicate, this._object, this._graph); + return next; + }, + + // ### `_readQuadPunctuation` reads punctuation after a quad + _readQuadPunctuation: function (token) { + if (token.type !== '.') + return this._error('Expected dot to follow quad', token); + return this._readInTopContext; + }, + + // ### `_readPrefix` reads the prefix of a prefix declaration + _readPrefix: function (token) { + if (token.type !== 'prefix') + return this._error('Expected prefix to follow @prefix', token); + this._prefix = token.value; + return this._readPrefixIRI; + }, + + // ### `_readPrefixIRI` reads the IRI of a prefix declaration + _readPrefixIRI: function (token) { + if (token.type !== 'IRI') + return this._error('Expected IRI to follow prefix "' + this._prefix + ':"', token); + var prefixIRI = this._readEntity(token); + this._prefixes[this._prefix] = prefixIRI; + this._prefixCallback(this._prefix, prefixIRI); + return this._readDeclarationPunctuation; + }, + + // ### `_readBaseIRI` reads the IRI of a base declaration + _readBaseIRI: function (token) { + if (token.type !== 'IRI') + return this._error('Expected IRI to follow base declaration', token); + this._setBase(this._base === null || absoluteIRI.test(token.value) ? + token.value : this._resolveIRI(token)); + return this._readDeclarationPunctuation; + }, + + // ### `_readNamedGraphLabel` reads the label of a named graph + _readNamedGraphLabel: function (token) { + switch (token.type) { + case 'IRI': + case 'blank': + case 'prefixed': + return this._readSubject(token), this._readGraph; + case '[': + return this._readNamedGraphBlankLabel; + default: + return this._error('Invalid graph label', token); + } + }, + + // ### `_readNamedGraphLabel` reads a blank node label of a named graph + _readNamedGraphBlankLabel: function (token) { + if (token.type !== ']') + return this._error('Invalid graph label', token); + this._subject = '_:b' + blankNodeCount++; + return this._readGraph; + }, + + // ### `_readDeclarationPunctuation` reads the punctuation of a declaration + _readDeclarationPunctuation: function (token) { + // SPARQL-style declarations don't have punctuation + if (this._sparqlStyle) { + this._sparqlStyle = false; + return this._readInTopContext(token); + } + + if (token.type !== '.') + return this._error('Expected declaration to end with a dot', token); + return this._readInTopContext; + }, + + // Reads a list of quantified symbols from a @forSome or @forAll statement + _readQuantifierList: function (token) { + var entity; + switch (token.type) { + case 'IRI': + case 'prefixed': + if ((entity = this._readEntity(token, true)) !== undefined) + break; + default: + return this._error('Unexpected ' + token.type, token); + } + // Without explicit quantifiers, map entities to a quantified entity + if (!this._explicitQuantifiers) + this._quantified[entity] = this._quantifiedPrefix + blankNodeCount++; + // With explicit quantifiers, output the reified quantifier + else { + // If this is the first item, start a new quantifier list + if (this._subject === null) + this._triple(this._graph || '', this._predicate, + this._subject = '_:b' + blankNodeCount++, QUANTIFIERS_GRAPH); + // Otherwise, continue the previous list + else + this._triple(this._subject, RDF_REST, + this._subject = '_:b' + blankNodeCount++, QUANTIFIERS_GRAPH); + // Output the list item + this._triple(this._subject, RDF_FIRST, entity, QUANTIFIERS_GRAPH); + } + return this._readQuantifierPunctuation; + }, + + // Reads punctuation from a @forSome or @forAll statement + _readQuantifierPunctuation: function (token) { + // Read more quantifiers + if (token.type === ',') + return this._readQuantifierList; + // End of the quantifier list + else { + // With explicit quantifiers, close the quantifier list + if (this._explicitQuantifiers) { + this._triple(this._subject, RDF_REST, RDF_NIL, QUANTIFIERS_GRAPH); + this._subject = null; + } + // Read a dot + this._readCallback = this._getContextEndReader(); + return this._readCallback(token); + } + }, + + // ### `_getPathReader` reads a potential path and then resumes with the given function + _getPathReader: function (afterPath) { + this._afterPath = afterPath; + return this._readPath; + }, + + // ### `_readPath` reads a potential path + _readPath: function (token) { + switch (token.type) { + // Forward path + case '!': return this._readForwardPath; + // Backward path + case '^': return this._readBackwardPath; + // Not a path; resume reading where we left off + default: + var stack = this._contextStack, parent = stack.length && stack[stack.length - 1]; + // If we were reading a list item, we still need to output it + if (parent && parent.type === 'item') { + // The list item is the remaining subejct after reading the path + var item = this._subject; + // Switch back to the context of the list + this._restoreContext(); + // Output the list item + this._triple(this._subject, RDF_FIRST, item, this._graph); + } + return this._afterPath(token); + } + }, + + // ### `_readForwardPath` reads a '!' path + _readForwardPath: function (token) { + var subject, predicate, object = '_:b' + blankNodeCount++; + // The next token is the predicate + if ((predicate = this._readEntity(token)) === undefined) + return; + // If we were reading a subject, replace the subject by the path's object + if (this._predicate === null) + subject = this._subject, this._subject = object; + // If we were reading an object, replace the subject by the path's object + else + subject = this._object, this._object = object; + // Emit the path's current triple and read its next section + this._triple(subject, predicate, object, this._graph); + return this._readPath; + }, + + // ### `_readBackwardPath` reads a '^' path + _readBackwardPath: function (token) { + var subject = '_:b' + blankNodeCount++, predicate, object; + // The next token is the predicate + if ((predicate = this._readEntity(token)) === undefined) + return; + // If we were reading a subject, replace the subject by the path's subject + if (this._predicate === null) + object = this._subject, this._subject = subject; + // If we were reading an object, replace the subject by the path's subject + else + object = this._object, this._object = subject; + // Emit the path's current triple and read its next section + this._triple(subject, predicate, object, this._graph); + return this._readPath; + }, + + // ### `_getContextEndReader` gets the next reader function at the end of a context + _getContextEndReader: function () { + var contextStack = this._contextStack; + if (!contextStack.length) + return this._readPunctuation; + + switch (contextStack[contextStack.length - 1].type) { + case 'blank': + return this._readBlankNodeTail; + case 'list': + return this._readListItem; + case 'formula': + return this._readFormulaTail; + } + }, + + // ### `_triple` emits a triple through the callback + _triple: function (subject, predicate, object, graph) { + this._callback(null, + { subject: subject, predicate: predicate, object: object, graph: graph || '' }); + }, + + // ### `_error` emits an error message through the callback + _error: function (message, token) { + var err = new Error(message + ' on line ' + token.line + '.'); + err.context = { + token: token, + line: token.line, + previousToken: this._lexer.previousToken, + }; + this._callback(err); + }, + + // ### `_resolveIRI` resolves a relative IRI token against the base path, + // assuming that a base path has been set and that the IRI is indeed relative + _resolveIRI: function (token) { + var iri = token.value; + switch (iri[0]) { + // An empty relative IRI indicates the base IRI + case undefined: return this._base; + // Resolve relative fragment IRIs against the base IRI + case '#': return this._base + iri; + // Resolve relative query string IRIs by replacing the query string + case '?': return this._base.replace(/(?:\?.*)?$/, iri); + // Resolve root-relative IRIs at the root of the base IRI + case '/': + // Resolve scheme-relative IRIs to the scheme + return (iri[1] === '/' ? this._baseScheme : this._baseRoot) + this._removeDotSegments(iri); + // Resolve all other IRIs at the base IRI's path + default: + return this._removeDotSegments(this._basePath + iri); + } + }, + + // ### `_removeDotSegments` resolves './' and '../' path segments in an IRI as per RFC3986 + _removeDotSegments: function (iri) { + // Don't modify the IRI if it does not contain any dot segments + if (!dotSegments.test(iri)) + return iri; + + // Start with an imaginary slash before the IRI in order to resolve trailing './' and '../' + var result = '', length = iri.length, i = -1, pathStart = -1, segmentStart = 0, next = '/'; + + while (i < length) { + switch (next) { + // The path starts with the first slash after the authority + case ':': + if (pathStart < 0) { + // Skip two slashes before the authority + if (iri[++i] === '/' && iri[++i] === '/') + // Skip to slash after the authority + while ((pathStart = i + 1) < length && iri[pathStart] !== '/') + i = pathStart; + } + break; + // Don't modify a query string or fragment + case '?': + case '#': + i = length; + break; + // Handle '/.' or '/..' path segments + case '/': + if (iri[i + 1] === '.') { + next = iri[++i + 1]; + switch (next) { + // Remove a '/.' segment + case '/': + result += iri.substring(segmentStart, i - 1); + segmentStart = i + 1; + break; + // Remove a trailing '/.' segment + case undefined: + case '?': + case '#': + return result + iri.substring(segmentStart, i) + iri.substr(i + 1); + // Remove a '/..' segment + case '.': + next = iri[++i + 1]; + if (next === undefined || next === '/' || next === '?' || next === '#') { + result += iri.substring(segmentStart, i - 2); + // Try to remove the parent path from result + if ((segmentStart = result.lastIndexOf('/')) >= pathStart) + result = result.substr(0, segmentStart); + // Remove a trailing '/..' segment + if (next !== '/') + return result + '/' + iri.substr(i + 1); + segmentStart = i + 1; + } + } + } + } + next = iri[++i]; + } + return result + iri.substring(segmentStart); + }, + + // ## Public methods + + // ### `parse` parses the N3 input and emits each parsed triple through the callback + parse: function (input, tripleCallback, prefixCallback) { + var self = this; + // The read callback is the next function to be executed when a token arrives. + // We start reading in the top context. + this._readCallback = this._readInTopContext; + this._sparqlStyle = false; + this._prefixes = Object.create(null); + this._prefixes._ = this._blankNodePrefix || '_:b' + blankNodePrefix++ + '_'; + this._prefixCallback = prefixCallback || noop; + this._inversePredicate = false; + this._quantified = Object.create(null); + + // Parse synchronously if no triple callback is given + if (!tripleCallback) { + var triples = [], error; + this._callback = function (e, t) { e ? (error = e) : t && triples.push(t); }; + this._lexer.tokenize(input).every(function (token) { + return self._readCallback = self._readCallback(token); + }); + if (error) throw error; + return triples; + } + + // Parse asynchronously otherwise, executing the read callback when a token arrives + this._callback = tripleCallback; + this._lexer.tokenize(input, function (error, token) { + if (error !== null) + self._callback(error), self._callback = noop; + else if (self._readCallback) + self._readCallback = self._readCallback(token); + }); + }, +}; + +// The empty function +function noop() {} + +// ## Exports +module.exports = N3Parser; + +},{"./N3Lexer":231}],233:[function(_dereq_,module,exports){ +// **N3Store** objects store N3 triples by graph in memory. + +var expandPrefixedName = _dereq_('./N3Util').expandPrefixedName; + +// ## Constructor +function N3Store(triples, options) { + if (!(this instanceof N3Store)) + return new N3Store(triples, options); + + // The number of triples is initially zero + this._size = 0; + // `_graphs` contains subject, predicate, and object indexes per graph + this._graphs = Object.create(null); + // `_ids` maps entities such as `http://xmlns.com/foaf/0.1/name` to numbers, + // saving memory by using only numbers as keys in `_graphs` + this._id = 0; + this._ids = Object.create(null); + this._ids['><'] = 0; // dummy entry, so the first actual key is non-zero + this._entities = Object.create(null); // inverse of `_ids` + // `_blankNodeIndex` is the index of the last automatically named blank node + this._blankNodeIndex = 0; + + // Shift parameters if `triples` is not given + if (!options && triples && !triples[0]) + options = triples, triples = null; + options = options || {}; + + // Add triples and prefixes if passed + this._prefixes = Object.create(null); + if (options.prefixes) + this.addPrefixes(options.prefixes); + if (triples) + this.addTriples(triples); +} + +N3Store.prototype = { + // ## Public properties + + // ### `size` returns the number of triples in the store + get size() { + // Return the triple count if if was cached + var size = this._size; + if (size !== null) + return size; + + // Calculate the number of triples by counting to the deepest level + size = 0; + var graphs = this._graphs, subjects, subject; + for (var graphKey in graphs) + for (var subjectKey in (subjects = graphs[graphKey].subjects)) + for (var predicateKey in (subject = subjects[subjectKey])) + size += Object.keys(subject[predicateKey]).length; + return this._size = size; + }, + + // ## Private methods + + // ### `_addToIndex` adds a triple to a three-layered index. + // Returns if the index has changed, if the entry did not already exist. + _addToIndex: function (index0, key0, key1, key2) { + // Create layers as necessary + var index1 = index0[key0] || (index0[key0] = {}); + var index2 = index1[key1] || (index1[key1] = {}); + // Setting the key to _any_ value signals the presence of the triple + var existed = key2 in index2; + if (!existed) + index2[key2] = null; + return !existed; + }, + + // ### `_removeFromIndex` removes a triple from a three-layered index + _removeFromIndex: function (index0, key0, key1, key2) { + // Remove the triple from the index + var index1 = index0[key0], index2 = index1[key1], key; + delete index2[key2]; + + // Remove intermediary index layers if they are empty + for (key in index2) return; + delete index1[key1]; + for (key in index1) return; + delete index0[key0]; + }, + + // ### `_findInIndex` finds a set of triples in a three-layered index. + // The index base is `index0` and the keys at each level are `key0`, `key1`, and `key2`. + // Any of these keys can be undefined, which is interpreted as a wildcard. + // `name0`, `name1`, and `name2` are the names of the keys at each level, + // used when reconstructing the resulting triple + // (for instance: _subject_, _predicate_, and _object_). + // Finally, `graph` will be the graph of the created triples. + // If `callback` is given, each result is passed through it + // and iteration halts when it returns truthy for any triple. + // If instead `array` is given, each result is added to the array. + _findInIndex: function (index0, key0, key1, key2, name0, name1, name2, graph, callback, array) { + var tmp, index1, index2, varCount = !key0 + !key1 + !key2, + // depending on the number of variables, keys or reverse index are faster + entityKeys = varCount > 1 ? Object.keys(this._ids) : this._entities; + + // If a key is specified, use only that part of index 0. + if (key0) (tmp = index0, index0 = {})[key0] = tmp[key0]; + for (var value0 in index0) { + var entity0 = entityKeys[value0]; + + if (index1 = index0[value0]) { + // If a key is specified, use only that part of index 1. + if (key1) (tmp = index1, index1 = {})[key1] = tmp[key1]; + for (var value1 in index1) { + var entity1 = entityKeys[value1]; + + if (index2 = index1[value1]) { + // If a key is specified, use only that part of index 2, if it exists. + var values = key2 ? (key2 in index2 ? [key2] : []) : Object.keys(index2); + // Create triples for all items found in index 2. + for (var l = values.length - 1; l >= 0; l--) { + var result = { subject: '', predicate: '', object: '', graph: graph }; + result[name0] = entity0; + result[name1] = entity1; + result[name2] = entityKeys[values[l]]; + if (array) + array.push(result); + else if (callback(result)) + return true; + } + } + } + } + } + return array; + }, + + // ### `_loop` executes the callback on all keys of index 0 + _loop: function (index0, callback) { + for (var key0 in index0) + callback(key0); + }, + + // ### `_loopByKey0` executes the callback on all keys of a certain entry in index 0 + _loopByKey0: function (index0, key0, callback) { + var index1, key1; + if (index1 = index0[key0]) { + for (key1 in index1) + callback(key1); + } + }, + + // ### `_loopByKey1` executes the callback on given keys of all entries in index 0 + _loopByKey1: function (index0, key1, callback) { + var key0, index1; + for (key0 in index0) { + index1 = index0[key0]; + if (index1[key1]) + callback(key0); + } + }, + + // ### `_loopBy2Keys` executes the callback on given keys of certain entries in index 2 + _loopBy2Keys: function (index0, key0, key1, callback) { + var index1, index2, key2; + if ((index1 = index0[key0]) && (index2 = index1[key1])) { + for (key2 in index2) + callback(key2); + } + }, + + // ### `_countInIndex` counts matching triples in a three-layered index. + // The index base is `index0` and the keys at each level are `key0`, `key1`, and `key2`. + // Any of these keys can be undefined, which is interpreted as a wildcard. + _countInIndex: function (index0, key0, key1, key2) { + var count = 0, tmp, index1, index2; + + // If a key is specified, count only that part of index 0 + if (key0) (tmp = index0, index0 = {})[key0] = tmp[key0]; + for (var value0 in index0) { + if (index1 = index0[value0]) { + // If a key is specified, count only that part of index 1 + if (key1) (tmp = index1, index1 = {})[key1] = tmp[key1]; + for (var value1 in index1) { + if (index2 = index1[value1]) { + // If a key is specified, count the triple if it exists + if (key2) (key2 in index2) && count++; + // Otherwise, count all triples + else count += Object.keys(index2).length; + } + } + } + } + return count; + }, + + // ### `_getGraphs` returns an array with the given graph, + // or all graphs if the argument is null or undefined. + _getGraphs: function (graph) { + if (!isString(graph)) + return this._graphs; + var graphs = {}; + graphs[graph] = this._graphs[graph]; + return graphs; + }, + + // ### `_uniqueEntities` returns a function that accepts an entity ID + // and passes the corresponding entity to callback if it hasn't occurred before. + _uniqueEntities: function (callback) { + var uniqueIds = Object.create(null), entities = this._entities; + return function (id) { + if (!(id in uniqueIds)) { + uniqueIds[id] = true; + callback(entities[id]); + } + }; + }, + + // ## Public methods + + // ### `addTriple` adds a new N3 triple to the store. + // Returns if the triple index has changed, if the triple did not already exist. + addTriple: function (subject, predicate, object, graph) { + // Shift arguments if a triple object is given instead of components + if (!predicate) + graph = subject.graph, object = subject.object, + predicate = subject.predicate, subject = subject.subject; + + // Find the graph that will contain the triple + graph = graph || ''; + var graphItem = this._graphs[graph]; + // Create the graph if it doesn't exist yet + if (!graphItem) { + graphItem = this._graphs[graph] = { subjects: {}, predicates: {}, objects: {} }; + // Freezing a graph helps subsequent `add` performance, + // and properties will never be modified anyway + Object.freeze(graphItem); + } + + // Since entities can often be long IRIs, we avoid storing them in every index. + // Instead, we have a separate index that maps entities to numbers, + // which are then used as keys in the other indexes. + var ids = this._ids; + var entities = this._entities; + subject = ids[subject] || (ids[entities[++this._id] = subject] = this._id); + predicate = ids[predicate] || (ids[entities[++this._id] = predicate] = this._id); + object = ids[object] || (ids[entities[++this._id] = object] = this._id); + + var changed = this._addToIndex(graphItem.subjects, subject, predicate, object); + this._addToIndex(graphItem.predicates, predicate, object, subject); + this._addToIndex(graphItem.objects, object, subject, predicate); + + // The cached triple count is now invalid + this._size = null; + return changed; + }, + + // ### `addTriples` adds multiple N3 triples to the store + addTriples: function (triples) { + for (var i = triples.length - 1; i >= 0; i--) + this.addTriple(triples[i]); + }, + + // ### `addPrefix` adds support for querying with the given prefix + addPrefix: function (prefix, iri) { + this._prefixes[prefix] = iri; + }, + + // ### `addPrefixes` adds support for querying with the given prefixes + addPrefixes: function (prefixes) { + for (var prefix in prefixes) + this.addPrefix(prefix, prefixes[prefix]); + }, + + // ### `removeTriple` removes an N3 triple from the store if it exists + removeTriple: function (subject, predicate, object, graph) { + // Shift arguments if a triple object is given instead of components + if (!predicate) + graph = subject.graph, object = subject.object, + predicate = subject.predicate, subject = subject.subject; + graph = graph || ''; + + // Find internal identifiers for all components + // and verify the triple exists. + var graphItem, ids = this._ids, graphs = this._graphs, subjects, predicates; + if (!(subject = ids[subject]) || !(predicate = ids[predicate]) || + !(object = ids[object]) || !(graphItem = graphs[graph]) || + !(subjects = graphItem.subjects[subject]) || + !(predicates = subjects[predicate]) || + !(object in predicates)) + return false; + + // Remove it from all indexes + this._removeFromIndex(graphItem.subjects, subject, predicate, object); + this._removeFromIndex(graphItem.predicates, predicate, object, subject); + this._removeFromIndex(graphItem.objects, object, subject, predicate); + if (this._size !== null) this._size--; + + // Remove the graph if it is empty + for (subject in graphItem.subjects) return true; + delete graphs[graph]; + return true; + }, + + // ### `removeTriples` removes multiple N3 triples from the store + removeTriples: function (triples) { + for (var i = triples.length - 1; i >= 0; i--) + this.removeTriple(triples[i]); + }, + + // ### `getTriples` returns an array of triples matching a pattern, expanding prefixes as necessary. + // Setting any field to `undefined` or `null` indicates a wildcard. + getTriples: function (subject, predicate, object, graph) { + var prefixes = this._prefixes; + return this.getTriplesByIRI( + expandPrefixedName(subject, prefixes), + expandPrefixedName(predicate, prefixes), + expandPrefixedName(object, prefixes), + expandPrefixedName(graph, prefixes) + ); + }, + + // ### `getTriplesByIRI` returns an array of triples matching a pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + getTriplesByIRI: function (subject, predicate, object, graph) { + var quads = [], graphs = this._getGraphs(graph), content, + ids = this._ids, subjectId, predicateId, objectId; + + // Translate IRIs to internal index keys. + if (isString(subject) && !(subjectId = ids[subject]) || + isString(predicate) && !(predicateId = ids[predicate]) || + isString(object) && !(objectId = ids[object])) + return quads; + + for (var graphId in graphs) { + // Only if the specified graph contains triples, there can be results + if (content = graphs[graphId]) { + // Choose the optimal index, based on what fields are present + if (subjectId) { + if (objectId) + // If subject and object are given, the object index will be the fastest + this._findInIndex(content.objects, objectId, subjectId, predicateId, + 'object', 'subject', 'predicate', graphId, null, quads); + else + // If only subject and possibly predicate are given, the subject index will be the fastest + this._findInIndex(content.subjects, subjectId, predicateId, null, + 'subject', 'predicate', 'object', graphId, null, quads); + } + else if (predicateId) + // If only predicate and possibly object are given, the predicate index will be the fastest + this._findInIndex(content.predicates, predicateId, objectId, null, + 'predicate', 'object', 'subject', graphId, null, quads); + else if (objectId) + // If only object is given, the object index will be the fastest + this._findInIndex(content.objects, objectId, null, null, + 'object', 'subject', 'predicate', graphId, null, quads); + else + // If nothing is given, iterate subjects and predicates first + this._findInIndex(content.subjects, null, null, null, + 'subject', 'predicate', 'object', graphId, null, quads); + } + } + return quads; + }, + + // ### `countTriples` returns the number of triples matching a pattern, expanding prefixes as necessary. + // Setting any field to `undefined` or `null` indicates a wildcard. + countTriples: function (subject, predicate, object, graph) { + var prefixes = this._prefixes; + return this.countTriplesByIRI( + expandPrefixedName(subject, prefixes), + expandPrefixedName(predicate, prefixes), + expandPrefixedName(object, prefixes), + expandPrefixedName(graph, prefixes) + ); + }, + + // ### `countTriplesByIRI` returns the number of triples matching a pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + countTriplesByIRI: function (subject, predicate, object, graph) { + var count = 0, graphs = this._getGraphs(graph), content, + ids = this._ids, subjectId, predicateId, objectId; + + // Translate IRIs to internal index keys. + if (isString(subject) && !(subjectId = ids[subject]) || + isString(predicate) && !(predicateId = ids[predicate]) || + isString(object) && !(objectId = ids[object])) + return 0; + + for (var graphId in graphs) { + // Only if the specified graph contains triples, there can be results + if (content = graphs[graphId]) { + // Choose the optimal index, based on what fields are present + if (subject) { + if (object) + // If subject and object are given, the object index will be the fastest + count += this._countInIndex(content.objects, objectId, subjectId, predicateId); + else + // If only subject and possibly predicate are given, the subject index will be the fastest + count += this._countInIndex(content.subjects, subjectId, predicateId, objectId); + } + else if (predicate) { + // If only predicate and possibly object are given, the predicate index will be the fastest + count += this._countInIndex(content.predicates, predicateId, objectId, subjectId); + } + else { + // If only object is possibly given, the object index will be the fastest + count += this._countInIndex(content.objects, objectId, subjectId, predicateId); } } - return null; } - }, { - key: 'init', - value: function init() {} - }, { - key: 'newBlankNode', - value: function newBlankNode() { - this.blankCounter++; - return '_:' + this.blankCounter; + return count; + }, + + // ### `forEach` executes the callback on all triples. + // Setting any field to `undefined` or `null` indicates a wildcard. + forEach: function (callback, subject, predicate, object, graph) { + var prefixes = this._prefixes; + this.forEachByIRI( + callback, + expandPrefixedName(subject, prefixes), + expandPrefixedName(predicate, prefixes), + expandPrefixedName(object, prefixes), + expandPrefixedName(graph, prefixes) + ); + }, + + // ### `forEachByIRI` executes the callback on all triples. + // Setting any field to `undefined` or `null` indicates a wildcard. + forEachByIRI: function (callback, subject, predicate, object, graph) { + this.someByIRI(function (quad) { + callback(quad); + return false; + }, subject, predicate, object, graph); + }, + + // ### `every` executes the callback on all triples, + // and returns `true` if it returns truthy for all them. + // Setting any field to `undefined` or `null` indicates a wildcard. + every: function (callback, subject, predicate, object, graph) { + var prefixes = this._prefixes; + return this.everyByIRI( + callback, + expandPrefixedName(subject, prefixes), + expandPrefixedName(predicate, prefixes), + expandPrefixedName(object, prefixes), + expandPrefixedName(graph, prefixes) + ); + }, + + // ### `everyByIRI` executes the callback on all triples, + // and returns `true` if it returns truthy for all them. + // Setting any field to `undefined` or `null` indicates a wildcard. + everyByIRI: function (callback, subject, predicate, object, graph) { + var some = false; + var every = !this.someByIRI(function (quad) { + some = true; + return !callback(quad); + }, subject, predicate, object, graph); + return some && every; + }, + + // ### `some` executes the callback on all triples, + // and returns `true` if it returns truthy for any of them. + // Setting any field to `undefined` or `null` indicates a wildcard. + some: function (callback, subject, predicate, object, graph) { + var prefixes = this._prefixes; + return this.someByIRI( + callback, + expandPrefixedName(subject, prefixes), + expandPrefixedName(predicate, prefixes), + expandPrefixedName(object, prefixes), + expandPrefixedName(graph, prefixes) + ); + }, + + // ### `someByIRI` executes the callback on all triples, + // and returns `true` if it returns truthy for any of them. + // Setting any field to `undefined` or `null` indicates a wildcard. + someByIRI: function (callback, subject, predicate, object, graph) { + var graphs = this._getGraphs(graph), content, + ids = this._ids, subjectId, predicateId, objectId; + + // Translate IRIs to internal index keys. + if (isString(subject) && !(subjectId = ids[subject]) || + isString(predicate) && !(predicateId = ids[predicate]) || + isString(object) && !(objectId = ids[object])) + return false; + + for (var graphId in graphs) { + // Only if the specified graph contains triples, there can be result + if (content = graphs[graphId]) { + // Choose the optimal index, based on what fields are present + if (subjectId) { + if (objectId) { + // If subject and object are given, the object index will be the fastest + if (this._findInIndex(content.objects, objectId, subjectId, predicateId, + 'object', 'subject', 'predicate', graphId, callback, null)) + return true; + } + else + // If only subject and possibly predicate are given, the subject index will be the fastest + if (this._findInIndex(content.subjects, subjectId, predicateId, null, + 'subject', 'predicate', 'object', graphId, callback, null)) + return true; + } + else if (predicateId) { + // If only predicate and possibly object are given, the predicate index will be the fastest + if (this._findInIndex(content.predicates, predicateId, objectId, null, + 'predicate', 'object', 'subject', graphId, callback, null)) { + return true; + } + } + else if (objectId) { + // If only object is given, the object index will be the fastest + if (this._findInIndex(content.objects, objectId, null, null, + 'object', 'subject', 'predicate', graphId, callback, null)) { + return true; + } + } + else + // If nothing is given, iterate subjects and predicates first + if (this._findInIndex(content.subjects, null, null, null, + 'subject', 'predicate', 'object', graphId, callback, null)) { + return true; + } + } + } + return false; + }, + + // ### `getSubjects` returns all subjects that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + getSubjects: function (predicate, object, graph) { + var prefixes = this._prefixes; + return this.getSubjectsByIRI( + expandPrefixedName(predicate, prefixes), + expandPrefixedName(object, prefixes), + expandPrefixedName(graph, prefixes) + ); + }, + + // ### `getSubjectsByIRI` returns all subjects that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + getSubjectsByIRI: function (predicate, object, graph) { + var results = []; + this.forSubjectsByIRI(function (s) { results.push(s); }, predicate, object, graph); + return results; + }, + + // ### `forSubjects` executes the callback on all subjects that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + forSubjects: function (callback, predicate, object, graph) { + var prefixes = this._prefixes; + this.forSubjectsByIRI( + callback, + expandPrefixedName(predicate, prefixes), + expandPrefixedName(object, prefixes), + expandPrefixedName(graph, prefixes) + ); + }, + + // ### `forSubjectsByIRI` executes the callback on all subjects that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + forSubjectsByIRI: function (callback, predicate, object, graph) { + var ids = this._ids, graphs = this._getGraphs(graph), content, predicateId, objectId; + callback = this._uniqueEntities(callback); + + // Translate IRIs to internal index keys. + if (isString(predicate) && !(predicateId = ids[predicate]) || + isString(object) && !(objectId = ids[object])) + return; + + for (graph in graphs) { + // Only if the specified graph contains triples, there can be results + if (content = graphs[graph]) { + // Choose optimal index based on which fields are wildcards + if (predicateId) { + if (objectId) + // If predicate and object are given, the POS index is best. + this._loopBy2Keys(content.predicates, predicateId, objectId, callback); + else + // If only predicate is given, the SPO index is best. + this._loopByKey1(content.subjects, predicateId, callback); + } + else if (objectId) + // If only object is given, the OSP index is best. + this._loopByKey0(content.objects, objectId, callback); + else + // If no params given, iterate all the subjects + this._loop(content.subjects, callback); + } + } + }, + + // ### `getPredicates` returns all predicates that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + getPredicates: function (subject, object, graph) { + var prefixes = this._prefixes; + return this.getPredicatesByIRI( + expandPrefixedName(subject, prefixes), + expandPrefixedName(object, prefixes), + expandPrefixedName(graph, prefixes) + ); + }, + + // ### `getPredicatesByIRI` returns all predicates that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + getPredicatesByIRI: function (subject, object, graph) { + var results = []; + this.forPredicatesByIRI(function (p) { results.push(p); }, subject, object, graph); + return results; + }, + + // ### `forPredicates` executes the callback on all predicates that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + forPredicates: function (callback, subject, object, graph) { + var prefixes = this._prefixes; + this.forPredicatesByIRI( + callback, + expandPrefixedName(subject, prefixes), + expandPrefixedName(object, prefixes), + expandPrefixedName(graph, prefixes) + ); + }, + + // ### `forPredicatesByIRI` executes the callback on all predicates that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + forPredicatesByIRI: function (callback, subject, object, graph) { + var ids = this._ids, graphs = this._getGraphs(graph), content, subjectId, objectId; + callback = this._uniqueEntities(callback); + + // Translate IRIs to internal index keys. + if (isString(subject) && !(subjectId = ids[subject]) || + isString(object) && !(objectId = ids[object])) + return; + + for (graph in graphs) { + // Only if the specified graph contains triples, there can be results + if (content = graphs[graph]) { + // Choose optimal index based on which fields are wildcards + if (subjectId) { + if (objectId) + // If subject and object are given, the OSP index is best. + this._loopBy2Keys(content.objects, objectId, subjectId, callback); + else + // If only subject is given, the SPO index is best. + this._loopByKey0(content.subjects, subjectId, callback); + } + else if (objectId) + // If only object is given, the POS index is best. + this._loopByKey1(content.predicates, objectId, callback); + else + // If no params given, iterate all the predicates. + this._loop(content.predicates, callback); + } + } + }, + + // ### `getObjects` returns all objects that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + getObjects: function (subject, predicate, graph) { + var prefixes = this._prefixes; + return this.getObjectsByIRI( + expandPrefixedName(subject, prefixes), + expandPrefixedName(predicate, prefixes), + expandPrefixedName(graph, prefixes) + ); + }, + + // ### `getObjectsByIRI` returns all objects that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + getObjectsByIRI: function (subject, predicate, graph) { + var results = []; + this.forObjectsByIRI(function (o) { results.push(o); }, subject, predicate, graph); + return results; + }, + + // ### `forObjects` executes the callback on all objects that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + forObjects: function (callback, subject, predicate, graph) { + var prefixes = this._prefixes; + this.forObjectsByIRI( + callback, + expandPrefixedName(subject, prefixes), + expandPrefixedName(predicate, prefixes), + expandPrefixedName(graph, prefixes) + ); + }, + + // ### `forObjectsByIRI` executes the callback on all objects that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + forObjectsByIRI: function (callback, subject, predicate, graph) { + var ids = this._ids, graphs = this._getGraphs(graph), content, subjectId, predicateId; + callback = this._uniqueEntities(callback); + + // Translate IRIs to internal index keys. + if (isString(subject) && !(subjectId = ids[subject]) || + isString(predicate) && !(predicateId = ids[predicate])) + return; + + for (graph in graphs) { + // Only if the specified graph contains triples, there can be results + if (content = graphs[graph]) { + // Choose optimal index based on which fields are wildcards + if (subjectId) { + if (predicateId) + // If subject and predicate are given, the SPO index is best. + this._loopBy2Keys(content.subjects, subjectId, predicateId, callback); + else + // If only subject is given, the OSP index is best. + this._loopByKey1(content.objects, subjectId, callback); + } + else if (predicateId) + // If only predicate is given, the POS index is best. + this._loopByKey0(content.predicates, predicateId, callback); + else + // If no params given, iterate all the objects. + this._loop(content.objects, callback); + } + } + }, + + // ### `getGraphs` returns all graphs that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + getGraphs: function (subject, predicate, object) { + var prefixes = this._prefixes; + return this.getGraphsByIRI( + expandPrefixedName(subject, prefixes), + expandPrefixedName(predicate, prefixes), + expandPrefixedName(object, prefixes) + ); + }, + + // ### `getGraphsByIRI` returns all graphs that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + getGraphsByIRI: function (subject, predicate, object) { + var results = []; + this.forGraphsByIRI(function (g) { results.push(g); }, subject, predicate, object); + return results; + }, + + // ### `forGraphs` executes the callback on all graphs that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + forGraphs: function (callback, subject, predicate, object) { + var prefixes = this._prefixes; + this.forGraphsByIRI( + callback, + expandPrefixedName(subject, prefixes), + expandPrefixedName(predicate, prefixes), + expandPrefixedName(object, prefixes) + ); + }, + + // ### `forGraphsByIRI` executes the callback on all graphs that match the pattern. + // Setting any field to `undefined` or `null` indicates a wildcard. + forGraphsByIRI: function (callback, subject, predicate, object) { + for (var graph in this._graphs) { + this.someByIRI(function (quad) { + callback(quad.graph); + return true; // Halt iteration of some() + }, subject, predicate, object, graph); + } + }, + + // ### `createBlankNode` creates a new blank node, returning its name + createBlankNode: function (suggestedName) { + var name, index; + // Generate a name based on the suggested name + if (suggestedName) { + name = suggestedName = '_:' + suggestedName, index = 1; + while (this._ids[name]) + name = suggestedName + index++; } - }, { - key: 'newSubjectOrigin', - value: function newSubjectOrigin(origin, subject) {} - }, { - key: 'parseCURIE', - value: function parseCURIE(value, prefixes, base) { - var colon = value.indexOf(':'); - var uri; - if (colon >= 0) { - var prefix = value.substring(0, colon); - if (prefix === '') { - // default prefix - uri = prefixes['']; - return uri ? uri + value.substring(colon + 1) : null; - } else if (prefix === '_') { - // blank node - return '_:' + value.substring(colon + 1); - } else if (RDFaProcessor.NCNAME.test(prefix)) { - uri = prefixes[prefix]; - if (uri) { - return uri + value.substring(colon + 1); - } + // Generate a generic blank node name + else { + do { name = '_:b' + this._blankNodeIndex++; } + while (this._ids[name]); + } + // Add the blank node to the entities, avoiding the generation of duplicates + this._ids[name] = ++this._id; + this._entities[this._id] = name; + return name; + }, +}; + +// Determines whether the argument is a string +function isString(s) { + return typeof s === 'string' || s instanceof String; +} + +// ## Exports +module.exports = N3Store; + +},{"./N3Util":236}],234:[function(_dereq_,module,exports){ +// **N3StreamParser** parses an N3 stream into a triple stream. +var Transform = _dereq_('stream').Transform, + util = _dereq_('util'), + N3Parser = _dereq_('./N3Parser.js'); + +// ## Constructor +function N3StreamParser(options) { + if (!(this instanceof N3StreamParser)) + return new N3StreamParser(options); + + // Initialize Transform base class + Transform.call(this, { decodeStrings: true }); + this._readableState.objectMode = true; + + // Set up parser + var self = this, parser = new N3Parser(options), onData, onEnd; + // Pass dummy stream to obtain `data` and `end` callbacks + parser.parse({ + on: function (event, cb) { + switch (event) { + case 'data': onData = cb; break; + case 'end': onEnd = cb; break; + } + }, + }, + // Handle triples by pushing them down the pipeline + function (error, t) { error && self.emit('error', error) || t && self.push(t); }, + // Emit prefixes through the `prefix` event + function (prefix, uri) { self.emit('prefix', prefix, uri); }); + + // Implement Transform methods through parser callbacks + this._transform = function (chunk, encoding, done) { onData(chunk); done(); }; + this._flush = function (done) { onEnd(); done(); }; +} +util.inherits(N3StreamParser, Transform); + +// ## Exports +module.exports = N3StreamParser; + +},{"./N3Parser.js":232,"stream":36,"util":51}],235:[function(_dereq_,module,exports){ +// **N3StreamWriter** serializes a triple stream into an N3 stream. +var Transform = _dereq_('stream').Transform, + util = _dereq_('util'), + N3Writer = _dereq_('./N3Writer.js'); + +// ## Constructor +function N3StreamWriter(options) { + if (!(this instanceof N3StreamWriter)) + return new N3StreamWriter(options); + + // Initialize Transform base class + Transform.call(this, { encoding: 'utf8' }); + this._writableState.objectMode = true; + + // Set up writer with a dummy stream object + var self = this; + var writer = new N3Writer({ + write: function (chunk, encoding, callback) { self.push(chunk); callback && callback(); }, + end: function (callback) { self.push(null); callback && callback(); }, + }, options); + + // Implement Transform methods on top of writer + this._transform = function (triple, encoding, done) { writer.addTriple(triple, done); }; + this._flush = function (done) { writer.end(done); }; +} +util.inherits(N3StreamWriter, Transform); + +// ## Exports +module.exports = N3StreamWriter; + +},{"./N3Writer.js":237,"stream":36,"util":51}],236:[function(_dereq_,module,exports){ +// **N3Util** provides N3 utility functions. + +var Xsd = 'http://www.w3.org/2001/XMLSchema#'; +var XsdString = Xsd + 'string'; +var XsdInteger = Xsd + 'integer'; +var XsdDouble = Xsd + 'double'; +var XsdBoolean = Xsd + 'boolean'; +var RdfLangString = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'; + +var N3Util = { + // Tests whether the given entity (triple object) represents an IRI in the N3 library + isIRI: function (entity) { + if (typeof entity !== 'string') + return false; + else if (entity.length === 0) + return true; + else { + var firstChar = entity[0]; + return firstChar !== '"' && firstChar !== '_'; + } + }, + + // Tests whether the given entity (triple object) represents a literal in the N3 library + isLiteral: function (entity) { + return typeof entity === 'string' && entity[0] === '"'; + }, + + // Tests whether the given entity (triple object) represents a blank node in the N3 library + isBlank: function (entity) { + return typeof entity === 'string' && entity.substr(0, 2) === '_:'; + }, + + // Tests whether the given entity represents the default graph + isDefaultGraph: function (entity) { + return !entity; + }, + + // Tests whether the given triple is in the default graph + inDefaultGraph: function (triple) { + return !triple.graph; + }, + + // Gets the string value of a literal in the N3 library + getLiteralValue: function (literal) { + var match = /^"([^]*)"/.exec(literal); + if (!match) + throw new Error(literal + ' is not a literal'); + return match[1]; + }, + + // Gets the type of a literal in the N3 library + getLiteralType: function (literal) { + var match = /^"[^]*"(?:\^\^([^"]+)|(@)[^@"]+)?$/.exec(literal); + if (!match) + throw new Error(literal + ' is not a literal'); + return match[1] || (match[2] ? RdfLangString : XsdString); + }, + + // Gets the language of a literal in the N3 library + getLiteralLanguage: function (literal) { + var match = /^"[^]*"(?:@([^@"]+)|\^\^[^"]+)?$/.exec(literal); + if (!match) + throw new Error(literal + ' is not a literal'); + return match[1] ? match[1].toLowerCase() : ''; + }, + + // Tests whether the given entity (triple object) represents a prefixed name + isPrefixedName: function (entity) { + return typeof entity === 'string' && /^[^:\/"']*:[^:\/"']+$/.test(entity); + }, + + // Expands the prefixed name to a full IRI (also when it occurs as a literal's type) + expandPrefixedName: function (prefixedName, prefixes) { + var match = /(?:^|"\^\^)([^:\/#"'\^_]*):[^\/]*$/.exec(prefixedName), prefix, base, index; + if (match) + prefix = match[1], base = prefixes[prefix], index = match.index; + if (base === undefined) + return prefixedName; + + // The match index is non-zero when expanding a literal's type + return index === 0 ? base + prefixedName.substr(prefix.length + 1) + : prefixedName.substr(0, index + 3) + + base + prefixedName.substr(index + prefix.length + 4); + }, + + // Creates an IRI in N3.js representation + createIRI: function (iri) { + return iri && iri[0] === '"' ? N3Util.getLiteralValue(iri) : iri; + }, + + // Creates a literal in N3.js representation + createLiteral: function (value, modifier) { + if (!modifier) { + switch (typeof value) { + case 'boolean': + modifier = XsdBoolean; + break; + case 'number': + if (isFinite(value)) + modifier = value % 1 === 0 ? XsdInteger : XsdDouble; + else { + modifier = XsdDouble; + if (!isNaN(value)) + value = value > 0 ? 'INF' : '-INF'; } + break; + default: + return '"' + value + '"'; } - return null; } - }, { - key: 'parseCURIEOrURI', - value: function parseCURIEOrURI(value, prefixes, base) { - var curie = this.parseCURIE(value, prefixes, base); - if (curie) { - return curie; + return '"' + value + + (/^[a-z]+(-[a-z0-9]+)*$/i.test(modifier) ? '"@' + modifier.toLowerCase() + : '"^^' + modifier); + }, + + // Creates a function that prepends the given IRI to a local name + prefix: function (iri) { + return N3Util.prefixes({ '': iri })(''); + }, + + // Creates a function that allows registering and expanding prefixes + prefixes: function (defaultPrefixes) { + // Add all of the default prefixes + var prefixes = Object.create(null); + for (var prefix in defaultPrefixes) + processPrefix(prefix, defaultPrefixes[prefix]); + + // Registers a new prefix (if an IRI was specified) + // or retrieves a function that expands an existing prefix (if no IRI was specified) + function processPrefix(prefix, iri) { + // Create a new prefix if an IRI is specified or the prefix doesn't exist + if (iri || !(prefix in prefixes)) { + var cache = Object.create(null); + iri = iri || ''; + // Create a function that expands the prefix + prefixes[prefix] = function (localName) { + return cache[localName] || (cache[localName] = iri + localName); + }; } - return this.resolveAndNormalize(base, value); + return prefixes[prefix]; } - }, { - key: 'parsePredicate', - value: function parsePredicate(value, defaultVocabulary, terms, prefixes, base, ignoreTerms) { - if (value === '') { - return null; + return processPrefix; + }, +}; + +// ## Exports +module.exports = N3Util; + +},{}],237:[function(_dereq_,module,exports){ +// **N3Writer** writes N3 documents. + +// Matches a literal as represented in memory by the N3 library +var N3LiteralMatcher = /^"([^]*)"(?:\^\^(.+)|@([\-a-z]+))?$/i; + +// rdf:type predicate (for 'a' abbreviation) +var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', + RDF_TYPE = RDF_PREFIX + 'type'; + +// Characters in literals that require escaping +var escape = /["\\\t\n\r\b\f\u0000-\u0019\ud800-\udbff]/, + escapeAll = /["\\\t\n\r\b\f\u0000-\u0019]|[\ud800-\udbff][\udc00-\udfff]/g, + escapedCharacters = { + '\\': '\\\\', '"': '\\"', '\t': '\\t', + '\n': '\\n', '\r': '\\r', '\b': '\\b', '\f': '\\f', + }; + +// ## Constructor +function N3Writer(outputStream, options) { + if (!(this instanceof N3Writer)) + return new N3Writer(outputStream, options); + + // Shift arguments if the first argument is not a stream + if (outputStream && typeof outputStream.write !== 'function') + options = outputStream, outputStream = null; + options = options || {}; + + // If no output stream given, send the output as string through the end callback + if (!outputStream) { + var output = ''; + this._outputStream = { + write: function (chunk, encoding, done) { output += chunk; done && done(); }, + end: function (done) { done && done(null, output); }, + }; + this._endStream = true; + } + else { + this._outputStream = outputStream; + this._endStream = options.end === undefined ? true : !!options.end; + } + + // Initialize writer, depending on the format + this._subject = null; + if (!(/triple|quad/i).test(options.format)) { + this._graph = ''; + this._prefixIRIs = Object.create(null); + options.prefixes && this.addPrefixes(options.prefixes); + } + else { + this._writeTriple = this._writeTripleLine; + } +} + +N3Writer.prototype = { + // ## Private methods + + // ### `_write` writes the argument to the output stream + _write: function (string, callback) { + this._outputStream.write(string, 'utf8', callback); + }, + + // ### `_writeTriple` writes the triple to the output stream + _writeTriple: function (subject, predicate, object, graph, done) { + try { + // Write the graph's label if it has changed + if (this._graph !== graph) { + // Close the previous graph and start the new one + this._write((this._subject === null ? '' : (this._graph ? '\n}\n' : '.\n')) + + (graph ? this._encodeIriOrBlankNode(graph) + ' {\n' : '')); + this._subject = null; + // Don't treat identical blank nodes as repeating graphs + this._graph = graph[0] !== '[' ? graph : ']'; } - var predicate = this.parseTermOrCURIEOrAbsURI(value, defaultVocabulary, ignoreTerms ? null : terms, prefixes, base); - if (predicate && predicate.indexOf('_:') === 0) { - return null; + // Don't repeat the subject if it's the same + if (this._subject === subject) { + // Don't repeat the predicate if it's the same + if (this._predicate === predicate) + this._write(', ' + this._encodeObject(object), done); + // Same subject, different predicate + else + this._write(';\n ' + + this._encodePredicate(this._predicate = predicate) + ' ' + + this._encodeObject(object), done); } - return predicate; + // Different subject; write the whole triple + else + this._write((this._subject === null ? '' : '.\n') + + this._encodeSubject(this._subject = subject) + ' ' + + this._encodePredicate(this._predicate = predicate) + ' ' + + this._encodeObject(object), done); } - }, { - key: 'parsePrefixMappings', - value: function parsePrefixMappings(str, target) { - var values = this.tokenize(str); - var prefix = null; - // var uri = null - for (var i = 0; i < values.length; i++) { - if (values[i][values[i].length - 1] === ':') { - prefix = values[i].substring(0, values[i].length - 1); - } else if (prefix) { - target[prefix] = this.options.base ? Uri.join(values[i], this.options.base) : values[i]; - prefix = null; + catch (error) { done && done(error); } + }, + + // ### `_writeTripleLine` writes the triple or quad to the output stream as a single line + _writeTripleLine: function (subject, predicate, object, graph, done) { + // Write the triple without prefixes + delete this._prefixMatch; + try { this._write(this.tripleToString(subject, predicate, object, graph), done); } + catch (error) { done && done(error); } + }, + + // ### `tripleToString` serializes a triple or quad as a string + tripleToString: function (subject, predicate, object, graph) { + return this._encodeIriOrBlankNode(subject) + ' ' + + this._encodeIriOrBlankNode(predicate) + ' ' + + this._encodeObject(object) + + (graph ? ' ' + this._encodeIriOrBlankNode(graph) + '.\n' : '.\n'); + }, + + // ### `triplesToString` serializes an array of triples or quads as a string + triplesToString: function (triples) { + return triples.map(function (t) { + return this.tripleToString(t.subject, t.predicate, t.object, t.graph); + }, this).join(''); + }, + + // ### `_encodeIriOrBlankNode` represents an IRI or blank node + _encodeIriOrBlankNode: function (entity) { + // A blank node or list is represented as-is + var firstChar = entity[0]; + if (firstChar === '[' || firstChar === '(' || firstChar === '_' && entity[1] === ':') + return entity; + // Escape special characters + if (escape.test(entity)) + entity = entity.replace(escapeAll, characterReplacer); + // Try to represent the IRI as prefixed name + var prefixMatch = this._prefixRegex.exec(entity); + return !prefixMatch ? '<' + entity + '>' : + (!prefixMatch[1] ? entity : this._prefixIRIs[prefixMatch[1]] + prefixMatch[2]); + }, + + // ### `_encodeLiteral` represents a literal + _encodeLiteral: function (value, type, language) { + // Escape special characters + if (escape.test(value)) + value = value.replace(escapeAll, characterReplacer); + // Write the literal, possibly with type or language + if (language) + return '"' + value + '"@' + language; + else if (type) + return '"' + value + '"^^' + this._encodeIriOrBlankNode(type); + else + return '"' + value + '"'; + }, + + // ### `_encodeSubject` represents a subject + _encodeSubject: function (subject) { + if (subject[0] === '"') + throw new Error('A literal as subject is not allowed: ' + subject); + // Don't treat identical blank nodes as repeating subjects + if (subject[0] === '[') + this._subject = ']'; + return this._encodeIriOrBlankNode(subject); + }, + + // ### `_encodePredicate` represents a predicate + _encodePredicate: function (predicate) { + if (predicate[0] === '"') + throw new Error('A literal as predicate is not allowed: ' + predicate); + return predicate === RDF_TYPE ? 'a' : this._encodeIriOrBlankNode(predicate); + }, + + // ### `_encodeObject` represents an object + _encodeObject: function (object) { + // Represent an IRI or blank node + if (object[0] !== '"') + return this._encodeIriOrBlankNode(object); + // Represent a literal + var match = N3LiteralMatcher.exec(object); + if (!match) throw new Error('Invalid literal: ' + object); + return this._encodeLiteral(match[1], match[2], match[3]); + }, + + // ### `_blockedWrite` replaces `_write` after the writer has been closed + _blockedWrite: function () { + throw new Error('Cannot write because the writer has been closed.'); + }, + + // ### `addTriple` adds the triple to the output stream + addTriple: function (subject, predicate, object, graph, done) { + // The triple was given as a triple object, so shift parameters + if (object === undefined) + this._writeTriple(subject.subject, subject.predicate, subject.object, + subject.graph || '', predicate); + // The optional `graph` parameter was not provided + else if (typeof graph !== 'string') + this._writeTriple(subject, predicate, object, '', graph); + // The `graph` parameter was provided + else + this._writeTriple(subject, predicate, object, graph, done); + }, + + // ### `addTriples` adds the triples to the output stream + addTriples: function (triples) { + for (var i = 0; i < triples.length; i++) + this.addTriple(triples[i]); + }, + + // ### `addPrefix` adds the prefix to the output stream + addPrefix: function (prefix, iri, done) { + var prefixes = {}; + prefixes[prefix] = iri; + this.addPrefixes(prefixes, done); + }, + + // ### `addPrefixes` adds the prefixes to the output stream + addPrefixes: function (prefixes, done) { + // Add all useful prefixes + var prefixIRIs = this._prefixIRIs, hasPrefixes = false; + for (var prefix in prefixes) { + // Verify whether the prefix can be used and does not exist yet + var iri = prefixes[prefix]; + if (/[#\/]$/.test(iri) && prefixIRIs[iri] !== (prefix += ':')) { + hasPrefixes = true; + prefixIRIs[iri] = prefix; + // Finish a possible pending triple + if (this._subject !== null) { + this._write(this._graph ? '\n}\n' : '.\n'); + this._subject = null, this._graph = ''; } + // Write prefix + this._write('@prefix ' + prefix + ' <' + iri + '>.\n'); } } - }, { - key: 'parseSafeCURIEOrCURIEOrURI', - value: function parseSafeCURIEOrCURIEOrURI(value, prefixes, base) { - value = this.trim(value); - if (value.charAt(0) === '[' && value.charAt(value.length - 1) === ']') { - value = value.substring(1, value.length - 1); - value = value.trim(value); - if (value.length === 0) { - return null; - } - if (value === '_:') { - // the one node - return this.theOne; - } - return this.parseCURIE(value, prefixes, base); - } else { - return this.parseCURIEOrURI(value, prefixes, base); + // Recreate the prefix matcher + if (hasPrefixes) { + var IRIlist = '', prefixList = ''; + for (var prefixIRI in prefixIRIs) { + IRIlist += IRIlist ? '|' + prefixIRI : prefixIRI; + prefixList += (prefixList ? '|' : '') + prefixIRIs[prefixIRI]; } + IRIlist = IRIlist.replace(/[\]\/\(\)\*\+\?\.\\\$]/g, '\\$&'); + this._prefixRegex = new RegExp('^(?:' + prefixList + ')[^\/]*$|' + + '^(' + IRIlist + ')([a-zA-Z][\\-_a-zA-Z0-9]*)$'); } - }, { - key: 'parseTermOrCURIEOrAbsURI', - value: function parseTermOrCURIEOrAbsURI(value, defaultVocabulary, terms, prefixes, base) { - // alert("Parsing "+value+" with default vocab "+defaultVocabulary) - value = this.trim(value); - var curie = this.parseCURIE(value, prefixes, base); - if (curie) { - return curie; - } else if (terms) { - if (defaultVocabulary && !this.absURIRE.exec(value)) { - return defaultVocabulary + value; - } - var term = terms[value]; - if (term) { - return term; - } - var lcvalue = value.toLowerCase(); - term = terms[lcvalue]; - if (term) { - return term; + // End a prefix block with a newline + this._write(hasPrefixes ? '\n' : '', done); + }, + + // ### `blank` creates a blank node with the given content + blank: function (predicate, object) { + var children = predicate, child, length; + // Empty blank node + if (predicate === undefined) + children = []; + // Blank node passed as blank("predicate", "object") + else if (typeof predicate === 'string') + children = [{ predicate: predicate, object: object }]; + // Blank node passed as blank({ predicate: predicate, object: object }) + else if (!('length' in predicate)) + children = [predicate]; + + switch (length = children.length) { + // Generate an empty blank node + case 0: + return '[]'; + // Generate a non-nested one-triple blank node + case 1: + child = children[0]; + if (child.object[0] !== '[') + return '[ ' + this._encodePredicate(child.predicate) + ' ' + + this._encodeObject(child.object) + ' ]'; + // Generate a multi-triple or nested blank node + default: + var contents = '['; + // Write all triples in order + for (var i = 0; i < length; i++) { + child = children[i]; + // Write only the object is the predicate is the same as the previous + if (child.predicate === predicate) + contents += ', ' + this._encodeObject(child.object); + // Otherwise, write the predicate and the object + else { + contents += (i ? ';\n ' : '\n ') + + this._encodePredicate(child.predicate) + ' ' + + this._encodeObject(child.object); + predicate = child.predicate; } } - if (this.absURIRE.exec(value)) { - return this.resolveAndNormalize(base, value); - } - return null; + return contents + '\n]'; } - }, { - key: 'parseTermOrCURIEOrURI', - value: function parseTermOrCURIEOrURI(value, defaultVocabulary, terms, prefixes, base) { - // alert("Parsing "+value+" with default vocab "+defaultVocabulary) - value = this.trim(value); - var curie = this.parseCURIE(value, prefixes, base); - if (curie) { - return curie; - } else { - var term = terms[value]; - if (term) { - return term; - } - var lcvalue = value.toLowerCase(); - term = terms[lcvalue]; - if (term) { - return term; - } - if (defaultVocabulary && !this.absURIRE.exec(value)) { - return defaultVocabulary + value; - } - } - return this.resolveAndNormalize(base, value); + }, + + // ### `list` creates a list node with the given content + list: function (elements) { + var length = elements && elements.length || 0, contents = new Array(length); + for (var i = 0; i < length; i++) + contents[i] = this._encodeObject(elements[i]); + return '(' + contents.join(' ') + ')'; + }, + + // ### `_prefixRegex` matches a prefixed name or IRI that begins with one of the added prefixes + _prefixRegex: /$0^/, + + // ### `end` signals the end of the output stream + end: function (done) { + // Finish a possible pending triple + if (this._subject !== null) { + this._write(this._graph ? '\n}\n' : '.\n'); + this._subject = null; } - }, { - key: 'parseURI', - value: function parseURI(uri) { - return uri; // We just use strings as URIs, not objects now. + // Disallow further writing + this._write = this._blockedWrite; + + // Try to end the underlying stream, ensuring done is called exactly one time + var singleDone = done && function (error, result) { singleDone = null, done(error, result); }; + if (this._endStream) { + try { return this._outputStream.end(singleDone); } + catch (error) { /* error closing stream */ } } - }, { - key: 'process', - value: function process(node, options) { - /* - if (!window.console) { - window.console = { log: function() {} } - }*/ - var base; - if (node.nodeType === Node.DOCUMENT_NODE) { - base = node.baseURI; - node = node.documentElement; - node.baseURI = base; - this.setContext(node); - } else if (node.parentNode.nodeType === Node.DOCUMENT_NODE) { - this.setContext(node); - } - var queue = []; - // Fix for Firefox that includes the hash in the base URI - var removeHash = function removeHash(baseURI) { - // Fix for undefined baseURI property - if (!baseURI && options && options.baseURI) { - return options.baseURI; - } + singleDone && singleDone(); + }, +}; - var hash = baseURI.indexOf('#'); - if (hash >= 0) { - baseURI = baseURI.substring(0, hash); - } - if (options && options.baseURIMap) { - baseURI = options.baseURIMap(baseURI); - } - return baseURI; - }; - queue.push({ current: node, - context: this.push(null, removeHash(node.baseURI)) - }); - while (queue.length > 0) { - var item = queue.shift(); - if (item.parent) { - // Sequence Step 14: list triple generation - if (item.context.parent && item.context.parent.listMapping === item.listMapping) { - // Skip a child context with exactly the same mapping - continue; - } - // console.log("Generating lists for "+item.subject+", tag "+item.parent.localName) - for (var _predicate in item.listMapping) { - var list = item.listMapping[_predicate]; - if (list.length === 0) { - this.addTriple(item.parent, item.subject, _predicate, { type: RDFaProcessor.objectURI, value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' }); - continue; - } - var bnodes = []; - for (var _i = 0; _i < list.length; _i++) { - bnodes.push(this.newBlankNode()); - // this.newSubject(item.parent,bnodes[i]) - } - for (var _i2 = 0; _i2 < bnodes.length; _i2++) { - this.addTriple(item.parent, bnodes[_i2], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', list[_i2]); - this.addTriple(item.parent, bnodes[_i2], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', { type: RDFaProcessor.objectURI, value: _i2 + 1 < bnodes.length ? bnodes[_i2 + 1] : 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' }); - } - this.addTriple(item.parent, item.subject, _predicate, { type: RDFaProcessor.objectURI, value: bnodes[0] }); - } - continue; - } - var current = item.current; - var context = item.context; - // console.log("Tag: "+current.localName+", listMapping="+JSON.stringify(context.listMapping)) - // Sequence Step 1 - var skip = false; - var newSubject = null; - var currentObjectResource = null; - var typedResource = null; - var prefixes = context.prefixes; - var prefixesCopied = false; - var incomplete = []; - var listMapping = context.listMapping; - var listMappingDifferent = !context.parent; - var language = context.language; - var vocabulary = context.vocabulary; - // TODO: the "base" element may be used for HTML+RDFa 1.1 - base = this.parseURI(removeHash(current.baseURI)); - current.item = null; - // Sequence Step 2: set the default vocabulary - var vocabAtt = current.getAttributeNode('vocab'); - if (vocabAtt) { - var value = this.trim(vocabAtt.value); - if (value.length > 0) { - vocabulary = value; - var baseSubject = base.spec; - // this.newSubject(current,baseSubject) - this.addTriple(current, baseSubject, 'http://www.w3.org/ns/rdfa#usesVocabulary', { type: RDFaProcessor.objectURI, value: vocabulary }); - } else { - vocabulary = this.vocabulary; - } - } - // Sequence Step 3: IRI mappings - // handle xmlns attributes - for (var i = 0; i < current.attributes.length; i++) { - var att = current.attributes[i]; - // if (att.namespaceURI=="http://www.w3.org/2000/xmlns/") { - if (att.nodeName.charAt(0) === 'x' && att.nodeName.indexOf('xmlns:') === 0) { - if (!prefixesCopied) { - prefixes = this.copyMappings(prefixes); - prefixesCopied = true; - } - var prefix = att.nodeName.substring(6); - // TODO: resolve relative? - var ref = RDFaProcessor.trim(att.value); - prefixes[prefix] = this.options.base ? Uri.join(ref, this.options.base) : ref; - } - } - // Handle prefix mappings (@prefix) - var prefixAtt = current.getAttributeNode('prefix'); - if (prefixAtt) { - if (!prefixesCopied) { - prefixes = this.copyMappings(prefixes); - prefixesCopied = true; - } - this.parsePrefixMappings(prefixAtt.value, prefixes); - } - // Sequence Step 4: language - var xmlLangAtt = null; - for (var _i3 = 0; !xmlLangAtt && _i3 < this.langAttributes.length; _i3++) { - xmlLangAtt = current.getAttributeNodeNS(this.langAttributes[_i3].namespaceURI, this.langAttributes[_i3].localName); - } - if (xmlLangAtt) { - var _value = RDFaProcessor.trim(xmlLangAtt.value); - if (_value.length > 0) { - language = _value; - } else { - language = null; - } - } - var relAtt = current.getAttributeNode('rel'); - var revAtt = current.getAttributeNode('rev'); - var typeofAtt = current.getAttributeNode('typeof'); - var propertyAtt = current.getAttributeNode('property'); - var datatypeAtt = current.getAttributeNode('datatype'); - var datetimeAtt = this.inHTMLMode ? current.getAttributeNode('datetime') : null; - var contentAtt = current.getAttributeNode('content'); - var aboutAtt = current.getAttributeNode('about'); - var srcAtt = current.getAttributeNode('src'); - var resourceAtt = current.getAttributeNode('resource'); - var hrefAtt = current.getAttributeNode('href'); - var inlistAtt = current.getAttributeNode('inlist'); - var relAttPredicates = []; - var predicate, values; - if (relAtt) { - values = this.tokenize(relAtt.value); - for (var _i4 = 0; _i4 < values.length; _i4++) { - predicate = this.parsePredicate(values[_i4], vocabulary, context.terms, prefixes, base, this.inHTMLMode && propertyAtt !== null); - if (predicate) { - relAttPredicates.push(predicate); - } - } - } - var revAttPredicates = []; - if (revAtt) { - values = this.tokenize(revAtt.value); - for (var _i5 = 0; _i5 < values.length; _i5++) { - predicate = this.parsePredicate(values[_i5], vocabulary, context.terms, prefixes, base, this.inHTMLMode && propertyAtt); - if (predicate) { - revAttPredicates.push(predicate); - } - } - } - // Section 3.1, bullet 7 - if (this.inHTMLMode && (relAtt || revAtt) && propertyAtt) { - if (relAttPredicates.length === 0) { - relAtt = null; - } - if (revAttPredicates.length === 0) { - revAtt = null; - } - } - if (relAtt || revAtt) { - // Sequence Step 6: establish new subject and value - if (aboutAtt) { - newSubject = this.parseSafeCURIEOrCURIEOrURI(aboutAtt.value, prefixes, base); - } - if (typeofAtt) { - typedResource = newSubject; - } - if (!newSubject) { - if (current.parentNode.nodeType === Node.DOCUMENT_NODE) { - newSubject = removeHash(current.baseURI); - } else if (context.parentObject) { - // TODO: Verify: If the xml:base has been set and the parentObject is the baseURI of the parent, then the subject needs to be the new base URI - newSubject = removeHash(current.parentNode.baseURI) === context.parentObject ? removeHash(current.baseURI) : context.parentObject; - } - } - if (resourceAtt) { - currentObjectResource = this.parseSafeCURIEOrCURIEOrURI(resourceAtt.value, prefixes, base); - } - if (!currentObjectResource) { - if (hrefAtt) { - currentObjectResource = this.resolveAndNormalize(base, encodeURI(hrefAtt.value)); - } else if (srcAtt) { - currentObjectResource = this.resolveAndNormalize(base, encodeURI(srcAtt.value)); - } else if (typeofAtt && !aboutAtt && !(this.inXHTMLMode && (current.localName === 'head' || current.localName === 'body'))) { - currentObjectResource = this.newBlankNode(); - } - } - if (typeofAtt && !aboutAtt && this.inXHTMLMode && (current.localName === 'head' || current.localName === 'body')) { - typedResource = newSubject; - } else if (typeofAtt && !aboutAtt) { - typedResource = currentObjectResource; - } - } else if (propertyAtt && !contentAtt && !datatypeAtt) { - // Sequence Step 5.1: establish a new subject - if (aboutAtt) { - newSubject = this.parseSafeCURIEOrCURIEOrURI(aboutAtt.value, prefixes, base); - if (typeofAtt) { - typedResource = newSubject; - } - } - if (!newSubject && current.parentNode.nodeType === Node.DOCUMENT_NODE) { - newSubject = removeHash(current.baseURI); - if (typeofAtt) { - typedResource = newSubject; - } - } else if (!newSubject && context.parentObject) { - // TODO: Verify: If the xml:base has been set and the parentObject is the baseURI of the parent, then the subject needs to be the new base URI - newSubject = removeHash(current.parentNode.baseURI) === context.parentObject ? removeHash(current.baseURI) : context.parentObject; - } - if (typeofAtt && !typedResource) { - if (resourceAtt) { - typedResource = this.parseSafeCURIEOrCURIEOrURI(resourceAtt.value, prefixes, base); - } - if (!typedResource && hrefAtt) { - typedResource = this.resolveAndNormalize(base, encodeURI(hrefAtt.value)); - } - if (!typedResource && srcAtt) { - typedResource = this.resolveAndNormalize(base, encodeURI(srcAtt.value)); - } - if (!typedResource && (this.inXHTMLMode || this.inHTMLMode) && (current.localName === 'head' || current.localName === 'body')) { - typedResource = newSubject; - } - if (!typedResource) { - typedResource = this.newBlankNode(); - } - currentObjectResource = typedResource; - } - // console.log(current.localName+", newSubject="+newSubject+", typedResource="+typedResource+", currentObjectResource="+currentObjectResource) - } else { - // Sequence Step 5.2: establish a new subject - if (aboutAtt) { - newSubject = this.parseSafeCURIEOrCURIEOrURI(aboutAtt.value, prefixes, base); - } - if (!newSubject && resourceAtt) { - newSubject = this.parseSafeCURIEOrCURIEOrURI(resourceAtt.value, prefixes, base); - } - if (!newSubject && hrefAtt) { - newSubject = this.resolveAndNormalize(base, encodeURI(hrefAtt.value)); - } - if (!newSubject && srcAtt) { - newSubject = this.resolveAndNormalize(base, encodeURI(srcAtt.value)); - } - if (!newSubject) { - if (current.parentNode.nodeType === Node.DOCUMENT_NODE) { - newSubject = removeHash(current.baseURI); - } else if ((this.inXHTMLMode || this.inHTMLMode) && (current.localName === 'head' || current.localName === 'body')) { - newSubject = removeHash(current.parentNode.baseURI) === context.parentObject ? removeHash(current.baseURI) : context.parentObject; - } else if (typeofAtt) { - newSubject = this.newBlankNode(); - } else if (context.parentObject) { - // TODO: Verify: If the xml:base has been set and the parentObject is the baseURI of the parent, then the subject needs to be the new base URI - newSubject = removeHash(current.parentNode.baseURI) === context.parentObject ? removeHash(current.baseURI) : context.parentObject; - if (!propertyAtt) { - skip = true; - } - } - } - if (typeofAtt) { - typedResource = newSubject; - } - } - // console.log(current.tagName+": newSubject="+newSubject+", currentObjectResource="+currentObjectResource+", typedResource="+typedResource+", skip="+skip) - // var rdfaData = null - if (newSubject) { - // this.newSubject(current,newSubject) - if (aboutAtt || resourceAtt || typedResource) { - var id = newSubject; - if (typeofAtt && !aboutAtt && !resourceAtt && currentObjectResource) { - id = currentObjectResource; - } - // console.log("Setting data attribute for "+current.localName+" for subject "+id) - this.newSubjectOrigin(current, id); - } - } - // Sequence Step 7: generate type triple - if (typedResource) { - values = this.tokenize(typeofAtt.value); - for (var _i6 = 0; _i6 < values.length; _i6++) { - var object = this.parseTermOrCURIEOrAbsURI(values[_i6], vocabulary, context.terms, prefixes, base); - if (object) { - this.addTriple(current, typedResource, RDFaProcessor.typeURI, { type: RDFaProcessor.objectURI, value: object }); - } - } - } - // Sequence Step 8: new list mappings if there is a new subject - // console.log("Step 8: newSubject="+newSubject+", context.parentObject="+context.parentObject) - if (newSubject && newSubject !== context.parentObject) { - // console.log("Generating new list mapping for "+newSubject) - listMapping = {}; - listMappingDifferent = true; - } - // Sequence Step 9: generate object triple - if (currentObjectResource) { - if (relAtt && inlistAtt) { - for (var _i7 = 0; _i7 < relAttPredicates.length; _i7++) { - var _list = listMapping[relAttPredicates[_i7]]; - if (!_list) { - _list = []; - listMapping[relAttPredicates[_i7]] = _list; - } - _list.push({ type: RDFaProcessor.objectURI, value: currentObjectResource }); - } - } else if (relAtt) { - for (var _i8 = 0; _i8 < relAttPredicates.length; _i8++) { - this.addTriple(current, newSubject, relAttPredicates[_i8], { type: RDFaProcessor.objectURI, value: currentObjectResource }); - } - } - if (revAtt) { - for (var _i9 = 0; _i9 < revAttPredicates.length; _i9++) { - this.addTriple(current, currentObjectResource, revAttPredicates[_i9], { type: RDFaProcessor.objectURI, value: newSubject }); - } - } +// Replaces a character by its escaped version +function characterReplacer(character) { + // Replace a single character by its escaped version + var result = escapedCharacters[character]; + if (result === undefined) { + // Replace a single character with its 4-bit unicode escape sequence + if (character.length === 1) { + result = character.charCodeAt(0).toString(16); + result = '\\u0000'.substr(0, 6 - result.length) + result; + } + // Replace a surrogate pair with its 8-bit unicode escape sequence + else { + result = ((character.charCodeAt(0) - 0xD800) * 0x400 + + character.charCodeAt(1) + 0x2400).toString(16); + result = '\\U00000000'.substr(0, 10 - result.length) + result; + } + } + return result; +} + +// ## Exports +module.exports = N3Writer; + +},{}],238:[function(_dereq_,module,exports){ +/** +* pretty-data - nodejs plugin to pretty-print or minify data in XML, JSON and CSS formats. +* +* Version - 0.40.0 +* Copyright (c) 2012 Vadim Kiryukhin +* vkiryukhin @ gmail.com +* http://www.eslinstructor.net/pretty-data/ +* +* Dual licensed under the MIT and GPL licenses: +* http://www.opensource.org/licenses/mit-license.php +* http://www.gnu.org/licenses/gpl.html +* +* pd.xml(data ) - pretty print XML; +* pd.json(data) - pretty print JSON; +* pd.css(data ) - pretty print CSS; +* pd.sql(data) - pretty print SQL; +* +* pd.xmlmin(data [, preserveComments] ) - minify XML; +* pd.jsonmin(data) - minify JSON; +* pd.cssmin(data [, preserveComments] ) - minify CSS; +* pd.sqlmin(data) - minify SQL; +* +* PARAMETERS: +* +* @data - String; XML, JSON, CSS or SQL text to beautify; +* @preserveComments - Bool (optional, used in minxml and mincss only); +* Set this flag to true to prevent removing comments from @text; +* @Return - String; +* +* USAGE: +* +* var pd = require('pretty-data').pd; +* +* var xml_pp = pd.xml(xml_text); +* var xml_min = pd.xmlmin(xml_text [,true]); +* var json_pp = pd.json(json_text); +* var json_min = pd.jsonmin(json_text); +* var css_pp = pd.css(css_text); +* var css_min = pd.cssmin(css_text [, true]); +* var sql_pp = pd.sql(sql_text); +* var sql_min = pd.sqlmin(sql_text); +* +* TEST: +* comp-name:pretty-data$ node ./test/test_xml +* comp-name:pretty-data$ node ./test/test_json +* comp-name:pretty-data$ node ./test/test_css +* comp-name:pretty-data$ node ./test/test_sql +*/ + + +function pp() { + this.shift = ['\n']; // array of shifts + this.step = ' ', // 2 spaces + maxdeep = 100, // nesting level + ix = 0; + + // initialize array with shifts // + for(ix=0;ix\s{0,}<") + .replace(/ or -1) { + str += this.shift[deep]+ar[ix]; + inComment = true; + // end comment or // + if(ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1 || ar[ix].search(/!DOCTYPE/) > -1 ) { + inComment = false; + } + } else + // end comment or // + if(ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1) { + str += ar[ix]; + inComment = false; + } else + // // + if( /^<\w/.exec(ar[ix-1]) && /^<\/\w/.exec(ar[ix]) && + /^<[\w:\-\.\,]+/.exec(ar[ix-1]) == /^<\/[\w:\-\.\,]+/.exec(ar[ix])[0].replace('/','')) { + str += ar[ix]; + if(!inComment) deep--; + } else + // // + if(ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) == -1 && ar[ix].search(/\/>/) == -1 ) { + str = !inComment ? str += this.shift[deep++]+ar[ix] : str += ar[ix]; + } else + // ... // + if(ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) > -1) { + str = !inComment ? str += this.shift[deep]+ar[ix] : str += ar[ix]; + } else + // // + if(ar[ix].search(/<\//) > -1) { + str = !inComment ? str += this.shift[--deep]+ar[ix] : str += ar[ix]; + } else + // // + if(ar[ix].search(/\/>/) > -1 ) { + str = !inComment ? str += this.shift[deep]+ar[ix] : str += ar[ix]; + } else + // // + if(ar[ix].search(/<\?/) > -1) { + str += this.shift[deep]+ar[ix]; + } else + // xmlns // + if( ar[ix].search(/xmlns\:/) > -1 || ar[ix].search(/xmlns\=/) > -1) { + str += this.shift[deep]+ar[ix]; + } + + else { + str += ar[ix]; + } + } + + return (str[0] == '\n') ? str.slice(1) : str; +} + +// ----------------------- JSON section ---------------------------------------------------- + +pp.prototype.json = function(text) { + + if ( typeof text === "string" ) { + return JSON.stringify(JSON.parse(text), null, this.step); + } + if ( typeof text === "object" ) { + return JSON.stringify(text, null, this.step); + } + return null; +} + +// ----------------------- CSS section ---------------------------------------------------- + +pp.prototype.css = function(text) { + + var ar = text.replace(/\s{1,}/g,' ') + .replace(/\{/g,"{~::~") + .replace(/\}/g,"~::~}~::~") + .replace(/\;/g,";~::~") + .replace(/\/\*/g,"~::~/*") + .replace(/\*\//g,"*/~::~") + .replace(/~::~\s{0,}~::~/g,"~::~") + .split('~::~'), + len = ar.length, + deep = 0, + str = '', + ix = 0; + + for(ix=0;ix/g,""); + return str.replace(/>\s{0,}<"); +} + +pp.prototype.jsonmin = function(text) { + + return text.replace(/\s{0,}\{\s{0,}/g,"{") + .replace(/\s{0,}\[$/g,"[") + .replace(/\[\s{0,}/g,"[") + .replace(/:\s{0,}\[/g,':[') + .replace(/\s{0,}\}\s{0,}/g,"}") + .replace(/\s{0,}\]\s{0,}/g,"]") + .replace(/\"\s{0,}\,/g,'",') + .replace(/\,\s{0,}\"/g,',"') + .replace(/\"\s{0,}:/g,'":') + .replace(/:\s{0,}\"/g,':"') + .replace(/:\s{0,}\[/g,':[') + .replace(/\,\s{0,}\[/g,',[') + .replace(/\,\s{2,}/g,', ') + .replace(/\]\s{0,},\s{0,}\[/g,'],['); +} + +pp.prototype.cssmin = function(text, preserveComments) { + + var str = preserveComments ? text + : text.replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\//g,"") ; + return str.replace(/\s{1,}/g,' ') + .replace(/\{\s{1,}/g,"{") + .replace(/\}\s{1,}/g,"}") + .replace(/\;\s{1,}/g,";") + .replace(/\/\*\s{1,}/g,"/*") + .replace(/\*\/\s{1,}/g,"*/"); +} + +pp.prototype.sqlmin = function(text) { + return text.replace(/\s{1,}/g," ").replace(/\s{1,}\(/,"(").replace(/\s{1,}\)/,")"); +} + +// -------------------------------------------------------------------------------------------- + +exports.pd= new pp; + + + + + + + + + + + +},{}],239:[function(_dereq_,module,exports){ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var ClassOrder = _dereq_('./class-order'); +var Node = _dereq_('./node'); + +var BlankNode = function (_Node) { + _inherits(BlankNode, _Node); + + function BlankNode(id) { + _classCallCheck(this, BlankNode); + + var _this = _possibleConstructorReturn(this, (BlankNode.__proto__ || Object.getPrototypeOf(BlankNode)).call(this)); + + _this.termType = BlankNode.termType; + _this.id = BlankNode.nextId++; + _this.value = id || _this.id.toString(); + return _this; + } + + _createClass(BlankNode, [{ + key: 'compareTerm', + value: function compareTerm(other) { + if (this.classOrder < other.classOrder) { + return -1; } - if (this.inHTMLMode) { - this.copyProperties(); + if (this.classOrder > other.classOrder) { + return +1; } - for (var _i15 = 0; _i15 < this.finishedHandlers.length; _i15++) { - this.finishedHandlers[_i15](node); + if (this.id < other.id) { + return -1; } + if (this.id > other.id) { + return +1; + } + return 0; } }, { - key: 'push', - value: function push(parent, subject) { - return { - parent: parent, - subject: subject ? subject : parent ? parent.subject : null, - parentObject: null, - incomplete: [], - listMapping: parent ? parent.listMapping : {}, - language: parent ? parent.language : this.language, - prefixes: parent ? parent.prefixes : this.target.graph.prefixes, - terms: parent ? parent.terms : this.target.graph.terms, - vocabulary: parent ? parent.vocabulary : this.vocabulary - }; + key: 'copy', + value: function copy(formula) { + // depends on the formula + var bnodeNew = new BlankNode(); + formula.copyTo(this, bnodeNew); + return bnodeNew; } }, { - key: 'resolveAndNormalize', - value: function resolveAndNormalize(base, uri) { - // console.log("Joining " + uri + " to " + base + " making " + Uri.join(uri, base)) - return Uri.join(uri, base); // @@ normalize? + key: 'toCanonical', + value: function toCanonical() { + return '_:' + this.value; } }, { - key: 'setContext', - value: function setContext(node) { - // We only recognized XHTML+RDFa 1.1 if the version is set propertyly - if (node.localName === 'html' && node.getAttribute('version') === 'XHTML+RDFa 1.1') { - this.setXHTMLContext(); - } else if (node.localName === 'html' || node.namespaceURI === 'http://www.w3.org/1999/xhtml') { - if (typeof document !== 'undefined' && document.doctype) { - if (document.doctype.publicId === '-//W3C//DTD XHTML+RDFa 1.0//EN' && document.doctype.systemId === 'http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd') { - console.log('WARNING: RDF 1.0 is not supported. Defaulting to HTML5 mode.'); - this.setHTMLContext(); - } else if (document.doctype.publicId === '-//W3C//DTD XHTML+RDFa 1.1//EN' && document.doctype.systemId === 'http://www.w3.org/MarkUp/DTD/xhtml-rdfa-2.dtd') { - this.setXHTMLContext(); - } else { - this.setHTMLContext(); - } - } else { - this.setHTMLContext(); - } - } else { - this.setXMLContext(); - } + key: 'toString', + value: function toString() { + return BlankNode.NTAnonymousNodePrefix + this.id; } - }, { - key: 'setHTMLContext', - value: function setHTMLContext() { - this.setInitialContext(); - this.langAttributes = [{ - namespaceURI: 'http://www.w3.org/XML/1998/namespace', - localName: 'lang' - }, { namespaceURI: null, localName: 'lang' }]; - this.inXHTMLMode = false; - this.inHTMLMode = true; + }]); + + return BlankNode; +}(Node); + +BlankNode.nextId = 0; +BlankNode.termType = 'BlankNode'; +BlankNode.NTAnonymousNodePrefix = '_:n'; +BlankNode.prototype.classOrder = ClassOrder['BlankNode']; +BlankNode.prototype.isBlank = 1; +BlankNode.prototype.isVar = 1; + +module.exports = BlankNode; +},{"./class-order":240,"./node":256}],240:[function(_dereq_,module,exports){ +'use strict'; + +var ClassOrder = { + 'Literal': 1, + 'Collection': 3, + 'Graph': 4, + 'NamedNode': 5, + 'BlankNode': 6, + 'Variable': 7 +}; + +module.exports = ClassOrder; +},{}],241:[function(_dereq_,module,exports){ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var BlankNode = _dereq_('./blank-node'); +var ClassOrder = _dereq_('./class-order'); +var Node = _dereq_('./node'); + +var Collection = function (_Node) { + _inherits(Collection, _Node); + + function Collection(initial) { + _classCallCheck(this, Collection); + + var _this = _possibleConstructorReturn(this, (Collection.__proto__ || Object.getPrototypeOf(Collection)).call(this)); + + _this.termType = Collection.termType; + _this.id = BlankNode.nextId++; + _this.elements = []; + _this.closed = false; + if (initial && initial.length > 0) { + initial.forEach(function (element) { + _this.elements.push(Node.fromValue(element)); + }); } - }, { - key: 'setInitialContext', - value: function setInitialContext() { - this.vocabulary = null; - // By default, the prefixes are terms are loaded to the RDFa 1.1. standard within the graph constructor - this.langAttributes = [{ - namespaceURI: 'http://www.w3.org/XML/1998/namespace', - localName: 'lang' - }]; + return _this; + } + + _createClass(Collection, [{ + key: 'append', + value: function append(element) { + return this.elements.push(element); } }, { - key: 'setXHTMLContext', - value: function setXHTMLContext() { - this.setInitialContext(); - this.inXHTMLMode = true; - this.inHTMLMode = false; - this.langAttributes = [{ - namespaceURI: 'http://www.w3.org/XML/1998/namespace', - localName: 'lang' }, { namespaceURI: null, localName: 'lang' }]; - // From http://www.w3.org/2011/rdfa-context/xhtml-rdfa-1.1 - this.target.graph.terms['alternate'] = 'http://www.w3.org/1999/xhtml/vocab#alternate'; - this.target.graph.terms['appendix'] = 'http://www.w3.org/1999/xhtml/vocab#appendix'; - this.target.graph.terms['bookmark'] = 'http://www.w3.org/1999/xhtml/vocab#bookmark'; - this.target.graph.terms['cite'] = 'http://www.w3.org/1999/xhtml/vocab#cite'; - this.target.graph.terms['chapter'] = 'http://www.w3.org/1999/xhtml/vocab#chapter'; - this.target.graph.terms['contents'] = 'http://www.w3.org/1999/xhtml/vocab#contents'; - this.target.graph.terms['copyright'] = 'http://www.w3.org/1999/xhtml/vocab#copyright'; - this.target.graph.terms['first'] = 'http://www.w3.org/1999/xhtml/vocab#first'; - this.target.graph.terms['glossary'] = 'http://www.w3.org/1999/xhtml/vocab#glossary'; - this.target.graph.terms['help'] = 'http://www.w3.org/1999/xhtml/vocab#help'; - this.target.graph.terms['icon'] = 'http://www.w3.org/1999/xhtml/vocab#icon'; - this.target.graph.terms['index'] = 'http://www.w3.org/1999/xhtml/vocab#index'; - this.target.graph.terms['last'] = 'http://www.w3.org/1999/xhtml/vocab#last'; - this.target.graph.terms['license'] = 'http://www.w3.org/1999/xhtml/vocab#license'; - this.target.graph.terms['meta'] = 'http://www.w3.org/1999/xhtml/vocab#meta'; - this.target.graph.terms['next'] = 'http://www.w3.org/1999/xhtml/vocab#next'; - this.target.graph.terms['prev'] = 'http://www.w3.org/1999/xhtml/vocab#prev'; - this.target.graph.terms['previous'] = 'http://www.w3.org/1999/xhtml/vocab#previous'; - this.target.graph.terms['section'] = 'http://www.w3.org/1999/xhtml/vocab#section'; - this.target.graph.terms['stylesheet'] = 'http://www.w3.org/1999/xhtml/vocab#stylesheet'; - this.target.graph.terms['subsection'] = 'http://www.w3.org/1999/xhtml/vocab#subsection'; - this.target.graph.terms['start'] = 'http://www.w3.org/1999/xhtml/vocab#start'; - this.target.graph.terms['top'] = 'http://www.w3.org/1999/xhtml/vocab#top'; - this.target.graph.terms['up'] = 'http://www.w3.org/1999/xhtml/vocab#up'; - this.target.graph.terms['p3pv1'] = 'http://www.w3.org/1999/xhtml/vocab#p3pv1'; - // other - this.target.graph.terms['related'] = 'http://www.w3.org/1999/xhtml/vocab#related'; - this.target.graph.terms['role'] = 'http://www.w3.org/1999/xhtml/vocab#role'; - this.target.graph.terms['transformation'] = 'http://www.w3.org/1999/xhtml/vocab#transformation'; + key: 'close', + value: function close() { + this.closed = true; + return this.closed; } }, { - key: 'setXMLContext', - value: function setXMLContext() { - this.setInitialContext(); - this.inXHTMLMode = false; - this.inHTMLMode = false; + key: 'shift', + value: function shift() { + return this.elements.shift(); } }, { - key: 'tokenize', - value: function tokenize(str) { - return this.trim(str).split(/\s+/); + key: 'substitute', + value: function substitute(bindings) { + var elementsCopy = this.elements.map(function (ea) { + ea.substitute(bindings); + }); + return new Collection(elementsCopy); } }, { - key: 'toRDFNodeObject', - value: function toRDFNodeObject(x) { - if (typeof x === 'undefined') return undefined; - if (typeof x === 'string') { - if (x.substring(0, 2) === '_:') { - if (typeof this.blankNodes[x.substring(2)] === 'undefined') { - this.blankNodes[x.substring(2)] = new BlankNode(x.substring(2)); - } - return this.blankNodes[x.substring(2)]; - } - return rdf.namedNode(x); - } - switch (x.type) { - case RDFaProcessor.objectURI: - if (x.value.substring(0, 2) === '_:') { - if (typeof this.blankNodes[x.value.substring(2)] === 'undefined') { - this.blankNodes[x.value.substring(2)] = new BlankNode(x.value.substring(2)); - } - return this.blankNodes[x.value.substring(2)]; - } - return rdf.namedNode(x.value); - case RDFaProcessor.PlainLiteralURI: - return new Literal(x.value, x.language || ''); - case RDFaProcessor.XMLLiteralURI: - case RDFaProcessor.HTMLLiteralURI: - var string = ''; - Object.keys(x.value).forEach(function (i) { - string += Util.domToString(x.value[i], this.htmlOptions); - }); - return new Literal(string, '', new NamedNode(x.type)); - default: - return new Literal(x.value, '', new NamedNode(x.type)); - } + key: 'toNT', + value: function toNT() { + return BlankNode.NTAnonymousNodePrefix + this.id; } }, { - key: 'trim', - value: function trim(str) { - return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); + key: 'toString', + value: function toString() { + return '(' + this.elements.join(' ') + ')'; } - }], [{ - key: 'parseRDFaDOM', - value: function parseRDFaDOM(dom, kb, base) { - var p = new RDFaProcessor(kb, { 'base': base }); - dom.baseURI = base; - p.process(dom); + }, { + key: 'unshift', + value: function unshift(element) { + return this.elements.unshift(element); } }]); - return RDFaProcessor; -}(); + return Collection; +}(Node); -RDFaProcessor.XMLLiteralURI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'; -RDFaProcessor.HTMLLiteralURI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#HTML'; -RDFaProcessor.PlainLiteralURI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#PlainLiteral'; -RDFaProcessor.objectURI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#object'; -RDFaProcessor.typeURI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; -RDFaProcessor.nameChar = '[-A-Z_a-z\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u10000-\uEFFFF.0-9\xB7\u0300-\u036F\u203F-\u2040]'; -RDFaProcessor.nameStartChar = '[A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u0131\u0134-\u013E\u0141-\u0148\u014A-\u017E\u0180-\u01C3\u01CD-\u01F0\u01F4-\u01F5\u01FA-\u0217\u0250-\u02A8\u02BB-\u02C1\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03D6\u03DA\u03DC\u03DE\u03E0\u03E2-\u03F3\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E-\u0481\u0490-\u04C4\u04C7-\u04C8\u04CB-\u04CC\u04D0-\u04EB\u04EE-\u04F5\u04F8-\u04F9\u0531-\u0556\u0559\u0561-\u0586\u05D0-\u05EA\u05F0-\u05F2\u0621-\u063A\u0641-\u064A\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D3\u06D5\u06E5-\u06E6\u0905-\u0939\u093D\u0958-\u0961\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8B\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AE0\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B36-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60-\u0D61\u0E01-\u0E2E\u0E30\u0E32-\u0E33\u0E40-\u0E45\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EAE\u0EB0\u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0F40-\u0F47\u0F49-\u0F69\u10A0-\u10C5\u10D0-\u10F6\u1100\u1102-\u1103\u1105-\u1107\u1109\u110B-\u110C\u110E-\u1112\u113C\u113E\u1140\u114C\u114E\u1150\u1154-\u1155\u1159\u115F-\u1161\u1163\u1165\u1167\u1169\u116D-\u116E\u1172-\u1173\u1175\u119E\u11A8\u11AB\u11AE-\u11AF\u11B7-\u11B8\u11BA\u11BC-\u11C2\u11EB\u11F0\u11F9\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A-\u212B\u212E\u2180-\u2182\u3041-\u3094\u30A1-\u30FA\u3105-\u312C\uAC00-\uD7A3\u4E00-\u9FA5\u3007\u3021-\u3029_]'; -RDFaProcessor.NCNAME = new RegExp('^' + RDFaProcessor.nameStartChar + RDFaProcessor.nameChar + '*$'); +Collection.termType = 'Collection'; +Collection.prototype.classOrder = ClassOrder['Collection']; +Collection.prototype.compareTerm = BlankNode.prototype.compareTerm; +Collection.prototype.isVar = 0; -/* -RDFaProcessor.prototype.resolveAndNormalize = function(base,href) { - var u = base.resolve(href) - var parsed = this.parseURI(u) - parsed.normalize() - return parsed.spec +module.exports = Collection; +},{"./blank-node":239,"./class-order":240,"./node":256}],242:[function(_dereq_,module,exports){ +'use strict'; + +module.exports.convertToJson = convertToJson; +module.exports.convertToNQuads = convertToNQuads; + +var asyncLib = _dereq_('async'); // @@ Goal: remove this dependency +var jsonld = _dereq_('jsonld'); +var N3 = _dereq_('n3'); // @@ Goal: remove this dependency + +function convertToJson(n3String, jsonCallback) { + var jsonString; + var n3Parser = N3.Parser(); + var n3Writer = N3.Writer({ + format: 'N-Quads' + }); + asyncLib.waterfall([function (callback) { + n3Parser.parse(n3String, callback); + }, function (triple, prefix, callback) { + if (triple !== null) { + n3Writer.addTriple(triple); + } + if (typeof callback === 'function') { + n3Writer.end(callback); + } + }, function (result, callback) { + try { + jsonld.fromRDF(result, { + format: 'application/nquads' + }, callback); + } catch (err) { + callback(err); + } + }, function (json, callback) { + jsonString = JSON.stringify(json); + jsonCallback(null, jsonString); + }], function (err, result) { + jsonCallback(err, jsonString); + }); } -*/ -RDFaProcessor.dateTimeTypes = [{ pattern: /-?P(?:[0-9]+Y)?(?:[0-9]+M)?(?:[0-9]+D)?(?:T(?:[0-9]+H)?(?:[0-9]+M)?(?:[0-9]+(?:\.[0-9]+)?S)?)?/, - type: 'http://www.w3.org/2001/XMLSchema#duration' }, { pattern: /-?(?:[1-9][0-9][0-9][0-9]|0[1-9][0-9][0-9]|00[1-9][0-9]|000[1-9])-[0-9][0-9]-[0-9][0-9]T(?:[0-1][0-9]|2[0-4]):[0-5][0-9]:[0-5][0-9](?:\.[0-9]+)?(?:Z|[+\-][0-9][0-9]:[0-9][0-9])?/, - type: 'http://www.w3.org/2001/XMLSchema#dateTime' }, { pattern: /-?(?:[1-9][0-9][0-9][0-9]|0[1-9][0-9][0-9]|00[1-9][0-9]|000[1-9])-[0-9][0-9]-[0-9][0-9](?:Z|[+\-][0-9][0-9]:[0-9][0-9])?/, - type: 'http://www.w3.org/2001/XMLSchema#date' }, { pattern: /(?:[0-1][0-9]|2[0-4]):[0-5][0-9]:[0-5][0-9](?:\.[0-9]+)?(?:Z|[+\-][0-9][0-9]:[0-9][0-9])?/, - type: 'http://www.w3.org/2001/XMLSchema#time' }, { pattern: /-?(?:[1-9][0-9][0-9][0-9]|0[1-9][0-9][0-9]|00[1-9][0-9]|000[1-9])-[0-9][0-9]/, - type: 'http://www.w3.org/2001/XMLSchema#gYearMonth' }, { pattern: /-?[1-9][0-9][0-9][0-9]|0[1-9][0-9][0-9]|00[1-9][0-9]|000[1-9]/, - type: 'http://www.w3.org/2001/XMLSchema#gYear' }]; +function convertToNQuads(n3String, nquadCallback) { + var nquadString; + var n3Parser = N3.Parser(); + var n3Writer = N3.Writer({ + format: 'N-Quads' + }); + asyncLib.waterfall([function (callback) { + n3Parser.parse(n3String, callback); + }, function (triple, prefix, callback) { + if (triple !== null) { + n3Writer.addTriple(triple); + } + if (typeof callback === 'function') { + n3Writer.end(callback); + } + }, function (result, callback) { + nquadString = result; + nquadCallback(null, nquadString); + }], function (err, result) { + nquadCallback(err, nquadString); + }); +} +},{"async":1,"jsonld":55,"n3":273}],243:[function(_dereq_,module,exports){ +'use strict'; -module.exports = RDFaProcessor; -},{"./blank-node":42,"./data-factory":46,"./literal":54,"./named-node":57,"./uri":72,"./util":73}],65:[function(_dereq_,module,exports){ +var _indexedFormula = _dereq_('./indexed-formula'); + +var _indexedFormula2 = _interopRequireDefault(_indexedFormula); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var BlankNode = _dereq_('./blank-node'); +var Collection = _dereq_('./collection'); +var DefaultGraph = _dereq_('./default-graph'); +var Fetcher = _dereq_('./fetcher'); + +var Literal = _dereq_('./literal'); +var NamedNode = _dereq_('./named-node'); +var Statement = _dereq_('./statement'); +var Variable = _dereq_('./variable'); + +function blankNode(value) { + return new BlankNode(value); +} +function collection(elements) { + return new Collection(elements); +} +function defaultGraph() { + return new DefaultGraph(); +} +function fetcher(store, timeout, async) { + return new Fetcher(store, timeout, async); +} +function graph() { + return new _indexedFormula2.default(); +} +function lit(val, lang, dt) { + return new Literal('' + val, lang, dt); +} +function literal(value, languageOrDatatype) { + if (typeof languageOrDatatype === 'string') { + if (languageOrDatatype.indexOf(':') === -1) { + return new Literal(value, languageOrDatatype); + } else { + return new Literal(value, null, namedNode(languageOrDatatype)); + } + } else { + return new Literal(value, null, languageOrDatatype); + } +} +function namedNode(value) { + return new NamedNode(value); +} +function quad(subject, predicate, object, graph) { + graph = graph || new DefaultGraph(); + return new Statement(subject, predicate, object, graph); +} +function st(subject, predicate, object, graph) { + return new Statement(subject, predicate, object, graph); +} +function triple(subject, predicate, object) { + return quad(subject, predicate, object); +} +function variable(name) { + return new Variable(name); +} + +// rdfjs spec factory methods +module.exports.blankNode = blankNode; +module.exports.defaultGraph = defaultGraph; +module.exports.graph = graph; +module.exports.literal = literal; +module.exports.namedNode = namedNode; +module.exports.quad = quad; +module.exports.triple = triple; +module.exports.variable = variable; + +// rdflib only +module.exports.collection = collection; +module.exports.fetcher = fetcher; +module.exports.lit = lit; +module.exports.st = st; +},{"./blank-node":239,"./collection":241,"./default-graph":244,"./fetcher":246,"./indexed-formula":249,"./literal":251,"./named-node":254,"./statement":266,"./variable":271}],244:[function(_dereq_,module,exports){ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var Node = _dereq_('./node'); + +var DefaultGraph = function (_Node) { + _inherits(DefaultGraph, _Node); + + function DefaultGraph() { + _classCallCheck(this, DefaultGraph); + + var _this = _possibleConstructorReturn(this, (DefaultGraph.__proto__ || Object.getPrototypeOf(DefaultGraph)).call(this)); + + _this.termType = 'DefaultGraph'; + _this.value = ''; + return _this; + } + + _createClass(DefaultGraph, [{ + key: 'toCanonical', + value: function toCanonical() { + return this.value; + } + }]); + + return DefaultGraph; +}(Node); + +module.exports = DefaultGraph; +},{"./node":256}],245:[function(_dereq_,module,exports){ 'use strict'; +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var Node = _dereq_('./node'); + +/** + * Singleton subclass of an empty Collection. + */ + +var Empty = function (_Node) { + _inherits(Empty, _Node); + + function Empty() { + _classCallCheck(this, Empty); + + var _this = _possibleConstructorReturn(this, (Empty.__proto__ || Object.getPrototypeOf(Empty)).call(this)); + + _this.termType = Empty.termType; + return _this; + } + + _createClass(Empty, [{ + key: 'toString', + value: function toString() { + return '()'; + } + }]); + + return Empty; +}(Node); + +Empty.termType = 'empty'; + +module.exports = Empty; +},{"./node":256}],246:[function(_dereq_,module,exports){ +'use strict'; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +/* global $SolidTestEnvironment */ /** - * @fileoverview - * RDF/XML PARSER - * - * Version 0.1 - * Parser believed to be in full positive RDF/XML parsing compliance - * with the possible exception of handling deprecated RDF attributes - * appropriately. Parser is believed to comply fully with other W3C - * and industry standards where appropriate (DOM, ECMAScript, &c.) * - * Author: David Sheets + * Project: rdflib.js * - * W3C® SOFTWARE NOTICE AND LICENSE - * http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 - * This work (and included software, documentation such as READMEs, or - * other related items) is being provided by the copyright holders under - * the following license. By obtaining, using and/or copying this work, - * you (the licensee) agree that you have read, understood, and will - * comply with the following terms and conditions. + * File: fetcher.js * - * Permission to copy, modify, and distribute this software and its - * documentation, with or without modification, for any purpose and - * without fee or royalty is hereby granted, provided that you include - * the following on ALL copies of the software and documentation or - * portions thereof, including modifications: + * Description: contains functions for requesting/fetching/retracting + * This implements quite a lot of the web architecture. + * A fetcher is bound to a specific knowledge base graph, into which + * it loads stuff and into which it writes its metadata + * @@ The metadata should be optionally a separate graph * - * 1. The full text of this NOTICE in a location viewable to users of - * the redistributed or derivative work. - * 2. Any pre-existing intellectual property disclaimers, notices, or terms and - * conditions. If none exist, the W3C Software Short Notice should be - * included (hypertext is preferred, text is permitted) within the body - * of any redistributed or derivative code. - * 3. Notice of any changes or modifications to the files, including the - * date changes were made. (We recommend you provide URIs to the location - * from which the code is derived.) + * - implements semantics of HTTP headers, Internet Content Types + * - selects parsers for rdf/xml, n3, rdfa, grddl * - * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT - * HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS - * FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR - * DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, - * TRADEMARKS OR OTHER RIGHTS. + * Dependencies: * - * COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL - * OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR - * DOCUMENTATION. + * needs: util.js uri.js term.js rdfparser.js rdfa.js n3parser.js + * identity.js sparql.js jsonparser.js * - * The name and trademarks of copyright holders may NOT be used in - * advertising or publicity pertaining to the software without specific, - * written prior permission. Title to copyright in this software and any - * associated documentation will at all times remain with copyright - * holders. + * Independent of jQuery */ + /** - * @class Class defining an RDFParser resource object tied to an RDFStore - * - * @author David Sheets - * @version 0.1 - * - * @constructor - * @param {RDFStore} store An RDFStore object + * Things to test: callbacks on request, refresh, retract + * loading from HTTP, HTTPS, FTP, FILE, others? + * To do: + * Firing up a mail client for mid: (message:) URLs */ -var uriUtil = _dereq_('./uri'); - -var RDFParser = function RDFParser(store) { - var RDFParser = {}; - - /** Standard namespaces that we know how to handle @final - * @member RDFParser - */ - RDFParser.ns = { 'RDF': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'RDFS': 'http://www.w3.org/2000/01/rdf-schema#' }; - - /** DOM Level 2 node type magic numbers @final - * @member RDFParser - */ - RDFParser.nodeType = { 'ELEMENT': 1, 'ATTRIBUTE': 2, 'TEXT': 3, - 'CDATA_SECTION': 4, 'ENTITY_REFERENCE': 5, - 'ENTITY': 6, 'PROCESSING_INSTRUCTION': 7, - 'COMMENT': 8, 'DOCUMENT': 9, 'DOCUMENT_TYPE': 10, - 'DOCUMENT_FRAGMENT': 11, 'NOTATION': 12 }; - - /** - * Frame class for namespace and base URI lookups - * Base lookups will always resolve because the parser knows - * the default base. - * - * @private - */ +var log = _dereq_('./log'); +var N3Parser = _dereq_('./n3parser'); +var NamedNode = _dereq_('./named-node'); +var Namespace = _dereq_('./namespace'); +var rdfParse = _dereq_('./parse'); +var parseRDFaDOM = _dereq_('./rdfaparser').parseRDFaDOM; +var RDFParser = _dereq_('./rdfxmlparser'); +var Uri = _dereq_('./uri'); +var Util = _dereq_('./util'); +var serialize = _dereq_('./serialize'); - this.frameFactory = function (parser, parent, element) { - return { 'NODE': 1, 'ARC': 2, 'parent': parent, 'parser': parser, 'store': parser.store, 'element': element, - 'lastChild': 0, 'base': null, 'lang': null, 'node': null, 'nodeType': null, 'listIndex': 1, 'rdfid': null, 'datatype': null, 'collection': false, /** Terminate the frame and notify the store that we're done */ - 'terminateFrame': function terminateFrame() { - if (this.collection) { - this.node.close(); - } - }, /** Add a symbol of a certain type to the this frame */'addSymbol': function addSymbol(type, uri) { - uri = uriUtil.join(uri, this.base); - this.node = this.store.sym(uri); +var Parsable = { + 'text/n3': true, + 'text/turtle': true, + 'application/rdf+xml': true, + 'application/xhtml+xml': true, + 'text/html': true, + 'application/ld+json': true +}; - this.nodeType = type; - }, /** Load any constructed triples into the store */'loadTriple': function loadTriple() { - if (this.parent.parent.collection) { - this.parent.parent.node.append(this.node); - } else { - this.store.add(this.parent.parent.node, this.parent.node, this.node, this.parser.why); - } - if (this.parent.rdfid != null) { - // reify - var triple = this.store.sym(uriUtil.join('#' + this.parent.rdfid, this.base)); - this.store.add(triple, this.store.sym(RDFParser.ns.RDF + 'type'), this.store.sym(RDFParser.ns.RDF + 'Statement'), this.parser.why); - this.store.add(triple, this.store.sym(RDFParser.ns.RDF + 'subject'), this.parent.parent.node, this.parser.why); - this.store.add(triple, this.store.sym(RDFParser.ns.RDF + 'predicate'), this.parent.node, this.parser.why); +var Fetcher = function Fetcher(store, timeout, async) { + this.store = store; + this.thisURI = 'http://dig.csail.mit.edu/2005/ajar/ajaw/rdf/sources.js' + '#SourceFetcher'; // -- Kenny + this.timeout = timeout || 30000; + this.async = async != null ? async : true; + this.appNode = this.store.bnode(); // Denoting this session + this.store.fetcher = this; // Bi-linked + this.requested = {}; + // this.requested[uri] states: + // undefined no record of web access or records reset + // true has been requested, XHR in progress + // 'done' received, Ok + // 403 HTTP status unauthorized + // 404 Ressource does not exist. Can be created etc. + // 'redirected' In attempt to counter CORS problems retried. + // other strings mean various other erros, such as parse errros. + // + this.redirectedTo = {}; // Wehn 'redireced' + this.fetchCallbacks = {}; // fetchCallbacks[uri].push(callback) - this.store.add(triple, this.store.sym(RDFParser.ns.RDF + 'object'), this.node, this.parser.why); - } - }, /** Check if it's OK to load a triple */'isTripleToLoad': function isTripleToLoad() { - return this.parent != null && this.parent.parent != null && this.nodeType === this.NODE && this.parent.nodeType === this.ARC && this.parent.parent.nodeType === this.NODE; - }, /** Add a symbolic node to this frame */'addNode': function addNode(uri) { - this.addSymbol(this.NODE, uri); - if (this.isTripleToLoad()) { - this.loadTriple(); - } - }, /** Add a collection node to this frame */'addCollection': function addCollection() { - this.nodeType = this.NODE; - this.node = this.store.collection(); - this.collection = true; - if (this.isTripleToLoad()) { - this.loadTriple(); - } - }, /** Add a collection arc to this frame */'addCollectionArc': function addCollectionArc() { - this.nodeType = this.ARC; - }, /** Add a bnode to this frame */'addBNode': function addBNode(id) { - if (id != null) { - if (this.parser.bnodes[id] != null) { - this.node = this.parser.bnodes[id]; - } else { - this.node = this.parser.bnodes[id] = this.store.bnode(); - } - } else { - this.node = this.store.bnode(); - } - this.nodeType = this.NODE; - if (this.isTripleToLoad()) { - this.loadTriple(); - } - }, /** Add an arc or property to this frame */'addArc': function addArc(uri) { - if (uri === RDFParser.ns.RDF + 'li') { - uri = RDFParser.ns.RDF + '_' + this.parent.listIndex; - this.parent.listIndex++; - } + this.nonexistant = {}; // keep track of explict 404s -> we can overwrite etc + this.lookedUp = {}; + this.handlers = []; + this.mediatypes = {}; + var sf = this; + var kb = this.store; + var ns = {}; // Convenience namespaces needed in this module: + // These are delibertely not exported as the user application should + // make its own list and not rely on the prefixes used here, + // and not be tempted to add to them, and them clash with those of another + // application. + ns.link = Namespace('http://www.w3.org/2007/ont/link#'); + ns.http = Namespace('http://www.w3.org/2007/ont/http#'); + ns.httph = Namespace('http://www.w3.org/2007/ont/httph#'); + ns.rdf = Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#'); + ns.rdfs = Namespace('http://www.w3.org/2000/01/rdf-schema#'); + ns.dc = Namespace('http://purl.org/dc/elements/1.1/'); - this.addSymbol(this.ARC, uri); - }, /** Add a literal to this frame */'addLiteral': function addLiteral(value) { - if (this.parent.datatype) { - this.node = this.store.literal(value, '', this.store.sym(this.parent.datatype)); - } else { - this.node = this.store.literal(value, this.lang); - } - this.nodeType = this.NODE; - if (this.isTripleToLoad()) { - this.loadTriple(); - } - } - }; + sf.mediatypes['image/*'] = { + 'q': 0.9 }; - // from the OpenLayers source .. needed to get around IE problems. - this.getAttributeNodeNS = function (node, uri, name) { - var attributeNode = null; - if (node.getAttributeNodeNS) { - attributeNode = node.getAttributeNodeNS(uri, name); - } else { - var attributes = node.attributes; - var potentialNode, fullName; - for (var i = 0; i < attributes.length; ++i) { - potentialNode = attributes[i]; - if (potentialNode.namespaceURI === uri) { - fullName = potentialNode.prefix ? potentialNode.prefix + ':' + name : name; - if (fullName === potentialNode.nodeName) { - attributeNode = potentialNode; - break; - } - } - } - } - return attributeNode; + sf.mediatypes['*/*'] = { // Must allow access to random content + 'q': 0.1 }; - /** Our triple store reference @private */ - - this.store = store; /** Our identified blank nodes @private */ - this.bnodes = {}; /** A context for context-aware stores @private */ - this.why = null; /** Reification flag */ - this.reify = false; - - /** - * Build our initial scope frame and parse the DOM into triples - * @param {DOMTree} document The DOM to parse - * @param {String} base The base URL to use - * @param {Object} why The context to which this resource belongs - */ - - this.parse = function (document, base, why) { - var children = document.childNodes; // clean up for the next run - this.cleanParser(); // figure out the root element - var root; - if (document.nodeType === RDFParser.nodeType.DOCUMENT) { - for (var c = 0; c < children.length; c++) { - if (children[c].nodeType === RDFParser.nodeType.ELEMENT) { - root = children[c]; - break; - } - } - } else if (document.nodeType === RDFParser.nodeType.ELEMENT) { - root = document; + Fetcher.crossSiteProxy = function (uri) { + if (Fetcher.crossSiteProxyTemplate) { + return Fetcher.crossSiteProxyTemplate.replace('{uri}', encodeURIComponent(uri)); } else { - throw new Error("RDFParser: can't find root in " + base + '. Halting. '); - // return false + return undefined; } - this.why = why; // our topmost frame - var f = this.frameFactory(this); - this.base = base; - f.base = base; - f.lang = null; // was '' but can't have langs like that 2015 (!) - this.parseDOM(this.buildFrame(f, root)); - return true; }; - this.parseDOM = function (frame) { - // a DOM utility function used in parsing - var rdfid; - var elementURI = function (el) { - var result = ''; - if (el.namespaceURI == null) { - throw new Error('RDF/XML syntax error: No namespace for ' + el.localName + ' in ' + this.base); - } - if (el.namespaceURI) { - result = result + el.namespaceURI; - } - if (el.localName) { - result = result + el.localName; - } else if (el.nodeName) { - if (el.nodeName.indexOf(':') >= 0) result = result + el.nodeName.split(':')[1];else result = result + el.nodeName; - } - return result; - }.bind(this); - var dig = true; // if we'll dig down in the tree on the next iter - while (frame.parent) { - var dom = frame.element; - var attrs = dom.attributes; - if (dom.nodeType === RDFParser.nodeType.TEXT || dom.nodeType === RDFParser.nodeType.CDATA_SECTION) { - // we have a literal - if (frame.parent.nodeType === frame.NODE) { - // must have had attributes, store as rdf:value - frame.addArc(RDFParser.ns.RDF + 'value'); - frame = this.buildFrame(frame); - } - frame.addLiteral(dom.nodeValue); - } else if (elementURI(dom) !== RDFParser.ns.RDF + 'RDF') { - // not root - if (frame.parent && frame.parent.collection) { - // we're a collection element - frame.addCollectionArc(); - frame = this.buildFrame(frame, frame.element); - frame.parent.element = null; - } - if (!frame.parent || !frame.parent.nodeType || frame.parent.nodeType === frame.ARC) { - // we need a node - var about = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'about'); - rdfid = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'ID'); - if (about && rdfid) { - throw new Error('RDFParser: ' + dom.nodeName + ' has both rdf:id and rdf:about.' + ' Halting. Only one of these' + ' properties may be specified on a' + ' node.'); - } - if (!about && rdfid) { - frame.addNode('#' + rdfid.nodeValue); - dom.removeAttributeNode(rdfid); - } else if (about == null && rdfid == null) { - var bnid = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'nodeID'); - if (bnid) { - frame.addBNode(bnid.nodeValue); - dom.removeAttributeNode(bnid); - } else { - frame.addBNode(); - } - } else { - frame.addNode(about.nodeValue); - dom.removeAttributeNode(about); - } - // Typed nodes - var rdftype = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'type'); - if (RDFParser.ns.RDF + 'Description' !== elementURI(dom)) { - rdftype = { 'nodeValue': elementURI(dom) }; - } - if (rdftype != null) { - this.store.add(frame.node, this.store.sym(RDFParser.ns.RDF + 'type'), this.store.sym(uriUtil.join(rdftype.nodeValue, frame.base)), this.why); - if (rdftype.nodeName) { - dom.removeAttributeNode(rdftype); - } - } - // Property Attributes - for (var x = attrs.length - 1; x >= 0; x--) { - this.store.add(frame.node, this.store.sym(elementURI(attrs[x])), this.store.literal(attrs[x].nodeValue, frame.lang), this.why); - } - } else { - // we should add an arc (or implicit bnode+arc) - frame.addArc(elementURI(dom)); // save the arc's rdf:ID if it has one - if (this.reify) { - rdfid = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'ID'); - if (rdfid) { - frame.rdfid = rdfid.nodeValue; - dom.removeAttributeNode(rdfid); - } - } - var parsetype = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'parseType'); - var datatype = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'datatype'); - if (datatype) { - frame.datatype = datatype.nodeValue; - dom.removeAttributeNode(datatype); - } - if (parsetype) { - var nv = parsetype.nodeValue; - if (nv === 'Literal') { - frame.datatype = RDFParser.ns.RDF + 'XMLLiteral'; // (this.buildFrame(frame)).addLiteral(dom) - // should work but doesn't - frame = this.buildFrame(frame); - frame.addLiteral(dom); - dig = false; - } else if (nv === 'Resource') { - frame = this.buildFrame(frame, frame.element); - frame.parent.element = null; - frame.addBNode(); - } else if (nv === 'Collection') { - frame = this.buildFrame(frame, frame.element); - frame.parent.element = null; - frame.addCollection(); - } - dom.removeAttributeNode(parsetype); - } - if (attrs.length !== 0) { - var resource = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'resource'); - var bnid2 = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'nodeID'); - frame = this.buildFrame(frame); - if (resource) { - frame.addNode(resource.nodeValue); - dom.removeAttributeNode(resource); - } else { - if (bnid2) { - frame.addBNode(bnid2.nodeValue); - dom.removeAttributeNode(bnid2); - } else { - frame.addBNode(); - } - } - for (var x1 = attrs.length - 1; x1 >= 0; x1--) { - var f = this.buildFrame(frame); - f.addArc(elementURI(attrs[x1])); - if (elementURI(attrs[x1]) === RDFParser.ns.RDF + 'type') { - this.buildFrame(f).addNode(attrs[x1].nodeValue); - } else { - this.buildFrame(f).addLiteral(attrs[x1].nodeValue); - } - } - } else if (dom.childNodes.length === 0) { - this.buildFrame(frame).addLiteral(''); - } + Fetcher.RDFXMLHandler = function (args) { + if (args) { + this.dom = args[0]; + } + this.handlerFactory = function (xhr) { + xhr.handle = function (cb) { + // sf.addStatus(xhr.req, 'parsing soon as RDF/XML...') + var kb = sf.store; + if (!this.dom) this.dom = Util.parseXML(xhr.responseText); + var root = this.dom.documentElement; + if (root.nodeName === 'parsererror') { + // @@ Mozilla only See issue/issue110 + sf.failFetch(xhr, 'Badly formed XML in ' + xhr.resource.uri); // have to fail the request + throw new Error('Badly formed XML in ' + xhr.resource.uri); // @@ Add details } - } // rdf:RDF - // dig dug - dom = frame.element; - while (frame.parent) { - var pframe = frame; - while (dom == null) { - frame = frame.parent; - dom = frame.element; + var parser = new RDFParser(kb); + try { + parser.parse(this.dom, xhr.original.uri, xhr.original); + } catch (e) { + sf.addStatus(xhr.req, 'Syntax error parsing RDF/XML! ' + e); + console.log('Syntax error parsing RDF/XML! ' + e); } - var candidate = dom.childNodes && dom.childNodes[frame.lastChild]; - if (!candidate || !dig) { - frame.terminateFrame(); - if (!(frame = frame.parent)) { - break; - } // done - dom = frame.element; - dig = true; - } else if (candidate.nodeType !== RDFParser.nodeType.ELEMENT && candidate.nodeType !== RDFParser.nodeType.TEXT && candidate.nodeType !== RDFParser.nodeType.CDATA_SECTION || (candidate.nodeType === RDFParser.nodeType.TEXT || candidate.nodeType === RDFParser.nodeType.CDATA_SECTION) && dom.childNodes.length !== 1) { - frame.lastChild++; - } else { - // not a leaf - frame.lastChild++; - frame = this.buildFrame(pframe, dom.childNodes[frame.lastChild - 1]); - break; + if (!xhr.options.noMeta) { + kb.add(xhr.original, ns.rdf('type'), ns.link('RDFDocument'), sf.appNode); } - } - } // while + cb(); + }; + }; }; - - /** - * Cleans out state from a previous parse run - * @private - */ - this.cleanParser = function () { - this.bnodes = {}; - this.why = null; + Fetcher.RDFXMLHandler.toString = function () { + return 'RDFXMLHandler'; + }; + Fetcher.RDFXMLHandler.register = function (sf) { + sf.mediatypes['application/rdf+xml'] = { + 'q': 0.9 + }; }; + Fetcher.RDFXMLHandler.pattern = new RegExp('application/rdf\\+xml'); - /** - * Builds scope frame - * @private - */ - this.buildFrame = function (parent, element) { - var frame = this.frameFactory(this, parent, element); - if (parent) { - frame.base = parent.base; - frame.lang = parent.lang; - } - if (!element || element.nodeType === RDFParser.nodeType.TEXT || element.nodeType === RDFParser.nodeType.CDATA_SECTION) { - return frame; - } - var attrs = element.attributes; - var base = element.getAttributeNode('xml:base'); - if (base != null) { - frame.base = base.nodeValue; - element.removeAttribute('xml:base'); - } - var lang = element.getAttributeNode('xml:lang'); - if (lang != null) { - frame.lang = lang.nodeValue; - element.removeAttribute('xml:lang'); + // This would much better use on-board XSLT engine. @@ + /* deprocated 2016-02-17 timbl + Fetcher.doGRDDL = function(kb, doc, xslturi, xmluri) { + sf.requestURI('http://www.w3.org/2005/08/' + 'online_xslt/xslt?' + 'xslfile=' + escape(xslturi) + '&xmlfile=' + escape(xmluri), doc) + } + */ + Fetcher.XHTMLHandler = function (args) { + if (args) { + this.dom = args[0]; } - // remove all extraneous xml and xmlns attributes - for (var x = attrs.length - 1; x >= 0; x--) { - if (attrs[x].nodeName.substr(0, 3) === 'xml') { - if (attrs[x].name.slice(0, 6) === 'xmlns:') { - var uri = attrs[x].nodeValue; // alert('base for namespac attr:'+this.base) - if (this.base) uri = uriUtil.join(uri, this.base); - this.store.setPrefixForURI(attrs[x].name.slice(6), uri); + this.handlerFactory = function (xhr) { + xhr.handle = function (cb) { + var relation, reverse; + if (!this.dom) { + this.dom = Util.parseXML(xhr.responseText); } - // alert('rdfparser: xml atribute: '+attrs[x].name) //@@ - element.removeAttributeNode(attrs[x]); - } - } - return frame; - }; -}; + var kb = sf.store; -module.exports = RDFParser; -},{"./uri":72}],66:[function(_dereq_,module,exports){ -'use strict'; + // dc:title + var title = this.dom.getElementsByTagName('title'); + if (title.length > 0) { + kb.add(xhr.resource, ns.dc('title'), kb.literal(title[0].textContent), xhr.resource); + // log.info("Inferring title of " + xhr.resource) + } -module.exports = serialize; + // link rel + var links = this.dom.getElementsByTagName('link'); + for (var x = links.length - 1; x >= 0; x--) { + // @@ rev + relation = links[x].getAttribute('rel'); + reverse = false; + if (!relation) { + relation = links[x].getAttribute('rev'); + reverse = true; + } + if (relation) { + sf.linkData(xhr, relation, links[x].getAttribute('href'), xhr.resource, reverse); + } + } -var convert = _dereq_('./convert'); -var Serializer = _dereq_('./serializer'); + // Data Islands -/** - * Serialize to the appropriate format - * @@ Currently NQuads and JSON/LD are deal with extrelemently inefficiently - * through mutiple conversions. - */ -function serialize(target, kb, base, contentType, callback, options) { - base = base || target.uri; - options = options || {}; - contentType = contentType || 'text/turtle'; // text/n3 if complex? - var documentString = null; - try { - var sz = Serializer(kb); - if (options.flags) sz.setFlags(options.flags); - var newSts = kb.statementsMatching(undefined, undefined, undefined, target); - var n3String; - sz.suggestNamespaces(kb.namespaces); - sz.setBase(base); - switch (contentType) { - case 'application/rdf+xml': - documentString = sz.statementsToXML(newSts); - return executeCallback(null, documentString); - case 'text/n3': - case 'application/n3': - // Legacy - documentString = sz.statementsToN3(newSts); - return executeCallback(null, documentString); - case 'text/turtle': - case 'application/x-turtle': - // Legacy - sz.setFlags('si'); // Suppress = for sameAs and => for implies - documentString = sz.statementsToN3(newSts); - return executeCallback(null, documentString); - case 'application/n-triples': - sz.setFlags('deinprstux'); // Suppress nice parts of N3 to make ntriples - documentString = sz.statementsToNTriples(newSts); - return executeCallback(null, documentString); - case 'application/ld+json': - sz.setFlags('deinprstux'); // Use adapters to connect to incmpatible parser - n3String = sz.statementsToNTriples(newSts); - // n3String = sz.statementsToN3(newSts) - convert.convertToJson(n3String, callback); - break; - case 'application/n-quads': - case 'application/nquads': - // @@@ just outpout the quads? Does not work for collections - sz.setFlags('deinprstux q'); // Suppress nice parts of N3 to make ntriples - documentString = sz.statementsToNTriples(newSts); // q in flag means actually quads - return executeCallback(null, documentString); - // n3String = sz.statementsToN3(newSts) - // documentString = convert.convertToNQuads(n3String, callback) - break; - default: - throw new Error('Serialize: Content-type ' + contentType + ' not supported for data write.'); - } - } catch (err) { - if (callback) { - return callback(err); - } - throw err; // Don't hide problems from caller in sync mode - } + var scripts = this.dom.getElementsByTagName('script'); + for (var i = 0; i < scripts.length; i++) { + var contentType = scripts[i].getAttribute('type'); + if (Parsable[contentType]) { + rdfParse(scripts[i].textContent, kb, xhr.original.uri, contentType); + } + } - function executeCallback(err, result) { - if (callback) { - callback(err, result); - return; - } else { - return result; - } - } -} -},{"./convert":45,"./serializer":67}],67:[function(_dereq_,module,exports){ -'use strict'; + if (!xhr.options.noMeta) { + kb.add(xhr.resource, ns.rdf('type'), ns.link('WebPage'), sf.appNode); + } -/* Serialization of RDF Graphs -** -** Tim Berners-Lee 2006 -** This is was http://dig.csail.mit.edu/2005/ajar/ajaw/js/rdf/serialize.js -** This is or was https://github.com/linkeddata/rdflib.js/blob/master/src/serializer.js -** Licence: MIT -*/ -var NamedNode = _dereq_('./named-node'); -var BlankNode = _dereq_('./blank-node'); -var Uri = _dereq_('./uri'); -var Util = _dereq_('./util'); -var XSD = _dereq_('./xsd'); + if (!xhr.options.noRDFa && parseRDFaDOM) { + // enable by default + try { + parseRDFaDOM(this.dom, kb, xhr.original.uri); + } catch (e) { + var msg = 'Error trying to parse ' + xhr.resource + ' as RDFa:\n' + e + ':\n' + e.stack; + // dump(msg+"\n") + sf.failFetch(xhr, msg); + return; + } + } + cb(); // Fire done callbacks + }; + }; + }; + Fetcher.XHTMLHandler.toString = function () { + return 'XHTMLHandler'; + }; + Fetcher.XHTMLHandler.register = function (sf) { + sf.mediatypes['application/xhtml+xml'] = {}; + }; + Fetcher.XHTMLHandler.pattern = new RegExp('application/xhtml'); -var Serializer = function () { - var __Serializer = function __Serializer(store) { - this.flags = ''; - this.base = null; + Fetcher.XMLHandler = function () { + this.handlerFactory = function (xhr) { + xhr.handle = function (cb) { + var dom = Util.parseXML(xhr.responseText); - this.prefixes = []; // suggested prefixes - this.namespaces = []; // complementary indexes + // XML Semantics defined by root element namespace + // figure out the root element + for (var c = 0; c < dom.childNodes.length; c++) { + // is this node an element? + if (dom.childNodes[c].nodeType === 1) { + // We've found the first element, it's the root + var ns = dom.childNodes[c].namespaceURI; - this.suggestPrefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'); // XML code assumes this! - this.suggestPrefix('xml', 'reserved:reservedForFutureUse'); // XML reserves xml: in the spec. + // Is it RDF/XML? + if (ns && ns === ns['rdf']) { + sf.addStatus(xhr.req, 'Has XML root element in the RDF namespace, so assume RDF/XML.'); + sf.switchHandler('RDFXMLHandler', xhr, cb, [dom]); + return; + } + // it isn't RDF/XML or we can't tell + // Are there any GRDDL transforms for this namespace? + // @@ assumes ns documents have already been loaded + /* + var xforms = kb.each(kb.sym(ns), kb.sym("http://www.w3.org/2003/g/data-view#namespaceTransformation")) + for (var i = 0; i < xforms.length; i++) { + var xform = xforms[i] + // log.info(xhr.resource.uri + " namespace " + ns + " has GRDDL ns transform" + xform.uri) + Fetcher.doGRDDL(kb, xhr.resource, xform.uri, xhr.resource.uri) + } + */ + break; + } + } - this.namespacesUsed = []; // Count actually used and so needed in @prefixes - this.keywords = ['a']; // The only one we generate at the moment - this.prefixchars = 'abcdefghijklmnopqustuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - this.incoming = null; // Array not calculated yet - this.formulas = []; // remebering original formulae from hashes - this.store = store; - }; + // Or it could be XHTML? + // Maybe it has an XHTML DOCTYPE? + if (dom.doctype) { + // log.info("We found a DOCTYPE in " + xhr.resource) + if (dom.doctype.name === 'html' && dom.doctype.publicId.match(/^-\/\/W3C\/\/DTD XHTML/) && dom.doctype.systemId.match(/http:\/\/www.w3.org\/TR\/xhtml/)) { + sf.addStatus(xhr.req, 'Has XHTML DOCTYPE. Switching to XHTML Handler.\n'); + sf.switchHandler('XHTMLHandler', xhr, cb); + return; + } + } - __Serializer.prototype.setBase = function (base) { - this.base = base;return this; + // Or what about an XHTML namespace? + var html = dom.getElementsByTagName('html')[0]; + if (html) { + var xmlns = html.getAttribute('xmlns'); + if (xmlns && xmlns.match(/^http:\/\/www.w3.org\/1999\/xhtml/)) { + sf.addStatus(xhr.req, 'Has a default namespace for ' + 'XHTML. Switching to XHTMLHandler.\n'); + sf.switchHandler('XHTMLHandler', xhr, cb); + return; + } + } + + // At this point we should check the namespace document (cache it!) and + // look for a GRDDL transform + // @@ Get namespace document , parse it, look for grddl:namespaceTransform ?y + // Apply ?y to dom + // We give up. What dialect is this? + sf.failFetch(xhr, 'Unsupported dialect of XML: not RDF or XHTML namespace, etc.\n' + xhr.responseText.slice(0, 80)); + }; + }; }; - __Serializer.prototype.setFlags = function (flags) { - this.flags = flags || '';return this; + Fetcher.XMLHandler.toString = function () { + return 'XMLHandler'; + }; + Fetcher.XMLHandler.register = function (sf) { + sf.mediatypes['text/xml'] = { + 'q': 0.5 + }; + sf.mediatypes['application/xml'] = { + 'q': 0.5 + }; }; + Fetcher.XMLHandler.pattern = new RegExp('(text|application)/(.*)xml'); - __Serializer.prototype.toStr = function (x) { - var s = x.toNT(); - if (x.termType === 'Graph') { - this.formulas[s] = x; // remember as reverse does not work - } - return s; + Fetcher.HTMLHandler = function () { + this.handlerFactory = function (xhr) { + xhr.handle = function (cb) { + var rt = xhr.responseText; + // We only handle XHTML so we have to figure out if this is XML + // log.info("Sniffing HTML " + xhr.resource + " for XHTML.") + + if (rt.match(/\s*<\?xml\s+version\s*=[^<>]+\?>/)) { + sf.addStatus(xhr.req, "Has an XML declaration. We'll assume " + "it's XHTML as the content-type was text/html.\n"); + sf.switchHandler('XHTMLHandler', xhr, cb); + return; + } + + // DOCTYPE + // There is probably a smarter way to do this + if (rt.match(/.*/)) { + sf.addStatus(xhr.req, 'Has XHTML DOCTYPE. Switching to XHTMLHandler.\n'); + sf.switchHandler('XHTMLHandler', xhr, cb); + return; + } + + // xmlns + if (rt.match(/[^(/)) { + sf.addStatus(xhr.req, 'Has default namespace for XHTML, so switching to XHTMLHandler.\n'); + sf.switchHandler('XHTMLHandler', xhr, cb); + return; + } + + // dc:title //no need to escape '/' here + var titleMatch = new RegExp('([\\s\\S]+?)', 'im').exec(rt); + if (titleMatch) { + var kb = sf.store; + kb.add(xhr.resource, ns.dc('title'), kb.literal(titleMatch[1]), xhr.resource); // think about xml:lang later + kb.add(xhr.resource, ns.rdf('type'), ns.link('WebPage'), sf.appNode); + cb(); // doneFetch, not failed + return; + } + sf.addStatus(xhr.req, 'non-XML HTML document, not parsed for data.'); + sf.doneFetch(xhr); + // sf.failFetch(xhr, "Sorry, can't yet parse non-XML HTML") + }; + }; }; - __Serializer.prototype.fromStr = function (s) { - if (s[0] === '{') { - var x = this.formulas[s]; - if (!x) console.log('No formula object for ' + s); - return x; - } - return this.store.fromNT(s); + Fetcher.HTMLHandler.toString = function () { + return 'HTMLHandler'; }; - /* Accumulate Namespaces - ** - ** These are only hints. If two overlap, only one gets used - ** There is therefore no guarantee in general. - */ - __Serializer.prototype.suggestPrefix = function (prefix, uri) { - if (prefix.slice(0, 7) === 'default') return; // Try to weed these out - if (prefix.slice(0, 2) === 'ns') return; // From others inferior algos - if (!prefix || !uri) return; // empty strings not suitable - if (prefix in this.namespaces || uri in this.prefixes) return; // already used - this.prefixes[uri] = prefix; - this.namespaces[prefix] = uri; + Fetcher.HTMLHandler.register = function (sf) { + sf.mediatypes['text/html'] = { + 'q': 0.9 + }; }; + Fetcher.HTMLHandler.pattern = new RegExp('text/html'); - // Takes a namespace -> prefix map - __Serializer.prototype.suggestNamespaces = function (namespaces) { - for (var px in namespaces) { - this.suggestPrefix(px, namespaces[px]); - } - return this; - }; + Fetcher.TextHandler = function () { + this.handlerFactory = function (xhr) { + xhr.handle = function (cb) { + // We only speak dialects of XML right now. Is this XML? + var rt = xhr.responseText; - __Serializer.prototype.checkIntegrity = function () { - var p, ns; - for (p in this.namespaces) { - if (this.prefixes[this.namespaces[p]] !== p) { - throw new Error('Serializer integity error 1: ' + p + ', ' + this.namespaces[p] + ', ' + this.prefixes[this.namespaces[p]] + '!'); - } - } - for (ns in this.prefixes) { - if (this.namespaces[this.prefixes[ns]] !== ns) { - throw new Error('Serializer integity error 2: ' + ns + ', ' + this.prefixs[ns] + ', ' + this.namespaces[this.prefixes[ns]] + '!'); - } - } - }; + // Look for an XML declaration + if (rt.match(/\s*<\?xml\s+version\s*=[^<>]+\?>/)) { + sf.addStatus(xhr.req, 'Warning: ' + xhr.resource + " has an XML declaration. We'll assume " + "it's XML but its content-type wasn't XML.\n"); + sf.switchHandler('XMLHandler', xhr, cb); + return; + } - // Make up an unused prefix for a random namespace - __Serializer.prototype.makeUpPrefix = function (uri) { - var p = uri; - function canUseMethod(pp) { - if (!__Serializer.prototype.validPrefix.test(pp)) return false; // bad format - if (pp === 'ns') return false; // boring - if (pp in this.namespaces) return false; // already used - this.prefixes[uri] = pp; - this.namespaces[pp] = uri; - return pp; - } - var canUse = canUseMethod.bind(this); + // Look for an XML declaration + if (rt.slice(0, 500).match(/xmlns:/)) { + sf.addStatus(xhr.req, "May have an XML namespace. We'll assume " + "it's XML but its content-type wasn't XML.\n"); + sf.switchHandler('XMLHandler', xhr, cb); + return; + } - if ('#/'.indexOf(p[p.length - 1]) >= 0) p = p.slice(0, -1); - var slash = p.lastIndexOf('/'); - if (slash >= 0) p = p.slice(slash + 1); - var i = 0; - while (i < p.length) { - if (this.prefixchars.indexOf(p[i])) { - i++; - } else { - break; - } - } - p = p.slice(0, i); + // We give up finding semantics - this is not an error, just no data + sf.addStatus(xhr.req, 'Plain text document, no known RDF semantics.'); + sf.doneFetch(xhr); + // sf.failFetch(xhr, "unparseable - text/plain not visibly XML") + // dump(xhr.resource + " unparseable - text/plain not visibly XML, starts:\n" + rt.slice(0, 500)+"\n") + }; + }; + }; - if (p.length < 6 && canUse(p)) return p; // exact is best - if (canUse(p.slice(0, 3))) return p.slice(0, 3); - if (canUse(p.slice(0, 2))) return p.slice(0, 2); - if (canUse(p.slice(0, 4))) return p.slice(0, 4); - if (canUse(p.slice(0, 1))) return p.slice(0, 1); - if (canUse(p.slice(0, 5))) return p.slice(0, 5); - if (!__Serializer.prototype.validPrefix.test(p)) { - p = 'n'; // Otherwise the loop below may never termimnate - } - for (var j = 0;; j++) { - if (canUse(p.slice(0, 3) + j)) return p.slice(0, 3) + j; - } + Fetcher.TextHandler.toString = function () { + return 'TextHandler'; + }; + Fetcher.TextHandler.register = function (sf) { + sf.mediatypes['text/plain'] = { + 'q': 0.5 + }; }; + Fetcher.TextHandler.pattern = new RegExp('text/plain'); - __Serializer.prototype.rootSubjects = function (sts) { - var incoming = {}; - var subjects = {}; - var allBnodes = {}; + Fetcher.N3Handler = function () { + this.handlerFactory = function (xhr) { + xhr.handle = function (cb) { + // Parse the text of this non-XML file - /* This scan is to find out which nodes will have to be the roots of trees - ** in the serialized form. This will be any symbols, and any bnodes - ** which hve more or less than one incoming arc, and any bnodes which have - ** one incoming arc but it is an uninterrupted loop of such nodes back to itself. - ** This should be kept linear time with repect to the number of statements. - ** Note it does not use any indexing of the store. - */ - for (var i = 0; i < sts.length; i++) { - var st = sts[i]; - var checkMentions = function checkMentions(x) { - if (!incoming.hasOwnProperty(x)) incoming[x] = []; - incoming[x].push(st.subject); // List of things which will cause this to be printed - }; - var st2 = [st.subject, st.predicate, st.object]; - st2.map(function (y) { - if (y.termType === 'BlankNode') { - allBnodes[y.toNT()] = true; - } else if (y.termType === 'Collection') { - y.elements.forEach(function (z) { - checkMentions(z); // bnodes in collections important - }); + // console.log('web.js: Parsing as N3 ' + xhr.resource.uri + ' base: ' + xhr.original.uri) // @@@@ comment me out + // sf.addStatus(xhr.req, "N3 not parsed yet...") + var p = N3Parser(kb, kb, xhr.original.uri, xhr.original.uri, null, null, '', null); + // p.loadBuf(xhr.responseText) + try { + p.loadBuf(xhr.responseText); + } catch (e) { + var msg = 'Error trying to parse ' + xhr.resource + ' as Notation3:\n' + e + ':\n' + e.stack; + // dump(msg+"\n") + sf.failFetch(xhr, msg); + return; } - }); - checkMentions(sts[i].object); - var ss = subjects[this.toStr(st.subject)]; // Statements with this as subject - if (!ss) ss = []; - ss.push(st); - subjects[this.toStr(st.subject)] = ss; // Make hash. @@ too slow for formula? - } - - var roots = []; - for (var xNT in subjects) { - if (!subjects.hasOwnProperty(xNT)) continue; - var y = this.fromStr(xNT); - if (y.termType !== 'BlankNode' || !incoming[y] || incoming[y].length !== 1) { - roots.push(y); - continue; - } - } - this.incoming = incoming; // Keep for serializing @@ Bug for nested formulas - // Now do the scan using existing roots - var rootsHash = {}; - for (var k = 0; k < roots.length; k++) { - rootsHash[roots[k].toNT()] = true; - } - return { 'roots': roots, 'subjects': subjects, - 'rootsHash': rootsHash, 'incoming': incoming }; + sf.addStatus(xhr.req, 'N3 parsed: ' + p.statementCount + ' triples in ' + p.lines + ' lines.'); + sf.store.add(xhr.original, ns.rdf('type'), ns.link('RDFDocument'), sf.appNode); + // var args = [xhr.original.uri] // Other args needed ever? + sf.doneFetch(xhr); + }; + }; }; - // ////////////////////////////////////////////////////// - - __Serializer.prototype.toN3 = function (f) { - return this.statementsToN3(f.statements); + Fetcher.N3Handler.toString = function () { + return 'N3Handler'; + }; + Fetcher.N3Handler.register = function (sf) { + sf.mediatypes['text/n3'] = { + 'q': '1.0' + }; // as per 2008 spec + /* + sf.mediatypes['application/x-turtle'] = { + 'q': 1.0 + } // pre 2008 + */ + sf.mediatypes['text/turtle'] = { + 'q': 1.0 + }; // post 2008 }; + Fetcher.N3Handler.pattern = new RegExp('(application|text)/(x-)?(rdf\\+)?(n3|turtle)'); - __Serializer.prototype._notQNameChars = '\t\r\n !"#$%&\'()*.,+/;<=>?@[\\]^`{|}~'; - __Serializer.prototype._notNameChars = __Serializer.prototype._notQNameChars + ':'; + Util.callbackify(this, ['request', 'recv', 'headers', 'load', 'fail', 'refresh', 'retract', 'done']); - __Serializer.prototype.explicitURI = function (uri) { - if (this.flags.indexOf('r') < 0 && this.base) { - uri = Uri.refTo(this.base, uri); - } else if (this.flags.indexOf('u') >= 0) { - // Unicode encoding NTriples style - uri = backslashUify(uri); - } else { - uri = hexify(uri); - } - return '<' + uri + '>'; + this.addHandler = function (handler) { + sf.handlers.push(handler); + handler.register(sf); }; - __Serializer.prototype.statementsToNTriples = function (sts) { - var sorted = sts.slice(); - sorted.sort(); - var str = ''; - var rdfns = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; - var self = this; - var kb = this.store; - var termToNT = function termToNT(x) { - if (x.termType !== 'Collection') { - return self.atomicTermToN3(x); - } - var list = x.elements; - var rest = kb.sym(rdfns + 'nill'); - for (var i = list.length - 1; i >= 0; i--) { - var bnode = new BlankNode(); - str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'first')) + ' ' + termToNT(list[i]) + '.\n'; - str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'rest')) + ' ' + termToNT(rest) + '.\n'; - rest = bnode; - } - return self.atomicTermToN3(rest); - }; - for (var i = 0; i < sorted.length; i++) { - var st = sorted[i]; - var s = ''; - s += termToNT(st.subject) + ' '; - s += termToNT(st.predicate) + ' '; - s += termToNT(st.object) + ' '; - if (this.flags.indexOf('q') >= 0) { - // Do quads not nrtiples - s += termToNT(st.why) + ' '; + this.switchHandler = function (name, xhr, cb, args) { + var Handler = null; + for (var i = 0; i < this.handlers.length; i++) { + if ('' + this.handlers[i] === name) { + Handler = this.handlers[i]; } - s += '.\n'; - str += s; } - return str; + if (!Handler) { + throw new Error('web.js: switchHandler: name=' + name + ' , this.handlers =' + this.handlers + '\n' + 'switchHandler: switching to ' + Handler + '; sf=' + sf + '; typeof Fetcher=' + (typeof Fetcher === 'undefined' ? 'undefined' : _typeof(Fetcher)) + ';\n\t Fetcher.HTMLHandler=' + Fetcher.HTMLHandler + '\n' + '\n\tsf.handlers=' + sf.handlers + '\n'); + } + new Handler(args).handlerFactory(xhr); + xhr.handle(cb); }; - __Serializer.prototype.statementsToN3 = function (sts) { - var indent = 4; - var width = 80; + this.addStatus = function (req, status) { + // + var now = new Date(); + status = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '.' + now.getMilliseconds() + '] ' + status; + // var kb = this.store; - // A URI Map alows us to put the type statemnts at the top. - var uriMap = { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type': 'aaa:00' }; - var SPO = function SPO(x, y) { - // Do limited canonicalization of bnodes - return Util.heavyCompareSPO(x, y, kb, uriMap); - }; - sts.sort(SPO); - - if (this.base && !this.defaultNamespace) { - this.defaultNamespace = this.base + '#'; + var s = kb.the(req, ns.link('status')); + if (s && s.append) { + s.append(kb.literal(status)); + } else { + log.warn('web.js: No list to add to: ' + s + ',' + status); // @@@ } + }; - var predMap = {}; - if (this.flags.indexOf('s') < 0) { - predMap['http://www.w3.org/2002/07/owl#sameAs'] = '='; + // Record errors in the system on failure + // Returns xhr so can just do return this.failfetch(...) + this.failFetch = function (xhr, status) { + this.addStatus(xhr.req, status); + if (!xhr.options.noMeta) { + kb.add(xhr.original, ns.link('error'), status); } - if (this.flags.indexOf('t') < 0) { - predMap['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'] = 'a'; + if (!xhr.resource.sameTerm(xhr.original)) { + console.log('@@ Recording failure original ' + xhr.original + '( as ' + xhr.resource + ') : ' + xhr.status); + } else { + console.log('@@ Recording failure for ' + xhr.original + ': ' + xhr.status); } - if (this.flags.indexOf('i') < 0) { - predMap['http://www.w3.org/2000/10/swap/log#implies'] = '=>'; + this.requested[Uri.docpart(xhr.original.uri)] = xhr.status; // changed 2015 was false + while (this.fetchCallbacks[xhr.original.uri] && this.fetchCallbacks[xhr.original.uri].length) { + this.fetchCallbacks[xhr.original.uri].shift()(false, 'Fetch of <' + xhr.original.uri + '> failed: ' + status, xhr); } - // //////////////////////// Arrange the bits of text + delete this.fetchCallbacks[xhr.original.uri]; + this.fireCallbacks('fail', [xhr.original.uri, status]); + xhr.abort(); + return xhr; + }; - var spaces = function spaces(n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += ' '; - }return s; - }; + // in the why part of the quad distinguish between HTML and HTTP header + // Reverse is set iif the link was rev= as opposed to rel= + this.linkData = function (xhr, rel, uri, why, reverse) { + if (!uri) return; + var predicate; + // See http://www.w3.org/TR/powder-dr/#httplink for describedby 2008-12-10 + var obj = kb.sym(Uri.join(uri, xhr.original.uri)); + if (rel === 'alternate' || rel === 'seeAlso' || rel === 'meta' || rel === 'describedby') { + if (obj.uri === xhr.original.uri) return; + predicate = ns.rdfs('seeAlso'); + } else if (rel === 'type') { + predicate = kb.sym('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); + } else { + // See https://www.iana.org/assignments/link-relations/link-relations.xml + // Alas not yet in RDF yet for each predicate + /// encode space in e.g. rel="shortcut icon" + predicate = kb.sym(Uri.join(encodeURIComponent(rel), 'http://www.iana.org/assignments/link-relations/')); + } + if (reverse) { + kb.add(obj, predicate, xhr.original, why); + } else { + kb.add(xhr.original, predicate, obj, why); + } + }; - var treeToLine = function treeToLine(tree) { - var str = ''; - for (var i = 0; i < tree.length; i++) { - var branch = tree[i]; - var s2 = typeof branch === 'string' ? branch : treeToLine(branch); - // Note the space before the dot in case statement ends 123. which is in fact allowed but be conservative. - if (i !== 0) { - var ch = str.slice(-1) || ' '; - if (s2 === ',' || s2 === ';') { - // no gap - } else if (s2 === '.' && !'0123456789.'.includes(ch)) {// no gap except after number - // no gap - } else { - str += ' '; // separate from previous token - } - } - str += s2; - } - return str; - }; + this.parseLinkHeader = function (xhr, thisReq) { + var link; + try { + link = xhr.getResponseHeader('link'); // May crash from CORS error + } catch (e) {} + if (link) { + var linkexp = /<[^>]*>\s*(\s*;\s*[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*")))*(,|$)/g; + var paramexp = /[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*"))/g; - // Convert a nested tree of lists and strings to a string - var treeToString = function treeToString(tree, level) { - var str = ''; - var lastLength = 100000; - if (level === undefined) level = -1; - for (var i = 0; i < tree.length; i++) { - var branch = tree[i]; - if (typeof branch !== 'string') { - var substr = treeToString(branch, level + 1); - if (substr.length < 10 * (width - indent * level) && substr.indexOf('"""') < 0) { - // Don't mess up multiline strings - var line = treeToLine(branch); - if (line.length < width - indent * level) { - branch = line; // Note! treat as string below - substr = ''; - } - } - if (substr) lastLength = 10000; - str += substr; - } - if (typeof branch === 'string') { - if (branch.length === 1 && str.slice(-1) === '\n') { - if (',.;'.indexOf(branch) >= 0) { - str = str.slice(0, -1) + branch + '\n'; // slip punct'n on end - lastLength += 1; - continue; - } - } - if (lastLength < indent * level + 4 || // if new line not necessary - lastLength + branch.length + 1 < width && ';.'.indexOf(str[str.length - 2]) < 0) { - // or the string fits on last line - str = str.slice(0, -1) + ' ' + branch + '\n'; // then continue on this line - lastLength += branch.length + 1; - } else { - var _line = spaces(indent * level) + branch; - str += _line + '\n'; - lastLength = _line.length; - if (level < 0) { - str += '\n'; // extra blank line - lastLength = 100000; // don't touch - } - } + var matches = link.match(linkexp); + for (var i = 0; i < matches.length; i++) { + var split = matches[i].split('>'); + var href = split[0].substring(1); + var ps = split[1]; + var s = ps.match(paramexp); + for (var j = 0; j < s.length; j++) { + var p = s[j]; + var paramsplit = p.split('='); + // var name = paramsplit[0] + var rel = paramsplit[1].replace(/["']/g, ''); // '" + this.linkData(xhr, rel, href, thisReq); } } - return str; - }; - - // //////////////////////////////////////////// Structure for N3 - // Convert a set of statements into a nested tree of lists and strings - function statementListToTreeMethod(statements) { - var stats = this.rootSubjects(statements); - var roots = stats.roots; - var results = []; - for (var i = 0; i < roots.length; i++) { - var root = roots[i]; - results.push(subjectTree(root, stats)); - } - return results; - } - var statementListToTree = statementListToTreeMethod.bind(this); - - // The tree for a subject - function subjectTree(subject, stats) { - if (subject.termType === 'BlankNode' && !stats.incoming[subject]) { - return objectTree(subject, stats, true).concat(['.']); // Anonymous bnode subject - } - return [termToN3(subject, stats)].concat([propertyTree(subject, stats)]).concat(['.']); } - // The property tree for a single subject or anonymous node - function propertyTreeMethod(subject, stats) { - var results = []; - var lastPred = null; - var sts = stats.subjects[this.toStr(subject)] || []; // relevant statements - if (typeof sts === 'undefined') { - throw new Error('Cant find statements for ' + subject); - } + }; - var objects = []; - for (var i = 0; i < sts.length; i++) { - var st = sts[i]; - if (st.predicate.uri === lastPred) { - objects.push(','); - } else { - if (lastPred) { - results = results.concat([objects]).concat([';']); - objects = []; - } - results.push(predMap[st.predicate.uri] ? predMap[st.predicate.uri] : termToN3(st.predicate, stats)); - } - lastPred = st.predicate.uri; - objects.push(objectTree(st.object, stats)); - } - results = results.concat([objects]); - return results; + this.doneFetch = function (xhr) { + this.addStatus(xhr.req, 'Done.'); + this.requested[xhr.original.uri] = 'done'; // Kenny + while (this.fetchCallbacks[xhr.original.uri] && this.fetchCallbacks[xhr.original.uri].length) { + this.fetchCallbacks[xhr.original.uri].shift()(true, undefined, xhr); } - var propertyTree = propertyTreeMethod.bind(this); + delete this.fetchCallbacks[xhr.original.uri]; + this.fireCallbacks('done', [xhr.original.uri]); + }; + var handlerList = [Fetcher.RDFXMLHandler, Fetcher.XHTMLHandler, Fetcher.XMLHandler, Fetcher.HTMLHandler, Fetcher.TextHandler, Fetcher.N3Handler]; + handlerList.map(this.addHandler); - function objectTreeMethod(obj, stats, force) { - if (obj.termType === 'BlankNode' && (force || stats.rootsHash[obj.toNT()] === undefined)) { - // if not a root - if (stats.subjects[this.toStr(obj)]) { - return ['[', propertyTree(obj, stats), ']']; - } else { - return '[]'; - } - } - return termToN3(obj, stats); + /** Note two nodes are now smushed + ** + ** If only one was flagged as looked up, then + ** the new node is looked up again, which + ** will make sure all the URIs are dereferenced + */ + this.nowKnownAs = function (was, now) { + if (this.lookedUp[was.uri]) { + if (!this.lookedUp[now.uri]) this.lookUpThing(now, was); // @@@@ Transfer userCallback + } else if (this.lookedUp[now.uri]) { + if (!this.lookedUp[was.uri]) this.lookUpThing(was, now); } - var objectTree = objectTreeMethod.bind(this); + }; - function termToN3Method(expr, stats) { - // - var i, res; - switch (expr.termType) { - case 'Graph': - res = ['{']; - res = res.concat(statementListToTree(expr.statements)); - return res.concat(['}']); + // Returns promise of XHR + // + // Writes back to the web what we have in the store for this uri + this.putBack = function (uri) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - case 'Collection': - res = ['(']; - for (i = 0; i < expr.elements.length; i++) { - res.push([objectTree(expr.elements[i], stats)]); - } - res.push(')'); - return res; + uri = uri.uri || uri; // Accept object or string + var doc = new NamedNode(uri).doc(); // strip off # + options.data = serialize(doc, this.store, doc.uri, options.contentType || 'text/turtle'); + return this.webOperation('PUT', uri, options); + }; - default: - return this.atomicTermToN3(expr); - } - } - __Serializer.prototype.termToN3 = termToN3; - var termToN3 = termToN3Method.bind(this); + // Returns promise of XHR + // + this.webOperation = function (method, uri) { + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - function prefixDirectivesMethod() { - var str = ''; - if (this.defaultNamespace) { - str += '@prefix : ' + this.explicitURI(this.defaultNamespace) + '.\n'; - } - for (var ns in this.prefixes) { - if (!this.prefixes.hasOwnProperty(ns)) continue; - if (!this.namespacesUsed[ns]) continue; - str += '@prefix ' + this.prefixes[ns] + ': ' + this.explicitURI(ns) + '.\n'; + uri = uri.uri || uri; + uri = this.proxyIfNecessary(uri); + var fetcher = this; + return new Promise(function (resolve, reject) { + var xhr = Util.XMLHTTPFactory(); + xhr.options = options; + xhr.original = fetcher.store.sym(uri); + if (!options.noMeta && typeof tabulator !== 'undefined') { + fetcher.saveRequestMetadata(xhr, fetcher.store, uri); } - return str + '\n'; - } - var prefixDirectives = prefixDirectivesMethod.bind(this); - // Body of statementsToN3: - var tree = statementListToTree(sts); - return prefixDirectives() + treeToString(tree); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + // NOte a 404 can be not afailure + var ok = !xhr.status || xhr.status >= 200 && xhr.status < 300; + if (!options.noMeta && typeof tabulator !== 'undefined') { + fetcher.saveResponseMetadata(xhr, fetcher.store); + } + if (ok) { + resolve(xhr); + } else { + reject(xhr.status + ' ' + xhr.statusText); + } + } + }; + xhr.open(method, uri, true); + xhr.setRequestHeader('Content-type', options.contentType || 'text/turtle'); + xhr.send(options.data ? options.data : undefined); + }); }; - // //////////////////////////////////////////// Atomic Terms - // Deal with term level things and nesting with no bnode structure - __Serializer.prototype.atomicTermToN3 = function atomicTermToN3(expr, stats) { - switch (expr.termType) { - case 'BlankNode': - case 'Variable': - return expr.toNT(); - case 'Literal': - var val = expr.value.toString(); // should be a string already - if (expr.datatype && this.flags.indexOf('x') < 0) { - // Supress native numbers - switch (expr.datatype.uri) { + this.webCopy = function (here, there, content_type) { + var fetcher = this; + here = here.uri || here; + return new Promise(function (resolve, reject) { + fetcher.webOperation('GET', here).then(function (xhr) { + fetcher.webOperation('PUT', // @@@ change to binary from text + there, { data: xhr.responseText, contentType: content_type }).then(function (xhr) { + resolve(xhr); + }).catch(function (e) { + reject(e); + }); + }).catch(function (e) { + reject(e); + }); + }); + }; - case 'http://www.w3.org/2001/XMLSchema#integer': - return val; + // Looks up something. + // + // Looks up all the URIs a things has. + // + // Parameters: + // + // term: canonical term for the thing whose URI is to be dereferenced + // rterm: the resource which refered to this (for tracking bad links) + // options: (old: force paraemter) or dictionary of options: + // force: Load the data even if loaded before + // oneDone: is called as callback(ok, errorbody, xhr) for each one + // allDone: is called as callback(ok, errorbody) for all of them + // Returns the number of URIs fetched + // + this.lookUpThing = function (term, rterm, options, oneDone, allDone) { + var uris = kb.uris(term); // Get all URIs + var success = true; + var errors = ''; + var outstanding = {}; + var force; + if (options === false || options === true) { + // Old signature + force = options; + options = { force: force }; + } else { + if (options === undefined) options = {}; + force = !!options.force; + } - case 'http://www.w3.org/2001/XMLSchema#decimal': - // In urtle must have dot - if (val.indexOf('.') < 0) val += '.0'; - return val; + if (typeof uris !== 'undefined') { + for (var i = 0; i < uris.length; i++) { + var u = uris[i]; + outstanding[u] = true; + this.lookedUp[u] = true; + var sf = this; - case 'http://www.w3.org/2001/XMLSchema#double': - // Must force use of 'e' - if (val.indexOf('.') < 0) val += '.0'; - if (val.indexOf('e') < 0) val += 'e0'; - return val; + var requestOne = function requestOne(u1) { + sf.requestURI(Uri.docpart(u1), rterm, options, function (ok, body, xhr) { + if (ok) { + if (oneDone) oneDone(true, u1); + } else { + if (oneDone) oneDone(false, body); + success = false; + errors += body + '\n'; + } + delete outstanding[u]; + if (Object.keys(outstanding).length > 0) { + return; + } + if (allDone) { + allDone(success, errors); + } + }); + }; + requestOne(u); + } + } + return uris.length; + }; - case 'http://www.w3.org/2001/XMLSchema#boolean': - return expr.value ? 'true' : 'false'; - } - } - var str = this.stringToN3(expr.value); - if (expr.language) { - str += '@' + expr.language; - } else if (!expr.datatype.equals(XSD.string)) { - str += '^^' + this.atomicTermToN3(expr.datatype, stats); - } - return str; - case 'NamedNode': - return this.symbolToN3(expr); - default: - throw new Error('Internal: atomicTermToN3 cannot handle ' + expr + ' of termType: ' + expr.termType); + /* Promise-based load function + ** + ** NamedNode -> Promise of xhr + ** uri string -> Promise of xhr + ** Array of the above -> Promise of array of xhr + ** + ** @@ todo: If p1 is array then sequence or parallel fetch of all + */ + this.load = function (uri, options) { + var fetcher = this; + if (uri instanceof Array) { + var ps = uri.map(function (x) { + return fetcher.load(x); + }); + return Promise.all(ps); } + uri = uri.uri || uri; // NamedNode or URI string + return new Promise(function (resolve, reject) { + fetcher.nowOrWhenFetched(uri, options, function (ok, message, xhr) { + if (ok) { + resolve(xhr); + } else { + reject(message); + } + }); + }); }; - // stringToN3: String escaping for N3 - - __Serializer.prototype.validPrefix = new RegExp(/^[a-zA-Z][a-zA-Z0-9]*$/); - - __Serializer.prototype.forbidden1 = new RegExp(/[\\"\b\f\r\v\t\n\u0080-\uffff]/gm); - __Serializer.prototype.forbidden3 = new RegExp(/[\\"\b\f\r\v\u0080-\uffff]/gm); - __Serializer.prototype.stringToN3 = function stringToN3(str, flags) { - if (!flags) flags = 'e'; - var res = ''; - var i, j, k; - var delim; - var forbidden; - if (str.length > 20 && // Long enough to make sense - str.slice(-1) !== '"' && // corner case' - flags.indexOf('n') < 0 && ( // Force single line - str.indexOf('\n') > 0 || str.indexOf('"') > 0)) { - delim = '"""'; - forbidden = __Serializer.prototype.forbidden3; + /* Ask for a doc to be loaded if necessary then call back + ** + ** Changed 2013-08-20: Added (ok, errormessage) params to callback + ** + ** Calling methods: + ** nowOrWhenFetched (uri, userCallback) + ** nowOrWhenFetched (uri, options, userCallback) + ** nowOrWhenFetched (uri, referringTerm, userCallback, options) <-- old + ** nowOrWhenFetched (uri, referringTerm, userCallback) <-- old + ** + ** Options include: + ** referringTerm The docuemnt in which this link was found. + ** this is valuable when finding the source of bad URIs + ** force boolean. Never mind whether you have tried before, + ** load this from scratch. + ** forceContentType Override the incoming header to force the data to be + ** treaed as this content-type. + **/ + this.nowOrWhenFetched = function (uri, p2, userCallback, options) { + uri = uri.uri || uri; // allow symbol object or string to be passed + if (typeof p2 === 'function') { + options = {}; + userCallback = p2; + } else if (typeof p2 === 'undefined') {// original calling signature + // referingTerm = undefined + } else if (p2 instanceof NamedNode) { + // referingTerm = p2 + options = { referingTerm: p2 }; } else { - delim = '"'; - forbidden = __Serializer.prototype.forbidden1; + options = p2; } - for (i = 0; i < str.length;) { - forbidden.lastIndex = 0; - var m = forbidden.exec(str.slice(i)); - if (m == null) break; - j = i + forbidden.lastIndex - 1; - res += str.slice(i, j); - var ch = str[j]; - if (ch === '"' && delim === '"""' && str.slice(j, j + 3) !== '"""') { - res += ch; - } else { - k = '\b\f\r\t\v\n\\"'.indexOf(ch); // No escaping of bell (7)? - if (k >= 0) { - res += '\\' + 'bfrtvn\\"'[k]; - } else { - if (flags.indexOf('e') >= 0) { - // Unicode escaping in strings not unix style - res += '\\u' + ('000' + ch.charCodeAt(0).toString(16).toLowerCase()).slice(-4); - } else { - // no 'e' flag - res += ch; + + this.requestURI(uri, p2, options || {}, userCallback); + }; + + this.get = this.nowOrWhenFetched; + + // Look up response header + // + // Returns: a list of header values found in a stored HTTP response + // or [] if response was found but no header found + // or undefined if no response is available. + // + this.getHeader = function (doc, header) { + var kb = this.store; + var requests = kb.each(undefined, ns.link('requestedURI'), doc.uri); + for (var r = 0; r < requests.length; r++) { + var request = requests[r]; + if (request !== undefined) { + var response = kb.any(request, ns.link('response')); + if (request !== undefined) { + var results = kb.each(response, ns.httph(header.toLowerCase())); + if (results.length) { + return results.map(function (v) { + return v.value; + }); } + return []; } } - i = j + 1; } - return delim + res + str.slice(i) + delim; + return undefined; }; - // A single symbol, either in <> or namespace notation - __Serializer.prototype.symbolToN3 = function symbolToN3(x) { - // c.f. symbolString() in notation3.py - var uri = x.uri; - var j = uri.indexOf('#'); - if (j < 0 && this.flags.indexOf('/') < 0) { - j = uri.lastIndexOf('/'); - } - if (j >= 0 && this.flags.indexOf('p') < 0 && ( - // Can split at namespace but only if http[s]: URI or file: or ws[s] (why not others?) - uri.indexOf('http') === 0 || uri.indexOf('ws') === 0 || uri.indexOf('file') === 0)) { - var canSplit = true; - for (var k = j + 1; k < uri.length; k++) { - if (__Serializer.prototype._notNameChars.indexOf(uri[k]) >= 0) { - canSplit = false; - break; - } - } - /* - if (uri.slice(0, j + 1) === this.base + '#') { // base-relative - if (canSplit) { - return ':' + uri.slice(j + 1) // assume deafult ns is local - } else { - return '<#' + uri.slice(j + 1) + '>' - } - } - */ - if (canSplit) { - var localid = uri.slice(j + 1); - var namesp = uri.slice(0, j + 1); - if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) { - // d -> suppress default - if (this.flags.indexOf('k') >= 0 && this.keyords.indexOf(localid) < 0) { - return localid; - } - return ':' + localid; - } - // this.checkIntegrity() // @@@ Remove when not testing - var prefix = this.prefixes[namesp]; - if (!prefix) prefix = this.makeUpPrefix(namesp); - if (prefix) { - this.namespacesUsed[namesp] = true; - return prefix + ':' + localid; + this.proxyIfNecessary = function (uri) { + if (typeof tabulator !== 'undefined' && tabulator.isExtension) return uri; // Extenstion does not need proxy + + if (typeof $SolidTestEnvironment !== 'undefined' && $SolidTestEnvironment.localSiteMap) { + // nested dictionaries of URI parts from origin down + var hostpath = uri.split('/').slice(2); // the bit after the // + var lookup = function lookup(parts, index) { + var z = index[parts.shift()]; + if (!z) return null; + if (typeof z === 'string') { + return z + parts.join('/'); } - // Fall though if can't do qname + if (!parts) return null; + return lookup(parts, z); + }; + var y = lookup(hostpath, $SolidTestEnvironment.localSiteMap); + if (y) { + return y; } } - return this.explicitURI(uri); + // browser does 2014 on as https browser script not trusted + // If the web app origin is https: then the mixed content rules + // prevent it loading insecure http: stuff so we need proxy. + if (Fetcher.crossSiteProxyTemplate && typeof document !== 'undefined' && document.location && ('' + document.location).slice(0, 6) === 'https:' && // origin is secure + uri.slice(0, 5) === 'http:') { + // requested data is not + return Fetcher.crossSiteProxyTemplate.replace('{uri}', encodeURIComponent(uri)); + } + return uri; }; - // String escaping utilities - function hexify(str) { - // also used in parser - return encodeURI(str); - } + this.saveRequestMetadata = function (xhr, kb, docuri) { + var request = kb.bnode(); + xhr.resource = kb.sym(docuri); - function backslashUify(str) { - var res = ''; - var k; - for (var i = 0; i < str.length; i++) { - k = str.charCodeAt(i); - if (k > 65535) { - res += '\\U' + ('00000000' + k.toString(16)).slice(-8); // convert to upper? - } else if (k > 126) { - res += '\\u' + ('0000' + k.toString(16)).slice(-4); - } else { - res += str[i]; + xhr.req = request; + if (!xhr.options.noMeta) { + // Store no triples but do mind the bnode for req + var now = new Date(); + var timeNow = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '] '; + kb.add(request, ns.rdfs('label'), kb.literal(timeNow + ' Request for ' + docuri), this.appNode); + kb.add(request, ns.link('requestedURI'), kb.literal(docuri), this.appNode); + if (xhr.original && xhr.original.uri !== docuri) { + kb.add(request, ns.link('orginalURI'), kb.literal(xhr.original.uri), this.appNode); } + kb.add(request, ns.link('status'), kb.collection(), this.appNode); } - return res; - } - - // /////////////////////////// Quad store serialization + return request; + }; - // @para. write - a function taking a single string to be output - // - __Serializer.prototype.writeStore = function (write) { - var kb = this.store; - var fetcher = kb.fetcher; - var session = fetcher && fetcher.appNode; + this.saveResponseMetadata = function (xhr, kb) { + var response = kb.bnode(); - // The core data + if (xhr.req) kb.add(xhr.req, ns.link('response'), response); + kb.add(response, ns.http('status'), kb.literal(xhr.status), response); + kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response); - var sources = this.store.index[3]; - for (var s in sources) { - // -> assume we can use -> as short for log:semantics - var source = kb.fromNT(s); - if (session && source.sameTerm(session)) continue; - write('\n' + this.atomicTermToN3(source) + ' ' + this.atomicTermToN3(kb.sym('http://www.w3.org/2000/10/swap/log#semantics')) + ' { ' + this.statementsToN3(kb.statementsMatching(undefined, undefined, undefined, source)) + ' }.\n'); + xhr.headers = {}; + if (Uri.protocol(xhr.resource.uri) === 'http' || Uri.protocol(xhr.resource.uri) === 'https') { + xhr.headers = Util.getHTTPHeaders(xhr); + for (var h in xhr.headers) { + // trim below for Safari - adds a CR! + var value = xhr.headers[h].trim(); + var h2 = h.toLowerCase(); + kb.add(response, ns.httph(h2), value, response); + if (h2 === 'content-type') { + // Convert to RDF type + kb.add(xhr.resource, ns.rdf('type'), Util.mediaTypeClass(value), response); + } + } } - - // The metadata from HTTP interactions: - - kb.statementsMatching(undefined, kb.sym('http://www.w3.org/2007/ont/link#requestedURI')).map(function (st) { - write('\n<' + st.object.value + '> log:metadata {\n'); - var sts = kb.statementsMatching(undefined, undefined, undefined, st.subject); - write(this.statementsToN3(this.statementsToN3(sts))); - write('}.\n'); - }); - - // Inferences we have made ourselves not attributable to anyone else - - var metaSources = []; - if (session) metaSources.push(session); - var metadata = []; - metaSources.map(function (source) { - metadata = metadata.concat(kb.statementsMatching(undefined, undefined, undefined, source)); - }); - write(this.statementsToN3(metadata)); + return response; }; - // ////////////////////////////////////////////// XML serialization - - __Serializer.prototype.statementsToXML = function (sts) { - var indent = 4; - var width = 80; - - var namespaceCounts = []; // which have been used - namespaceCounts['http://www.w3.org/1999/02/22-rdf-syntax-ns#'] = true; - - var liPrefix = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_'; // prefix for ordered list items - - // //////////////////////// Arrange the bits of XML text + /** Requests a document URI and arranges to load the document. + ** Parameters: + ** term: term for the thing whose URI is to be dereferenced + ** rterm: the resource which refered to this (for tracking bad links) + ** options: + ** force: Load the data even if loaded before + ** withCredentials: flag for XHR/CORS etc + ** userCallback: Called with (true) or (false, errorbody, {status: 400}) after load is done or failed + ** Return value: + ** The xhr object for the HTTP access + ** null if the protocol is not a look-up protocol, + ** or URI has already been loaded + */ + this.requestURI = function (docuri, rterm, options, userCallback) { + // sources_request_new + // Various calling conventions + docuri = docuri.uri || docuri; // NamedNode or string + docuri = docuri.split('#')[0]; + if (typeof options === 'boolean') { + options = { 'force': options }; // Ols dignature + } + if (typeof options === 'undefined') options = {}; - var spaces = function spaces(n) { - var s = ''; - for (var i = 0; i < n; i++) { - s += ' '; - }return s; - }; + var force = !!options.force; + var kb = this.store; + var args = arguments; + var baseURI = options.baseURI || docuri; // Preseve though proxying etc + options.userCallback = userCallback; - var XMLtreeToLine = function XMLtreeToLine(tree) { - var str = ''; - for (var i = 0; i < tree.length; i++) { - var branch = tree[i]; - var s2 = typeof branch === 'string' ? branch : XMLtreeToLine(branch); - str += s2; - } - return str; - }; + var pcol = Uri.protocol(docuri); + if (pcol === 'tel' || pcol === 'mailto' || pcol === 'urn') { + // "No look-up operation on these, but they are not errors?" + console.log('Unsupported protocol in: ' + docuri); + return userCallback(false, 'Unsupported protocol', { 'status': 900 }) || undefined; + } + var docterm = kb.sym(docuri); - // Convert a nested tree of lists and strings to a string - var XMLtreeToString = function XMLtreeToString(tree, level) { - var str = ''; - var line; - var lastLength = 100000; - if (!level) level = 0; - for (var i = 0; i < tree.length; i++) { - var branch = tree[i]; - if (typeof branch !== 'string') { - var substr = XMLtreeToString(branch, level + 1); - if (substr.length < 10 * (width - indent * level) && substr.indexOf('"""') < 0) { - // Don't mess up multiline strings - line = XMLtreeToLine(branch); - if (line.length < width - indent * level) { - branch = ' ' + line; // @@ Hack: treat as string below - substr = ''; - } - } - if (substr) lastLength = 10000; - str += substr; - } - if (typeof branch === 'string') { - if (lastLength < indent * level + 4) { - // continue - str = str.slice(0, -1) + ' ' + branch + '\n'; - lastLength += branch.length + 1; - } else { - line = spaces(indent * level) + branch; - str += line + '\n'; - lastLength = line.length; - } - } else {// not string - } + var sta = this.getState(docuri); + if (!force) { + if (sta === 'fetched') { + return userCallback ? userCallback(true) : undefined; } - return str; - }; - - function statementListToXMLTreeMethod(statements) { - this.suggestPrefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'); - var stats = this.rootSubjects(statements); - var roots = stats.roots; - var results = []; - for (var i = 0; i < roots.length; i++) { - var root = roots[i]; - results.push(subjectXMLTree(root, stats)); + if (sta === 'failed') { + return userCallback ? userCallback(false, 'Previously failed. ' + this.requested[docuri], { 'status': this.requested[docuri] }) : undefined; // An xhr standin } - return results; + // if (sta === 'requested') return userCallback? userCallback(false, "Sorry already requested - pending already.", {'status': 999 }) : undefined + } else { + delete this.nonexistant[docuri]; } - var statementListToXMLTree = statementListToXMLTreeMethod.bind(this); + // @@ Should allow concurrent requests - function escapeForXML(str) { - if (typeof str === 'undefined') return '@@@undefined@@@@'; - return str.replace(/[&<"]/g, function (m) { - switch (m[0]) { - case '&': - return '&'; - case '<': - return '<'; - case '"': - return '"'; // ' - } - }); - } + // If it is 'failed', then shoulkd we try again? I think so so an old error doens't get stuck + // if (sta === 'unrequested') - function relURIMethod(term) { - return escapeForXML(this.base ? Util.uri.refTo(this.base, term.uri) : term.uri); - } - var relURI = relURIMethod.bind(this); + this.fireCallbacks('request', args); // Kenny: fire 'request' callbacks here + // dump( "web.js: Requesting uri: " + docuri + "\n" ) - // The tree for a subject - function subjectXMLTreeMethod(subject, stats) { - var results = []; - var type, t, st, pred; - var sts = stats.subjects[this.toStr(subject)]; // relevant statements - if (typeof sts === 'undefined') { - // empty bnode - return propertyXMLTree(subject, stats); + if (userCallback) { + if (!this.fetchCallbacks[docuri]) { + this.fetchCallbacks[docuri] = [userCallback]; + } else { + this.fetchCallbacks[docuri].push(userCallback); } + } - // Sort only on the predicate, leave the order at object - // level undisturbed. This leaves multilingual content in - // the order of entry (for partner literals), which helps - // readability. - // - // For the predicate sort, we attempt to split the uri - // as a hint to the sequence - sts.sort(function (a, b) { - var ap = a.predicate.uri; - var bp = b.predicate.uri; - if (ap.substring(0, liPrefix.length) === liPrefix || bp.substring(0, liPrefix.length) === liPrefix) { - // we're only interested in sorting list items - return ap.localeCompare(bp); - } + if (this.requested[docuri] === true) { + return; // Don't ask again - wait for existing call + } else { + this.requested[docuri] = true; + } - var as = ap.substring(liPrefix.length); - var bs = bp.substring(liPrefix.length); - var an = parseInt(as, 10); - var bn = parseInt(bs, 10); - if (isNaN(an) || isNaN(bn) || an !== as || bn !== bs) { - // we only care about integers - return ap.localeCompare(bp); - } + if (!options.noMeta && rterm && rterm.uri) { + kb.add(docterm.uri, ns.link('requestedBy'), rterm.uri, this.appNode); + } - return an - bn; - }); + var xhr = Util.XMLHTTPFactory(); + var req = xhr.req = kb.bnode(); + xhr.original = kb.sym(baseURI); + // console.log('XHR original: ' + xhr.original) + xhr.options = options; + xhr.resource = docterm; // This might be proxified + var sf = this; - for (var i = 0; i < sts.length; i++) { - st = sts[i]; - // look for a type - if (st.predicate.uri === 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' && !type && st.object.termType === 'symbol') { - type = st.object; - continue; // don't include it as a child element - } + var now = new Date(); + var timeNow = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '] '; + if (!options.noMeta) { + kb.add(req, ns.rdfs('label'), kb.literal(timeNow + ' Request for ' + docuri), this.appNode); + kb.add(req, ns.link('requestedURI'), kb.literal(docuri), this.appNode); + kb.add(req, ns.link('status'), kb.collection(), this.appNode); + } - // see whether predicate can be replaced with "li" - pred = st.predicate; - if (pred.uri.substr(0, liPrefix.length) === liPrefix) { - var number = pred.uri.substr(liPrefix.length); - // make sure these are actually numeric list items - var intNumber = parseInt(number, 10); - if (number === intNumber.toString()) { - // was numeric; don't need to worry about ordering since we've already - // sorted the statements - pred = new NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#li'); - } - } + var checkCredentialsRetry = function checkCredentialsRetry() { + if (!xhr.withCredentials) return false; // not dealt with - t = qname(pred); - switch (st.object.termType) { - case 'BlankNode': - if (stats.incoming[st.object].length === 1) { - // there should always be something in the incoming array for a bnode - results = results.concat(['<' + t + ' rdf:parseType="Resource">', subjectXMLTree(st.object, stats), '']); - } else { - results = results.concat(['<' + t + ' rdf:nodeID="' + st.object.toNT().slice(2) + '"/>']); - } - break; - case 'NamedNode': - results = results.concat(['<' + t + ' rdf:resource="' + relURI(st.object) + '"/>']); - break; - case 'Literal': - results = results.concat(['<' + t + (st.object.datatype.equals(XSD.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.uri) + '"') + (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') + '>' + escapeForXML(st.object.value) + '']); - break; - case 'Collection': - results = results.concat(['<' + t + ' rdf:parseType="Collection">', collectionXMLTree(st.object, stats), '']); - break; - default: - throw new Error("Can't serialize object of type " + st.object.termType + ' into XML'); - } // switch + if (xhr.retriedWithCredentials) { + return true; } - - var tag = type ? qname(type) : 'rdf:Description'; - - var attrs = ''; - if (subject.termType === 'BlankNode') { - if (!stats.incoming[subject] || stats.incoming[subject].length !== 1) { - // not an anonymous bnode - attrs = ' rdf:nodeID="' + subject.toNT().slice(2) + '"'; + xhr.retriedWithCredentials = true; // protect against called twice + console.log('web: Retrying with no credentials for ' + xhr.resource); + xhr.abort(); + delete sf.requested[docuri]; // forget the original request happened + var newopt = {}; + for (var opt in options) { + // transfer baseURI etc + if (options.hasOwnProperty(opt)) { + newopt[opt] = options[opt]; } - } else { - attrs = ' rdf:about="' + relURI(subject) + '"'; } + newopt.withCredentials = false; + sf.addStatus(xhr.req, 'Abort: Will retry with credentials SUPPRESSED to see if that helps'); + sf.requestURI(docuri, rterm, newopt, xhr.userCallback); // userCallback already registered (with where?) + return true; + }; - return ['<' + tag + attrs + '>'].concat([results]).concat(['']); - } - - var subjectXMLTree = subjectXMLTreeMethod.bind(this); + var onerrorFactory = function onerrorFactory(xhr) { + return function (event) { + xhr.onErrorWasCalled = true; // debugging and may need it + if (typeof document !== 'undefined') { + // Mashup situation, not node etc + if (Fetcher.crossSiteProxyTemplate && document.location && !xhr.proxyUsed) { + var hostpart = Uri.hostpart; + var here = '' + document.location; + var uri = xhr.resource.uri; + if (hostpart(here) && hostpart(uri) && hostpart(here) !== hostpart(uri)) { + // If cross-site + if (xhr.status === 401 || xhr.status === 403 || xhr.status === 404) { + onreadystatechangeFactory(xhr)(); + } else { + // IT IS A PAIN THAT NO PROPER ERROR REPORTING + if (checkCredentialsRetry(xhr)) { + // If credentials flag set, retry without, + return; + } + // If it wasn't, or we already tried that + var newURI = Fetcher.crossSiteProxy(uri); + console.log('web: Direct failed so trying proxy ' + newURI); + sf.addStatus(xhr.req, 'BLOCKED -> Cross-site Proxy to <' + newURI + '>'); + if (xhr.aborted) return; - function collectionXMLTree(subject, stats) { - var res = []; - for (var i = 0; i < subject.elements.length; i++) { - res.push(subjectXMLTree(subject.elements[i], stats)); - } - return res; - } + var kb = sf.store; + var oldreq = xhr.req; + if (!xhr.options.noMeta) { + kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), oldreq); + } + xhr.abort(); + xhr.aborted = true; - // The property tree for a single subject or anonymos node - function propertyXMLTreeMethod(subject, stats) { - var results = []; - var sts = stats.subjects[this.toStr(subject)]; // relevant statements - if (!sts) return results; // No relevant statements - sts.sort(); - for (var i = 0; i < sts.length; i++) { - var st = sts[i]; - switch (st.object.termType) { - case 'BlankNode': - if (stats.rootsHash[st.object.toNT()]) { - // This bnode has been done as a root -- no content here @@ what bout first time - results = results.concat(['<' + qname(st.predicate) + ' rdf:nodeID="' + st.object.toNT().slice(2) + '">', '']); - } else { - results = results.concat(['<' + qname(st.predicate) + ' rdf:parseType="Resource">', propertyXMLTree(st.object, stats), '']); - } - break; - case 'NamedNode': - results = results.concat(['<' + qname(st.predicate) + ' rdf:resource="' + relURI(st.object) + '"/>']); - break; - case 'Literal': - results = results.concat(['<' + qname(st.predicate) + (st.object.datatype.equals(XSD.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.value) + '"') + (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') + '>' + escapeForXML(st.object.value) + '']); - break; - case 'Collection': - results = results.concat(['<' + qname(st.predicate) + ' rdf:parseType="Collection">', collectionXMLTree(st.object, stats), '']); - break; - default: - throw new Error("Can't serialize object of type " + st.object.termType + ' into XML'); - } // switch - } - return results; - } - var propertyXMLTree = propertyXMLTreeMethod.bind(this); + sf.addStatus(oldreq, 'redirected to new request'); // why + // the callback throws an exception when called from xhr.onerror (so removed) + // sf.fireCallbacks('done', args) // Are these args right? @@@ Not done yet! done means success + sf.requested[xhr.resource.uri] = 'redirected'; + sf.redirectedTo[xhr.resource.uri] = newURI; - function qnameMethod(term) { - var uri = term.uri; + if (sf.fetchCallbacks[xhr.resource.uri]) { + if (!sf.fetchCallbacks[newURI]) { + sf.fetchCallbacks[newURI] = []; + } + sf.fetchCallbacks[newURI] === sf.fetchCallbacks[newURI].concat(sf.fetchCallbacks[xhr.resource.uri]); + delete sf.fetchCallbacks[xhr.resource.uri]; + } - var j = uri.indexOf('#'); - if (j < 0 && this.flags.indexOf('/') < 0) { - j = uri.lastIndexOf('/'); - } - if (j < 0) throw new Error('Cannot make qname out of <' + uri + '>'); + var xhr2 = sf.requestURI(newURI, xhr.resource, xhr.options, xhr.userCallback); + if (xhr2) { + xhr2.proxyUsed = true; // only try the proxy once + xhr2.original = xhr.original; + console.log('Proxying but original still ' + xhr2.original); + } + if (xhr2 && xhr2.req) { + if (!xhr.options.noMeta) { + kb.add(xhr.req, kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), xhr2.req, sf.appNode); + } + return; + } + } + } + xhr.CORS_status = 999; + // xhr.status = 999 forbidden - read-only + } + } // mashu + }; // function of event + }; // onerrorFactory - for (var k = j + 1; k < uri.length; k++) { - if (__Serializer.prototype._notNameChars.indexOf(uri[k]) >= 0) { - throw new Error('Invalid character "' + uri[k] + '" cannot be in XML qname for URI: ' + uri); - } - } - var localid = uri.slice(j + 1); - var namesp = uri.slice(0, j + 1); - if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) { - // d -> suppress default - return localid; - } - var prefix = this.prefixes[namesp]; - if (!prefix) prefix = this.makeUpPrefix(namesp); - namespaceCounts[namesp] = true; - return prefix + ':' + localid; - } - var qname = qnameMethod.bind(this); + // Set up callbacks + var onreadystatechangeFactory = function onreadystatechangeFactory(xhr) { + return function () { + var handleResponse = function handleResponse() { + if (xhr.handleResponseDone) return; + xhr.handleResponseDone = true; + var handler = null; + var thisReq = xhr.req; // Might have changes by redirect + sf.fireCallbacks('recv', args); + var kb = sf.store; + sf.saveResponseMetadata(xhr, kb); + sf.fireCallbacks('headers', [{ uri: docuri, headers: xhr.headers }]); - // Body of toXML: + // Check for masked errors. + // For "security reasons" theboraser hides errors such as CORS errors from + // the calling code (2015). oneror() used to be called but is not now. + // + if (xhr.status === 0) { + console.log('Masked error - status 0 for ' + xhr.resource.uri); + if (checkCredentialsRetry(xhr)) { + // retry is could be credentials flag CORS issue + return; + } + xhr.CORS_status = 900; // unknown masked error + return; + } + if (xhr.status >= 400) { + // For extra dignostics, keep the reply + // @@@ 401 should cause a retry with credential son + // @@@ cache the credentials flag by host ???? + if (xhr.status === 404) { + kb.fetcher.nonexistant[xhr.resource.uri] = true; + } + if (xhr.responseText.length > 10) { + var response2 = kb.bnode(); + kb.add(response2, ns.http('content'), kb.literal(xhr.responseText), response2); + if (xhr.statusText) { + kb.add(response2, ns.http('statusText'), kb.literal(xhr.statusText), response2); + } + // dump("HTTP >= 400 responseText:\n"+xhr.responseText+"\n"); // @@@@ + } + sf.failFetch(xhr, 'HTTP error for ' + xhr.resource + ': ' + xhr.status + ' ' + xhr.statusText); + return; + } - var tree = statementListToXMLTree(sts); - var str = '']; // @@ namespace declrations - return XMLtreeToString(tree2, -1); - }; // End @@ body + // deduce some things from the HTTP transaction + var addType = function addType(cla) { + // add type to all redirected resources too + var prev = thisReq; + if (loc) { + var docURI = kb.any(prev, ns.link('requestedURI')); + if (docURI !== loc) { + kb.add(kb.sym(loc), ns.rdf('type'), cla, sf.appNode); + } + } + for (;;) { + var doc = kb.any(prev, ns.link('requestedURI')); + if (doc && doc.value) { + kb.add(kb.sym(doc.value), ns.rdf('type'), cla, sf.appNode); + } // convert Literal + prev = kb.any(undefined, kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), prev); + if (!prev) break; + var response = kb.any(prev, kb.sym('http://www.w3.org/2007/ont/link#response')); + if (!response) break; + var redirection = kb.any(response, kb.sym('http://www.w3.org/2007/ont/http#status')); + if (!redirection) break; + if (redirection !== '301' && redirection !== '302') break; + } + }; + // This is a minimal set to allow the use of damaged servers if necessary + var extensionToContentType = { + 'rdf': 'application/rdf+xml', 'owl': 'application/rdf+xml', + 'n3': 'text/n3', 'ttl': 'text/turtle', 'nt': 'text/n3', 'acl': 'text/n3', + 'html': 'text/html', + 'xml': 'text/xml' + }; + var guess; + if (xhr.status === 200) { + addType(ns.link('Document')); + var ct = xhr.headers['content-type']; + if (options.forceContentType) { + xhr.headers['content-type'] = options.forceContentType; + } + if (!ct || ct.indexOf('application/octet-stream') >= 0) { + guess = extensionToContentType[xhr.resource.uri.split('.').pop()]; + if (guess) { + xhr.headers['content-type'] = guess; + } + } + if (ct) { + if (ct.indexOf('image/') === 0 || ct.indexOf('application/pdf') === 0) addType(kb.sym('http://purl.org/dc/terms/Image')); + } + if (options.clearPreviousData) { + // Before we parse new data clear old but only on 200 + kb.removeDocument(xhr.resource); + } + } + // application/octet-stream; charset=utf-8 - var Serializer = function Serializer(store) { - return new __Serializer(store); - }; - return Serializer; -}(); + if (Uri.protocol(xhr.resource.uri) === 'file' || Uri.protocol(xhr.resource.uri) === 'chrome') { + if (options.forceContentType) { + xhr.headers['content-type'] = options.forceContentType; + } else { + guess = extensionToContentType[xhr.resource.uri.split('.').pop()]; + if (guess) { + xhr.headers['content-type'] = guess; + } else { + xhr.headers['content-type'] = 'text/xml'; + } + } + } -module.exports = Serializer; -},{"./blank-node":42,"./named-node":57,"./uri":72,"./util":73,"./xsd":75}],68:[function(_dereq_,module,exports){ -'use strict'; + // If we have alread got the thing at this location, abort + if (loc) { + var udoc = Uri.join(xhr.resource.uri, loc); + if (!force && udoc !== xhr.resource.uri && sf.requested[udoc] && sf.requested[udoc] === 'done') { + // we have already fetched this in fact. + // should we smush too? + // log.info("HTTP headers indicate we have already" + " retrieved " + xhr.resource + " as " + udoc + ". Aborting.") + sf.doneFetch(xhr); + xhr.abort(); + return; + } + sf.requested[udoc] = true; + } -// Converting between SPARQL queries and the $rdf query API -/* + for (var x = 0; x < sf.handlers.length; x++) { + if (xhr.headers['content-type'] && xhr.headers['content-type'].match(sf.handlers[x].pattern)) { + handler = new sf.handlers[x](); + break; + } + } -function SQuery () { - this.terms = [] - return this -} + sf.parseLinkHeader(xhr, thisReq); -STerm.prototype.toString = STerm.val -SQuery.prototype.add = function (str) {this.terms.push()}*/ + if (handler) { + try { + handler.handlerFactory(xhr); + } catch (e) { + // Try to avoid silent errors + sf.failFetch(xhr, 'Exception handling content-type ' + xhr.headers['content-type'] + ' was: ' + e); + } + } else { + sf.doneFetch(xhr); // Not a problem, we just don't extract data. + /* + // sf.failFetch(xhr, "Unhandled content type: " + xhr.headers['content-type']+ + // ", readyState = "+xhr.readyState) + */ + return; + } + }; -var log = _dereq_('./log'); -var Query = _dereq_('./query').Query; -// const Fetcher = require('./fetcher') + // DONE: 4 + // HEADERS_RECEIVED: 2 + // LOADING: 3 + // OPENED: 1 + // UNSENT: 0 -/** - * @SPARQL: SPARQL text that is converted to a query object which is returned. - * @testMode: testing flag. Prevents loading of sources. - */ -function SPARQLToQuery(SPARQL, testMode, kb) { - // AJAR_ClearTable() - var variableHash = []; - function makeVar(name) { - if (variableHash[name]) { - return variableHash[name]; - } - var newVar = kb.variable(name); - variableHash[name] = newVar; - return newVar; - } + // log.debug("web.js: XHR " + xhr.resource.uri + ' readyState='+xhr.readyState); // @@@@ comment me out - // term type functions - function isRealText(term) { - return typeof term === 'string' && term.match(/[^ \n\t]/); - } - function isVar(term) { - return typeof term === 'string' && term.match(/^[\?\$]/); - } - function fixSymbolBrackets(term) { - if (typeof term === 'string') { - return term.replace(/^</, '<').replace(/>$/, '>'); - } else { - return term; - } - } - function isSymbol(term) { - return typeof term === 'string' && term.match(/^<[^>]*>$/); - } - function isBnode(term) { - return typeof term === 'string' && (term.match(/^_:/) || term.match(/^$/)); - } - function isPrefix(term) { - return typeof term === 'string' && term.match(/:$/); - } - function isPrefixedSymbol(term) { - return typeof term === 'string' && term.match(/^:|^[^_][^:]*:/); - } - function getPrefix(term) { - var a = term.split(':'); - return a[0]; - } - function getSuffix(term) { - var a = term.split(':'); - return a[1]; - } - function removeBrackets(term) { - if (isSymbol(term)) { - return term.slice(1, term.length - 1); - } else { - return term; - } - } - // takes a string and returns an array of strings and Literals in the place of literals - function parseLiterals(str) { - // var sin = (str.indexOf(/[ \n]\'/)==-1)?null:str.indexOf(/[ \n]\'/), doub = (str.indexOf(/[ \n]\"/)==-1)?null:str.indexOf(/[ \n]\"/) - var sin = str.indexOf("'") === -1 ? null : str.indexOf("'"); - var doub = str.indexOf('"') === -1 ? null : str.indexOf('"'); - // alert("S: "+sin+" D: "+doub) - if (!sin && !doub) { - var a = new Array(1); - a[0] = str; - return a; - } - var res = new Array(2); - var br; - var ind; - if (!sin || doub && doub < sin) { - br = '"'; - ind = doub; - } else if (!doub || sin && sin < doub) { - br = "'"; - ind = sin; - } else { - log.error('SQARQL QUERY OOPS!'); - return res; - } - res[0] = str.slice(0, ind); - var end = str.slice(ind + 1).indexOf(br); - if (end === -1) { - log.error('SPARQL parsing error: no matching parentheses in literal ' + str); - return str; - } - // alert(str.slice(end + ind + 2).match(/^\^\^/)) - var end2; - if (str.slice(end + ind + 2).match(/^\^\^/)) { - end2 = str.slice(end + ind + 2).indexOf(' '); - // alert(end2) - res[1] = kb.literal(str.slice(ind + 1, ind + 1 + end), '', kb.sym(removeBrackets(str.slice(ind + 4 + end, ind + 2 + end + end2)))); - // alert(res[1].datatype.uri) - res = res.concat(parseLiterals(str.slice(end + ind + 3 + end2))); - } else if (str.slice(end + ind + 2).match(/^@/)) { - end2 = str.slice(end + ind + 2).indexOf(' '); - // alert(end2) - res[1] = kb.literal(str.slice(ind + 1, ind + 1 + end), str.slice(ind + 3 + end, ind + 2 + end + end2), null); - // alert(res[1].datatype.uri) - res = res.concat(parseLiterals(str.slice(end + ind + 2 + end2))); - } else { - res[1] = kb.literal(str.slice(ind + 1, ind + 1 + end), '', null); - log.info('Literal found: ' + res[1]); - res = res.concat(parseLiterals(str.slice(end + ind + 2))); // finds any other literals - } - return res; - } + switch (xhr.readyState) { + case 0: + var uri = xhr.resource.uri; + var newURI; + if (this.crossSiteProxyTemplate && typeof document !== 'undefined' && document.location) { + // In mashup situation + var hostpart = Uri.hostpart; + var here = '' + document.location; + if (hostpart(here) && hostpart(uri) && hostpart(here) !== hostpart(uri)) { + newURI = this.crossSiteProxyTemplate.replace('{uri}', encodeURIComponent(uri)); + sf.addStatus(xhr.req, 'BLOCKED -> Cross-site Proxy to <' + newURI + '>'); + if (xhr.aborted) return; - function spaceDelimit(str) { - str = str.replace(/\(/g, ' ( ').replace(/\)/g, ' ) ').replace(//g, '> ').replace(/{/g, ' { ').replace(/}/g, ' } ').replace(/[\t\n\r]/g, ' ').replace(/; /g, ' ; ').replace(/\. /g, ' . ').replace(/, /g, ' , '); - log.info('New str into spaceDelimit: \n' + str); - var res = []; - var br = str.split(' '); - for (var x in br) { - if (isRealText(br[x])) { - res = res.concat(br[x]); - } - } - return res; - } + var kb = sf.store; + var oldreq = xhr.req; + kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), oldreq); - function replaceKeywords(input) { - var strarr = input; - for (var x = 0; x < strarr.length; x++) { - if (strarr[x] === 'a') { - strarr[x] = ''; - } - if (strarr[x] === 'is' && strarr[x + 2] === 'of') { - strarr.splice(x, 1); - strarr.splice(x + 1, 1); - var s = strarr[x - 1]; - strarr[x - 1] = strarr[x + 1]; - strarr[x + 1] = s; - } - } - return strarr; - } + // //////////// Change the request node to a new one: @@@@@@@@@@@@ Duplicate? + var newreq = xhr.req = kb.bnode(); // Make NEW reqest for everything else + kb.add(oldreq, ns.http('redirectedRequest'), newreq, xhr.req); - function toTerms(input) { - var res = []; - for (var x = 0; x < input.length; x++) { - if (typeof input[x] !== 'string') { - res[x] = input[x]; - continue; - } - input[x] = fixSymbolBrackets(input[x]); - if (isVar(input[x])) { - res[x] = makeVar(input[x].slice(1)); - } else if (isBnode(input[x])) { - log.info(input[x] + ' was identified as a bnode.'); - res[x] = kb.bnode(); - } else if (isSymbol(input[x])) { - log.info(input[x] + ' was identified as a symbol.'); - res[x] = kb.sym(removeBrackets(input[x])); - } else if (isPrefixedSymbol(input[x])) { - log.info(input[x] + ' was identified as a prefixed symbol'); - if (prefixes[getPrefix(input[x])]) { - res[x] = kb.sym(input[x] = prefixes[getPrefix(input[x])] + getSuffix(input[x])); - } else { - log.error('SPARQL error: ' + input[x] + ' with prefix ' + getPrefix(input[x]) + ' does not have a correct prefix entry.'); - res[x] = input[x]; - } - } else { - res[x] = input[x]; - } - } - return res; - } + var now = new Date(); + var timeNow = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '] '; + kb.add(newreq, ns.rdfs('label'), kb.literal(timeNow + ' Request for ' + newURI), this.appNode); + kb.add(newreq, ns.link('status'), kb.collection(), this.appNode); + kb.add(newreq, ns.link('requestedURI'), kb.literal(newURI), this.appNode); - function tokenize(str) { - var token1 = parseLiterals(str); - var token2 = []; - for (var x in token1) { - if (typeof token1[x] === 'string') { - token2 = token2.concat(spaceDelimit(token1[x])); - } else { - token2 = token2.concat(token1[x]); - } - } - token2 = replaceKeywords(token2); - log.info('SPARQL Tokens: ' + token2); - return token2; - } + var response = kb.bnode(); + kb.add(oldreq, ns.link('response'), response); + // kb.add(response, ns.http('status'), kb.literal(xhr.status), response) + // if (xhr.statusText) kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response) - // CASE-INSENSITIVE - function arrayIndexOf(str, arr) { - for (var i = 0; i < arr.length; i++) { - if (typeof arr[i] !== 'string') { - continue; - } - if (arr[i].toLowerCase() === str.toLowerCase()) { - return i; - } - } - // log.warn("No instance of "+str+" in array "+arr) - return null; - } + xhr.abort(); + xhr.aborted = true; + xhr.redirected = true; - // CASE-INSENSITIVE - function arrayIndicesOf(str, arr) { - var ind = []; - for (var i = 0; i < arr.length; i++) { - if (typeof arr[i] !== 'string') { - continue; - } - if (arr[i].toLowerCase() === str.toLowerCase()) { - ind.push(i); - } - } - return ind; - } + sf.addStatus(oldreq, 'redirected XHR'); // why - function setVars(input, query) { - log.info('SPARQL vars: ' + input); - for (var x in input) { - if (isVar(input[x])) { - log.info('Added ' + input[x] + ' to query variables from SPARQL'); - var v = makeVar(input[x].slice(1)); - query.vars.push(v); - v.label = input[x].slice(1); - } else { - log.warn('Incorrect SPARQL variable in SELECT: ' + input[x]); - } - } - } + if (sf.fetchCallbacks[xhr.resource.uri]) { + if (!sf.fetchCallbacks[newURI]) { + sf.fetchCallbacks[newURI] = []; + } + sf.fetchCallbacks[newURI] === sf.fetchCallbacks[newURI].concat(sf.fetchCallbacks[xhr.resource.uri]); + delete sf.fetchCallbacks[xhr.resource.uri]; + } - function getPrefixDeclarations(input) { - var prefInd = arrayIndicesOf('PREFIX', input); - var res = []; - for (var i in prefInd) { - var a = input[prefInd[i] + 1]; - var b = input[prefInd[i] + 2]; - if (!isPrefix(a)) { - log.error('Invalid SPARQL prefix: ' + a); - } else if (!isSymbol(b)) { - log.error('Invalid SPARQL symbol: ' + b); - } else { - log.info('Prefix found: ' + a + ' -> ' + b); - var pref = getPrefix(a); - var symbol = removeBrackets(b); - res[pref] = symbol; - } - } - return res; - } + sf.fireCallbacks('redirected', args); // Are these args right? @@@ + sf.requested[xhr.resource.uri] = 'redirected'; - function getMatchingBracket(arr, open, close) { - log.info('Looking for a close bracket of type ' + close + ' in ' + arr); - var index = 0; - for (var i = 0; i < arr.length; i++) { - if (arr[i] === open) { - index++; - } - if (arr[i] === close) { - index--; - } - if (index < 0) { - return i; - } - } - log.error('Statement had no close parenthesis in SPARQL query'); - return 0; - } + var xhr2 = sf.requestURI(newURI, xhr.resource, xhr.options || {}, xhr.userCallback); + if (xhr2 && xhr2.req) { + kb.add(xhr.req, kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), xhr2.req, sf.appNode); + return; + } + } + } + sf.failFetch(xhr, 'HTTP Blocked. (ReadyState 0) Cross-site violation for <' + docuri + '>'); - function constraintGreaterThan(value) { - this.describe = function (varstr) { - return varstr + ' > ' + value.toNT(); - }; - this.test = function (term) { - if (term.value.match(/[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/)) { - return parseFloat(term.value) > parseFloat(value); - } else { - return term.toNT() > value.toNT(); - } - }; - return this; - } + break; - function constraintLessThan(value) { - // this is not the recommended usage. Should only work on literal, numeric, dateTime - this.describe = function (varstr) { - return varstr + ' < ' + value.toNT(); - }; - this.test = function (term) { - // this.describe = function (varstr) { return varstr + " < "+value } - if (term.value.match(/[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/)) { - return parseFloat(term.value) < parseFloat(value); - } else { - return term.toNT() < value.toNT(); - } - }; - return this; - } - // This should only work on literals but doesn't. - function ConstraintEqualTo(value) { - this.describe = function (varstr) { - return varstr + ' = ' + value.toNT(); - }; - this.test = function (term) { - return value.sameTerm(term); + case 3: + // Intermediate state -- 3 may OR MAY NOT be called, selon browser. + // handleResponse(); // In general it you can't do it yet as the headers are in but not the data + break; + case 4: + // Final state for this XHR but may be redirected + handleResponse(); + // Now handle + if (xhr.handle && xhr.responseText !== undefined) { + // can be validly zero length + if (sf.requested[xhr.resource.uri] === 'redirected') { + break; + } + sf.fireCallbacks('load', args); + xhr.handle(function () { + sf.doneFetch(xhr); + }); + } else { + if (xhr.redirected) { + sf.addStatus(xhr.req, 'Aborted and redirected to new request.'); + } else { + sf.addStatus(xhr.req, 'Fetch over. No data handled. Aborted = ' + xhr.aborted); + } + // sf.failFetch(xhr, "HTTP failed unusually. (no handler set) (x-site violation? no net?) for <"+ + // docuri+">") + } + break; + } // switch + }; }; - return this; - } - // value must be a literal - function ConstraintRegexp(value) { - this.describe = function (varstr) { - return "REGEXP( '" + value + "' , " + varstr + ' )'; - }; - this.test = function (term) { - var str = value; - // str = str.replace(/^//,"").replace(//$/,"") - var rg = new RegExp(str); - if (term.value) { - return rg.test(term.value); + // Map the URI to a localhost proxy if we are running on localhost + // This is used for working offline, e.g. on planes. + // Is the script istelf is running in localhost, then access all data in a localhost mirror. + // Do not remove without checking with TimBL + var uri2 = docuri; + if (typeof tabulator !== 'undefined' && tabulator.preferences.get('offlineModeUsingLocalhost')) { + if (uri2.slice(0, 7) === 'http://' && uri2.slice(7, 17) !== 'localhost/') { + uri2 = 'http://localhost/' + uri2.slice(7); + log.warn('Localhost kludge for offline use: actually getting <' + uri2 + '>'); } else { - return false; + // log.warn("Localhost kludge NOT USED <" + uri2 + ">") } - }; - } + } else {} + // log.warn("Localhost kludge OFF offline use: actually getting <" + uri2 + ">") - function setConstraint(input, pat) { - if (input.length === 3 && input[0].termType === 'Variable' && (input[2].termType === 'NamedNode' || input[2].termType === 'Literal')) { - if (input[1] === '=') { - log.debug('Constraint added: ' + input); - pat.constraints[input[0]] = new ConstraintEqualTo(input[2]); - } else if (input[1] === '>') { - log.debug('Constraint added: ' + input); - pat.constraints[input[0]] = new ConstraintEqualTo(input[2]); - } else if (input[1] === '<') { - log.debug('Constraint added: ' + input); - pat.constraints[input[0]] = new ConstraintEqualTo(input[2]); - } else { - log.warn("I don't know how to handle the constraint: " + input); - } - } else if (input.length === 6 && typeof input[0] === 'string' && input[0].toLowerCase() === 'regexp' && input[1] === '(' && input[5] === ')' && input[3] === ',' && input[4].termType === 'Variable' && input[2].termType === 'Literal') { - log.debug('Constraint added: ' + input); - pat.constraints[input[4]] = new ConstraintRegexp(input[2].value); + // 2014 probelm: + // XMLHttpRequest cannot load http://www.w3.org/People/Berners-Lee/card. + // A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. + // @ Many ontology files under http: and need CORS wildcard -> can't have withCredentials + + var withCredentials = uri2.slice(0, 6) === 'https:'; // @@ Kludge -- need for webid which typically is served from https + if (options.withCredentials !== undefined) { + withCredentials = options.withCredentials; } - // log.warn("I don't know how to handle the constraint: "+input) - // alert("length: "+input.length+" input 0 type: "+input[0].termType+" input 1: "+input[1]+" input[2] type: "+input[2].termType) - } + var actualProxyURI = this.proxyIfNecessary(uri2); - function setOptional(terms, pat) { - log.debug('Optional query: ' + terms + ' not yet implemented.'); - var opt = kb.formula(); - setWhere(terms, opt); - pat.optional.push(opt); - } + // Setup the request + // var xhr + // xhr = Util.XMLHTTPFactory() + xhr.onerror = onerrorFactory(xhr); + xhr.onreadystatechange = onreadystatechangeFactory(xhr); + xhr.timeout = sf.timeout; + xhr.withCredentials = withCredentials; + xhr.actualProxyURI = actualProxyURI; - function setWhere(input, pat) { - var terms = toTerms(input); - var end; - log.debug('WHERE: ' + terms); - var opt; - // var opt = arrayIndicesOf("OPTIONAL",terms) - while (arrayIndexOf('OPTIONAL', terms)) { - opt = arrayIndexOf('OPTIONAL', terms); - log.debug('OPT: ' + opt + ' ' + terms[opt] + ' in ' + terms); - if (terms[opt + 1] !== '{') { - log.warn('Bad optional opening bracket in word ' + opt); - } - end = getMatchingBracket(terms.slice(opt + 2), '{', '}'); - if (end === -1) { - log.error('No matching bracket in word ' + opt); - } else { - setOptional(terms.slice(opt + 2, opt + 2 + end), pat); - // alert(pat.statements[0].toNT()) - opt = arrayIndexOf('OPTIONAL', terms); - end = getMatchingBracket(terms.slice(opt + 2), '{', '}'); - terms.splice(opt, end + 3); - } + xhr.req = req; + xhr.options = options; + xhr.options = options; + xhr.resource = docterm; + xhr.requestedURI = uri2; + + xhr.ontimeout = function () { + sf.failFetch(xhr, 'requestTimeout'); + }; + try { + xhr.open('GET', actualProxyURI, this.async); + } catch (er) { + return this.failFetch(xhr, 'XHR open for GET failed for <' + uri2 + '>:\n\t' + er); } - log.debug('WHERE after optionals: ' + terms); - while (arrayIndexOf('FILTER', terms)) { - var filt = arrayIndexOf('FILTER', terms); - if (terms[filt + 1] !== '(') { - log.warn('Bad filter opening bracket in word ' + filt); - } - end = getMatchingBracket(terms.slice(filt + 2), '(', ')'); - if (end === -1) { - log.error('No matching bracket in word ' + filt); - } else { - setConstraint(terms.slice(filt + 2, filt + 2 + end), pat); - filt = arrayIndexOf('FILTER', terms); - end = getMatchingBracket(terms.slice(filt + 2), '(', ')'); - terms.splice(filt, end + 3); - } + if (force) { + // must happen after open + xhr.setRequestHeader('Cache-control', 'no-cache'); } - log.debug('WHERE after filters and optionals: ' + terms); - extractStatements(terms, pat); - } - function extractStatements(terms, formula) { - var arrayZero = new Array(1); - arrayZero[0] = -1; // this is just to add the beginning of the where to the periods index. - var per = arrayZero.concat(arrayIndicesOf('.', terms)); - var stat = []; - for (var x = 0; x < per.length - 1; x++) { - stat[x] = terms.slice(per[x] + 1, per[x + 1]); - } - // Now it's in an array of statements - for (x in stat) { - // THIS MUST BE CHANGED FOR COMMA, SEMICOLON - log.info('s+p+o ' + x + ' = ' + stat[x]); - var subj = stat[x][0]; - stat[x].splice(0, 1); - var sem = arrayZero.concat(arrayIndicesOf(';', stat[x])); - sem.push(stat[x].length); - var stat2 = []; - for (var y = 0; y < sem.length - 1; y++) { - stat2[y] = stat[x].slice(sem[y] + 1, sem[y + 1]); - } - for (x in stat2) { - log.info('p+o ' + x + ' = ' + stat[x]); - var pred = stat2[x][0]; - stat2[x].splice(0, 1); - var com = arrayZero.concat(arrayIndicesOf(',', stat2[x])); - com.push(stat2[x].length); - var stat3 = []; - for (y = 0; y < com.length - 1; y++) { - stat3[y] = stat2[x].slice(com[y] + 1, com[y + 1]); + // Set redirect callback and request headers -- alas Firefox Extension Only + if (typeof tabulator !== 'undefined' && tabulator.isExtension && xhr.channel && (Uri.protocol(xhr.resource.uri) === 'http' || Uri.protocol(xhr.resource.uri) === 'https')) { + try { + xhr.channel.notificationCallbacks = { + getInterface: function getInterface(iid) { + if (iid.equals(Components.interfaces.nsIChannelEventSink)) { + return { + onChannelRedirect: function onChannelRedirect(oldC, newC, flags) { + if (xhr.aborted) return; + var kb = sf.store; + var newURI = newC.URI.spec; + var oldreq = xhr.req; + if (!xhr.options.noMeta) { + sf.addStatus(xhr.req, 'Redirected: ' + xhr.status + ' to <' + newURI + '>'); + kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), xhr.req); + + // //////////// Change the request node to a new one: @@@@@@@@@@@@ Duplicate code? + var newreq = xhr.req = kb.bnode(); // Make NEW reqest for everything else + kb.add(oldreq, ns.http('redirectedRequest'), newreq, this.appNode); + + var now = new Date(); + var timeNow = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '] '; + kb.add(newreq, ns.rdfs('label'), kb.literal(timeNow + ' Request for ' + newURI), this.appNode); + kb.add(newreq, ns.link('status'), kb.collection(), this.appNode); + kb.add(newreq, ns.link('requestedURI'), kb.literal(newURI), this.appNode); + // ///////////// + + // // log.info('@@ sources onChannelRedirect'+ + // "Redirected: "+ + // xhr.status + " to <" + newURI + ">"); //@@ + var response = kb.bnode(); + // kb.add(response, ns.http('location'), newURI, response); Not on this response + kb.add(oldreq, ns.link('response'), response); + kb.add(response, ns.http('status'), kb.literal(xhr.status), response); + if (xhr.statusText) kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response); + } + if (xhr.status - 0 !== 303) kb.HTTPRedirects[xhr.resource.uri] = newURI; // same document as + if (xhr.status - 0 === 301 && rterm) { + // 301 Moved + var badDoc = Uri.docpart(rterm.uri); + var msg = 'Warning: ' + xhr.resource + ' has moved to <' + newURI + '>.'; + if (rterm) { + msg += ' Link in <' + badDoc + ' >should be changed'; + kb.add(badDoc, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg, sf.appNode); + } + // dump(msg+"\n") + } + xhr.abort(); + xhr.aborted = true; + + if (sf.fetchCallbacks[xhr.resource.uri]) { + if (!sf.fetchCallbacks[newURI]) { + sf.fetchCallbacks[newURI] = []; + } + sf.fetchCallbacks[newURI] === sf.fetchCallbacks[newURI].concat(sf.fetchCallbacks[xhr.resource.uri]); + delete sf.fetchCallbacks[xhr.resource.uri]; + } + + sf.addStatus(oldreq, 'redirected'); // why + sf.fireCallbacks('redirected', args); // Are these args right? @@@ + sf.requested[xhr.resource.uri] = 'redirected'; + sf.redirectedTo[xhr.resource.uri] = newURI; + + var hash = newURI.indexOf('#'); + if (hash >= 0) { + if (!xhr.options.noMeta) { + kb.add(xhr.resource, kb.sym('http://www.w3.org/2007/ont/link#warning'), 'Warning: ' + xhr.resource + ' HTTP redirects to' + newURI + ' which should not contain a "#" sign'); + } + newURI = newURI.slice(0, hash); + } + var xhr2 = sf.requestURI(newURI, xhr.resource, xhr.options, xhr.userCallback); + if (xhr2 && xhr2.req && !options.noMeta) { + kb.add(xhr.req, kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), xhr2.req, sf.appNode); + } + // else dump("No xhr.req available for redirect from "+xhr.resource+" to "+newURI+"\n") + }, + + // See https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIChannelEventSink + asyncOnChannelRedirect: function asyncOnChannelRedirect(oldC, newC, flags, callback) { + if (xhr.aborted) return; + var kb = sf.store; + var newURI = newC.URI.spec; + var oldreq = xhr.req; + sf.addStatus(xhr.req, 'Redirected: ' + xhr.status + ' to <' + newURI + '>'); + kb.add(oldreq, ns.http('redirectedTo'), kb.sym(newURI), xhr.req); + + // //////////// Change the request node to a new one: @@@@@@@@@@@@ Duplicate? + var newreq = xhr.req = kb.bnode(); // Make NEW reqest for everything else + // xhr.resource = docterm + // xhr.requestedURI = args[0] + + // kb.add(kb.sym(newURI), ns.link("request"), req, this.appNode) + kb.add(oldreq, ns.http('redirectedRequest'), newreq, xhr.req); + + var now = new Date(); + var timeNow = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '] '; + kb.add(newreq, ns.rdfs('label'), kb.literal(timeNow + ' Request for ' + newURI), this.appNode); + kb.add(newreq, ns.link('status'), kb.collection(), this.appNode); + kb.add(newreq, ns.link('requestedURI'), kb.literal(newURI), this.appNode); + // ///////////// + + // // log.info('@@ sources onChannelRedirect'+ + // "Redirected: "+ + // xhr.status + " to <" + newURI + ">"); //@@ + var response = kb.bnode(); + // kb.add(response, ns.http('location'), newURI, response); Not on this response + kb.add(oldreq, ns.link('response'), response); + kb.add(response, ns.http('status'), kb.literal(xhr.status), response); + if (xhr.statusText) kb.add(response, ns.http('statusText'), kb.literal(xhr.statusText), response); + + if (xhr.status - 0 !== 303) kb.HTTPRedirects[xhr.resource.uri] = newURI; // same document as + if (xhr.status - 0 === 301 && rterm) { + // 301 Moved + var badDoc = Uri.docpart(rterm.uri); + var msg = 'Warning: ' + xhr.resource + ' has moved to <' + newURI + '>.'; + if (rterm) { + msg += ' Link in <' + badDoc + ' >should be changed'; + kb.add(badDoc, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg, sf.appNode); + } + // dump(msg+"\n") + } + xhr.abort(); + xhr.aborted = true; + + var hash = newURI.indexOf('#'); + if (hash >= 0) { + var msg2 = 'Warning: ' + xhr.resource + ' HTTP redirects to' + newURI + ' which do not normally contain a "#" sign'; + // dump(msg+"\n") + kb.add(xhr.resource, kb.sym('http://www.w3.org/2007/ont/link#warning'), msg2); + newURI = newURI.slice(0, hash); + } + /* + if (sf.fetchCallbacks[xhr.resource.uri]) { + if (!sf.fetchCallbacks[newURI]) { + sf.fetchCallbacks[newURI] = [] + } + sf.fetchCallbacks[newURI] = sf.fetchCallbacks[newURI].concat(sf.fetchCallbacks[xhr.resource.uri]) + delete sf.fetchCallbacks[xhr.resource.uri] + } + */ + sf.requested[xhr.resource.uri] = 'redirected'; + sf.redirectedTo[xhr.resource.uri] = newURI; + + var xhr2 = sf.requestURI(newURI, xhr.resource, xhr.options, xhr.userCallback); + if (xhr2) { + // may be no XHR is other URI already loaded + xhr2.original = xhr.original; // use this for finding base + if (xhr2.req) { + kb.add(xhr.req, kb.sym('http://www.w3.org/2007/ont/link#redirectedRequest'), xhr2.req, sf.appNode); + } + } + // else dump("No xhr.req available for redirect from "+xhr.resource+" to "+newURI+"\n") + } // asyncOnChannelRedirect + }; + } + return Components.results.NS_NOINTERFACE; + } + }; + } catch (err) { + return sf.failFetch(xhr, "@@ Couldn't set callback for redirects: " + err); + } // try + } // if Firefox extension + + try { + var acceptstring = ''; + for (var type in this.mediatypes) { + // var attrstring = '' + if (acceptstring !== '') { + acceptstring += ', '; } - for (x in stat3) { - var obj = stat3[x][0]; - log.info('Subj=' + subj + ' Pred=' + pred + ' Obj=' + obj); - formula.add(subj, pred, obj); + acceptstring += type; + for (var attr in this.mediatypes[type]) { + acceptstring += ';' + attr + '=' + this.mediatypes[type][attr]; } } + xhr.setRequestHeader('Accept', acceptstring); + this.addStatus(xhr.req, 'Accept: ' + acceptstring); + + // if (requester) { xhr.setRequestHeader('Referer',requester) } + } catch (err) { + throw new Error("Can't set Accept header: " + err); } - } - // ******************************* Body of SPARQLToQuery ***************************// - log.info('SPARQL input: \n' + SPARQL); - var q = new Query(); - var sp = tokenize(SPARQL); // first tokenize everything - var prefixes = getPrefixDeclarations(sp); - if (!prefixes.rdf) { - prefixes.rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; - } - if (!prefixes.rdfs) { - prefixes.rdfs = 'http://www.w3.org/2000/01/rdf-schema#'; - } - var selectLoc = arrayIndexOf('SELECT', sp); - var whereLoc = arrayIndexOf('WHERE', sp); - if (selectLoc < 0 || whereLoc < 0 || selectLoc > whereLoc) { - log.error('Invalid or nonexistent SELECT and WHERE tags in SPARQL query'); - return false; - } - setVars(sp.slice(selectLoc + 1, whereLoc), q); + // Fire + try { + xhr.send(null); + } catch (er) { + return this.failFetch(xhr, 'XHR send failed:' + er); + } + setTimeout(function () { + if (xhr.readyState !== 4 && sf.isPending(xhr.resource.uri)) { + sf.failFetch(xhr, 'requestTimeout'); + } + }, this.timeout); + this.addStatus(xhr.req, 'HTTP Request sent.'); + return xhr; + }; // this.requestURI() - setWhere(sp.slice(whereLoc + 2, sp.length - 1), q.pat); + this.objectRefresh = function (term) { + var uris = kb.uris(term); // Get all URIs + if (typeof uris !== 'undefined') { + for (var i = 0; i < uris.length; i++) { + this.refresh(this.store.sym(Uri.docpart(uris[i]))); + // what about rterm? + } + } + }; - if (testMode) { - return q; - } + // deprecated -- use IndexedFormula.removeDocument(doc) + this.unload = function (term) { + this.store.removeMany(undefined, undefined, undefined, term); + delete this.requested[term.uri]; // So it can be loaded again + }; - for (var x in q.pat.statements) { - var st = q.pat.statements[x]; - if (st.subject.termType === 'NamedNode') { - /* && sf.isPending(st.subject.uri) */ // This doesn't work. - // sf.requestURI(st.subject.uri,"sparql:"+st.subject) Kenny: I remove these two - if (kb.fetcher) { - kb.fetcher.lookUpThing(st.subject, 'sparql:' + st.subject); - } + this.refresh = function (term, userCallback) { + // sources_refresh + this.fireCallbacks('refresh', arguments); + this.requestURI(term.uri, undefined, { force: true, clearPreviousData: true }, userCallback); + }; + + this.retract = function (term) { + // sources_retract + this.store.removeMany(undefined, undefined, undefined, term); + if (term.uri) { + delete this.requested[Uri.docpart(term.uri)]; } - if (st.object.termType === 'NamedNode') { - /* && sf.isPending(st.object.uri) */ - // sf.requestURI(st.object.uri,"sparql:"+st.object) - if (kb.fetcher) { - kb.fetcher.lookUpThing(st.object, 'sparql:' + st.object); - } + this.fireCallbacks('retract', arguments); + }; + + this.getState = function (docuri) { + if (typeof this.requested[docuri] === 'undefined') { + return 'unrequested'; + } else if (this.requested[docuri] === true) { + return 'requested'; + } else if (this.requested[docuri] === 'done') { + return 'fetched'; + } else if (this.requested[docuri] === 'redirected') { + return this.getState(this.redirectedTo[docuri]); + } else { + // An non-200 HTTP error status + return 'failed'; } - } - // alert(q.pat) - return q; - // checkVars() - // *******************************************************************// -} + }; -module.exports = SPARQLToQuery; -},{"./log":55,"./query":63}],69:[function(_dereq_,module,exports){ + // doing anyStatementMatching is wasting time + this.isPending = function (docuri) { + // sources_pending + // if it's not pending: false -> flailed 'done' -> done 'redirected' -> redirected + return this.requested[docuri] === true; + }; + // var updatesVia = new $rdf.UpdatesVia(this) // Subscribe to headers + // @@@@@@@@ This is turned off because it causes a websocket to be set up for ANY fetch + // whether we want to track it ot not. including ontologies loaed though the XSSproxy +}; // End of fetcher + +module.exports = Fetcher; +},{"./log":252,"./n3parser":253,"./named-node":254,"./namespace":255,"./parse":257,"./rdfaparser":261,"./rdfxmlparser":262,"./serialize":263,"./uri":269,"./util":270}],247:[function(_dereq_,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var BlankNode = _dereq_('./blank-node'); +var ClassOrder = _dereq_('./class-order'); +var Collection = _dereq_('./collection'); +var Literal = _dereq_('./literal'); +var log = _dereq_('./log'); +var NamedNode = _dereq_('./named-node'); var Node = _dereq_('./node'); +var Serializer = _dereq_('./serialize'); +var Statement = _dereq_('./statement'); +var Variable = _dereq_('./variable'); -var Statement = function () { - function Statement(subject, predicate, object, graph) { - _classCallCheck(this, Statement); +var Formula = function (_Node) { + _inherits(Formula, _Node); - this.subject = Node.fromValue(subject); - this.predicate = Node.fromValue(predicate); - this.object = Node.fromValue(object); - this.why = graph; // property currently used by rdflib + function Formula(statements, constraints, initBindings, optional) { + _classCallCheck(this, Formula); + + var _this = _possibleConstructorReturn(this, (Formula.__proto__ || Object.getPrototypeOf(Formula)).call(this)); + + _this.termType = Formula.termType; + _this.statements = statements || []; + _this.constraints = constraints || []; + _this.initBindings = initBindings || []; + _this.optional = optional || []; + return _this; } - _createClass(Statement, [{ - key: 'equals', - value: function equals(other) { - return other.subject.equals(this.subject) && other.predicate.equals(this.predicate) && other.object.equals(this.object) && other.graph.equals(this.graph); + _createClass(Formula, [{ + key: 'add', + value: function add(s, p, o, g) { + return this.statements.push(new Statement(s, p, o, g)); } }, { - key: 'substitute', - value: function substitute(bindings) { - var y = new Statement(this.subject.substitute(bindings), this.predicate.substitute(bindings), this.object.substitute(bindings), this.why.substitute(bindings)); // 2016 - console.log('@@@ statement substitute:' + y); - return y; + key: 'addStatement', + value: function addStatement(st) { + return this.statements.push(st); } }, { - key: 'toCanonical', - value: function toCanonical() { - var terms = [this.subject.toCanonical(), this.predicate.toCanonical(), this.object.toCanonical()]; - if (this.graph && this.graph.termType !== 'DefaultGraph') { - terms.push(this.graph.toCanonical()); + key: 'bnode', + value: function bnode(id) { + return new BlankNode(id); + } + /** + * Finds the types in the list which have no *stored* subtypes + * These are a set of classes which provide by themselves complete + * information -- the other classes are redundant for those who + * know the class DAG. + */ + + }, { + key: 'bottomTypeURIs', + value: function bottomTypeURIs(types) { + var bots; + var bottom; + var elt; + var i; + var k; + var len; + var ref; + var subs; + var v; + bots = []; + for (k in types) { + if (!types.hasOwnProperty(k)) continue; + v = types[k]; + subs = this.each(void 0, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), this.sym(k)); + bottom = true; + i = 0; + for (len = subs.length; i < len; i++) { + elt = subs[i]; + ref = elt.uri; + if (ref in types) { + // the subclass is one we know + bottom = false; + break; + } + } + if (bottom) { + bots[k] = v; + } } - return terms.join(' ') + ' .'; + return bots; } }, { - key: 'toNT', - value: function toNT() { - return [this.subject.toNT(), this.predicate.toNT(), this.object.toNT()].join(' ') + ' .'; + key: 'collection', + value: function collection() { + return new Collection(); } }, { - key: 'toString', - value: function toString() { - return this.toNT(); + key: 'each', + value: function each(s, p, o, g) { + var elt, i, l, m, q; + var len, len1, len2, len3; + var results = []; + var sts = this.statementsMatching(s, p, o, g, false); + if (s == null) { + for (i = 0, len = sts.length; i < len; i++) { + elt = sts[i]; + results.push(elt.subject); + } + } else if (p == null) { + for (l = 0, len1 = sts.length; l < len1; l++) { + elt = sts[l]; + results.push(elt.predicate); + } + } else if (o == null) { + for (m = 0, len2 = sts.length; m < len2; m++) { + elt = sts[m]; + results.push(elt.object); + } + } else if (g == null) { + for (q = 0, len3 = sts.length; q < len3; q++) { + elt = sts[q]; + results.push(elt.why); + } + } + return results; } }, { - key: 'graph', - get: function get() { - return this.why; - }, - set: function set(g) { - this.why = g; + key: 'equals', + value: function equals(other) { + if (!other) { + return false; + } + return this.hashString() === other.hashString(); } - }]); - - return Statement; -}(); - -module.exports = Statement; -},{"./node":59}],70:[function(_dereq_,module,exports){ -'use strict'; - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -var _indexedFormula = _dereq_('./indexed-formula'); - -var _indexedFormula2 = _interopRequireDefault(_indexedFormula); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -// Joe Presbrey -// 2007-07-15 -// 2010-08-08 TimBL folded in Kenny's WEBDAV -// 2010-12-07 TimBL addred local file write code -var docpart = _dereq_('./uri').docpart; -var Fetcher = _dereq_('./fetcher'); -var graph = _dereq_('./data-factory').graph; + /* + For thisClass or any subclass, anything which has it is its type + or is the object of something which has the type as its range, or subject + of something which has the type as its domain + We don't bother doing subproperty (yet?)as it doesn't seeem to be used much. + Get all the Classes of which we can RDFS-infer the subject is a member + @returns a hash of URIs + */ -var namedNode = _dereq_('./data-factory').namedNode; -var Namespace = _dereq_('./namespace'); -var Serializer = _dereq_('./serializer'); -var uriJoin = _dereq_('./uri').join; -var Util = _dereq_('./util'); + /** + * For thisClass or any subclass, anything which has it is its type + * or is the object of something which has the type as its range, or subject + * of something which has the type as its domain + * We don't bother doing subproperty (yet?)as it doesn't seeem to be used + * much. + * Get all the Classes of which we can RDFS-infer the subject is a member + * @return a hash of URIs + */ -var UpdateManager = function () { - var sparql = function sparql(store) { - this.store = store; - if (store.updater) { - throw new Error("You can't have two UpdateManagers for the same store"); - } - if (!store.fetcher) { - // The store must also/already have a fetcher - new Fetcher(store); + }, { + key: 'findMembersNT', + value: function findMembersNT(thisClass) { + var i; + var l; + var len; + var len1; + var len2; + var len3; + var len4; + var m; + var members; + var pred; + var q; + var ref; + var ref1; + var ref2; + var ref3; + var ref4; + var ref5; + var seeds; + var st; + var t; + var u; + seeds = {}; + seeds[thisClass.toNT()] = true; + members = {}; + ref = this.transitiveClosure(seeds, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), true); + for (t in ref) { + if (!ref.hasOwnProperty(t)) continue; + ref1 = this.statementsMatching(void 0, this.sym('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), this.fromNT(t)); + for (i = 0, len = ref1.length; i < len; i++) { + st = ref1[i]; + members[st.subject.toNT()] = st; + } + ref2 = this.each(void 0, this.sym('http://www.w3.org/2000/01/rdf-schema#domain'), this.fromNT(t)); + for (l = 0, len1 = ref2.length; l < len1; l++) { + pred = ref2[l]; + ref3 = this.statementsMatching(void 0, pred); + for (m = 0, len2 = ref3.length; m < len2; m++) { + st = ref3[m]; + members[st.subject.toNT()] = st; + } + } + ref4 = this.each(void 0, this.sym('http://www.w3.org/2000/01/rdf-schema#range'), this.fromNT(t)); + for (q = 0, len3 = ref4.length; q < len3; q++) { + pred = ref4[q]; + ref5 = this.statementsMatching(void 0, pred); + for (u = 0, len4 = ref5.length; u < len4; u++) { + st = ref5[u]; + members[st.object.toNT()] = st; + } + } + } + return members; } - store.updater = this; - this.ifps = {}; - this.fps = {}; - this.ns = {}; - this.ns.link = Namespace('http://www.w3.org/2007/ont/link#'); - this.ns.http = Namespace('http://www.w3.org/2007/ont/http#'); - this.ns.httph = Namespace('http://www.w3.org/2007/ont/httph#'); - this.ns.ldp = Namespace('http://www.w3.org/ns/ldp#'); - this.ns.rdf = Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#'); - this.ns.rdfs = Namespace('http://www.w3.org/2000/01/rdf-schema#'); - this.ns.rdf = Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#'); - this.ns.owl = Namespace('http://www.w3.org/2002/07/owl#'); - - this.patchControl = []; // index of objects fro coordinating incomng and outgoing patches - }; - - sparql.prototype.patchControlFor = function (doc) { - if (!this.patchControl[doc.uri]) { - this.patchControl[doc.uri] = []; + }, { + key: 'findMemberURIs', + value: function findMemberURIs(subject) { + return this.NTtoURI(this.findMembersNT(subject)); } - return this.patchControl[doc.uri]; - }; + /** + * Get all the Classes of which we can RDFS-infer the subject is a superclass + * Returns a hash table where key is NT of type and value is statement why we + * think so. + * Does NOT return terms, returns URI strings. + * We use NT representations in this version because they handle blank nodes. + */ - // Returns The method string SPARQL or DAV or LOCALFILE or false if known, undefined if not known. - // - // Files have to have a specific annotaton that they are machine written, for safety. - // We don't actually check for write access on files. - // - sparql.prototype.editable = function (uri, kb) { - if (!uri) { - return false; // Eg subject is bnode, no known doc to write to - } - if (!kb) { - kb = this.store; + }, { + key: 'findSubClassesNT', + value: function findSubClassesNT(subject) { + var types = {}; + types[subject.toNT()] = true; + return this.transitiveClosure(types, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), true); } + /** + * Get all the Classes of which we can RDFS-infer the subject is a subclass + * Returns a hash table where key is NT of type and value is statement why we + * think so. + * Does NOT return terms, returns URI strings. + * We use NT representations in this version because they handle blank nodes. + */ - if (uri.slice(0, 8) === 'file:///') { - if (kb.holds(kb.sym(uri), namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode('http://www.w3.org/2007/ont/link#MachineEditableDocument'))) { - return 'LOCALFILE'; - } - - var sts = kb.statementsMatching(kb.sym(uri), undefined, undefined); - - console.log('sparql.editable: Not MachineEditableDocument file ' + uri + '\n'); - console.log(sts.map(function (x) { - return x.toNT(); - }).join('\n')); - return false; - // @@ Would be nifty of course to see whether we actually have write acess first. + }, { + key: 'findSuperClassesNT', + value: function findSuperClassesNT(subject) { + var types = {}; + types[subject.toNT()] = true; + return this.transitiveClosure(types, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), false); } + /** + * Get all the Classes of which we can RDFS-infer the subject is a member + * todo: This will loop is there is a class subclass loop (Sublass loops are + * not illegal) + * Returns a hash table where key is NT of type and value is statement why we + * think so. + * Does NOT return terms, returns URI strings. + * We use NT representations in this version because they handle blank nodes. + */ - var request; - var definitive = false; - var requests = kb.each(undefined, this.ns.link('requestedURI'), docpart(uri)); - - // Hack for the moment @@@@ 2016-02-12 - if (kb.holds(namedNode(uri), this.ns.rdf('type'), this.ns.ldp('Resource'))) { - return 'SPARQL'; - } - var i; - var method; - for (var r = 0; r < requests.length; r++) { - request = requests[r]; - if (request !== undefined) { - var response = kb.any(request, this.ns.link('response')); - if (request !== undefined) { - var acceptPatch = kb.each(response, this.ns.httph('accept-patch')); - if (acceptPatch.length) { - for (i = 0; i < acceptPatch.length; i++) { - method = acceptPatch[i].value.trim(); - if (method.indexOf('application/sparql-update') >= 0) return 'SPARQL'; - } - } - var author_via = kb.each(response, this.ns.httph('ms-author-via')); - if (author_via.length) { - for (i = 0; i < author_via.length; i++) { - method = author_via[i].value.trim(); - if (method.indexOf('SPARQL') >= 0) { - return 'SPARQL'; - } - if (method.indexOf('DAV') >= 0) { - return 'DAV'; - } - } - } - var status = kb.each(response, this.ns.http('status')); - if (status.length) { - for (i = 0; i < status.length; i++) { - if (status[i] === 200 || status[i] === 404) { - definitive = true; - // return false // A definitive answer - } - } - } + }, { + key: 'findTypesNT', + value: function findTypesNT(subject) { + var domain; + var i; + var l; + var len; + var len1; + var len2; + var len3; + var m; + var q; + var range; + var rdftype; + var ref; + var ref1; + var ref2; + var ref3; + var st; + var types; + rdftype = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; + types = []; + ref = this.statementsMatching(subject, void 0, void 0); + for (i = 0, len = ref.length; i < len; i++) { + st = ref[i]; + if (st.predicate.uri === rdftype) { + types[st.object.toNT()] = st; } else { - console.log('sparql.editable: No response for ' + uri + '\n'); + ref1 = this.each(st.predicate, this.sym('http://www.w3.org/2000/01/rdf-schema#domain')); + for (l = 0, len1 = ref1.length; l < len1; l++) { + range = ref1[l]; + types[range.toNT()] = st; + } } } - } - if (requests.length === 0) { - console.log('sparql.editable: No request for ' + uri + '\n'); - } else { - if (definitive) { - return false; // We have got a request and it did NOT say editable => not editable + ref2 = this.statementsMatching(void 0, void 0, subject); + for (m = 0, len2 = ref2.length; m < len2; m++) { + st = ref2[m]; + ref3 = this.each(st.predicate, this.sym('http://www.w3.org/2000/01/rdf-schema#range')); + for (q = 0, len3 = ref3.length; q < len3; q++) { + domain = ref3[q]; + types[domain.toNT()] = st; + } } + return this.transitiveClosure(types, this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf'), false); } - console.log('sparql.editable: inconclusive for ' + uri + '\n'); - return undefined; // We don't know (yet) as we haven't had a response (yet) - }; - - // ///////// The identification of bnodes - - sparql.prototype.anonymize = function (obj) { - return obj.toNT().substr(0, 2) === '_:' && this._mentioned(obj) ? '?' + obj.toNT().substr(2) : obj.toNT(); - }; - - sparql.prototype.anonymizeNT = function (stmt) { - return this.anonymize(stmt.subject) + ' ' + this.anonymize(stmt.predicate) + ' ' + this.anonymize(stmt.object) + ' .'; - }; - - // A list of all bnodes occuring in a statement - sparql.prototype._statement_bnodes = function (st) { - return [st.subject, st.predicate, st.object].filter(function (x) { - return x.isBlank; - }); - }; - - // A list of all bnodes occuring in a list of statements - sparql.prototype._statement_array_bnodes = function (sts) { - var bnodes = []; - for (var i = 0; i < sts.length; i++) { - bnodes = bnodes.concat(this._statement_bnodes(sts[i])); - } - bnodes.sort(); // in place sort - result may have duplicates - var bnodes2 = []; - for (var j = 0; j < bnodes.length; j++) { - if (j === 0 || !bnodes[j].sameTerm(bnodes[j - 1])) { - bnodes2.push(bnodes[j]); - } + }, { + key: 'findTypeURIs', + value: function findTypeURIs(subject) { + return this.NTtoURI(this.findTypesNT(subject)); } - return bnodes2; - }; + // Trace the statements which connect directly, or through bnodes + // Returns an array of statements + // doc param may be null to search all documents in store - sparql.prototype._cache_ifps = function () { - // Make a cached list of [Inverse-]Functional properties - // Call this once before calling context_statements - this.ifps = {}; - var a = this.store.each(undefined, this.ns.rdf('type'), this.ns.owl('InverseFunctionalProperty')); - for (var i = 0; i < a.length; i++) { - this.ifps[a[i].uri] = true; + }, { + key: 'connectedStatements', + value: function connectedStatements(subject, doc, excludePredicateURIs) { + excludePredicateURIs = excludePredicateURIs || []; + var todo = [subject]; + var done = []; + var doneArcs = []; + var result = []; + var self = this; + var follow = function follow(x) { + var queue = function queue(x) { + if (x.termType === 'BlankNode' && !done[x.value]) { + done[x.value] = true; + todo.push(x); + } + }; + var sts = self.statementsMatching(null, null, x, doc).concat(self.statementsMatching(x, null, null, doc)); + sts = sts.filter(function (st) { + if (excludePredicateURIs[st.predicate.uri]) return false; + var hash = st.toNT(); + if (doneArcs[hash]) return false; + doneArcs[hash] = true; + return true; + }); + sts.forEach(function (st, i) { + queue(st.subject); + queue(st.object); + }); + result = result.concat(sts); + }; + while (todo.length) { + follow(todo.shift()); + } + // console.log('' + result.length + ' statements about ' + subject) + return result; } - this.fps = {}; - a = this.store.each(undefined, this.ns.rdf('type'), this.ns.owl('FunctionalProperty')); - for (i = 0; i < a.length; i++) { - this.fps[a[i].uri] = true; + }, { + key: 'formula', + value: function formula() { + return new Formula(); } - }; + /** + * Transforms an NTriples string format into a Node. + * The bnode bit should not be used on program-external values; designed + * for internal work such as storing a bnode id in an HTML attribute. + * This will only parse the strings generated by the vaious toNT() methods. + */ - // Returns a context to bind a given node, up to a given depth - sparql.prototype._bnode_context2 = function (x, source, depth) { - // Return a list of statements which indirectly identify a node - // Depth > 1 if try further indirection. - // Return array of statements (possibly empty), or null if failure - var sts = this.store.statementsMatching(undefined, undefined, x, source); // incoming links - var y; - var res; - for (var i = 0; i < sts.length; i++) { - if (this.fps[sts[i].predicate.uri]) { - y = sts[i].subject; - if (!y.isBlank) { - return [sts[i]]; - } - if (depth) { - res = this._bnode_context2(y, source, depth - 1); - if (res) { - return res.concat([sts[i]]); + }, { + key: 'fromNT', + value: function fromNT(str) { + var dt, k, lang, x; + switch (str[0]) { + case '<': + return this.sym(str.slice(1, -1)); + case '"': + lang = void 0; + dt = void 0; + k = str.lastIndexOf('"'); + if (k < str.length - 1) { + if (str[k + 1] === '@') { + lang = str.slice(k + 2); + } else if (str.slice(k + 1, k + 3) === '^^') { + dt = this.fromNT(str.slice(k + 3)); + } else { + throw new Error("Can't convert string from NT: " + str); + } } - } + str = str.slice(1, k); + str = str.replace(/\\"/g, '"'); + str = str.replace(/\\n/g, '\n'); + str = str.replace(/\\\\/g, '\\'); + return this.literal(str, lang, dt); + case '_': + x = new BlankNode(); + x.id = parseInt(str.slice(3), 10); + BlankNode.nextId--; + return x; + case '?': + return new Variable(str.slice(1)); } + throw new Error("Can't convert from NT: " + str); } - // outgoing links - sts = this.store.statementsMatching(x, undefined, undefined, source); - for (i = 0; i < sts.length; i++) { - if (this.ifps[sts[i].predicate.uri]) { - y = sts[i].object; - if (!y.isBlank) { - return [sts[i]]; + }, { + key: 'holds', + value: function holds(s, p, o, g) { + var i; + if (arguments.length === 1) { + if (!s) { + return true; } - if (depth) { - res = this._bnode_context2(y, source, depth - 1); - if (res) { - return res.concat([sts[i]]); + if (s instanceof Array) { + for (i = 0; i < s.length; i++) { + if (!this.holds(s[i])) { + return false; + } } + return true; + } else if (s instanceof Statement) { + return this.holds(s.subject, s.predicate, s.object, s.why); + } else if (s.statements) { + return this.holds(s.statements); } } - } - return null; // Failure - }; - // Returns the smallest context to bind a given single bnode - sparql.prototype._bnode_context_1 = function (x, source) { - // Return a list of statements which indirectly identify a node - // Breadth-first - var self = this; - for (var depth = 0; depth < 3; depth++) { - // Try simple first - var con = this._bnode_context2(x, source, depth); - if (con !== null) return con; + var st = this.anyStatementMatching(s, p, o, g); + return st != null; } - // If we can't guarantee unique with logic just send all info about node - return this.store.connectedStatements(x, source); // was: - // throw new Error('Unable to uniquely identify bnode: ' + x.toNT()) - }; - - sparql.prototype._mentioned = function (x) { - return this.store.statementsMatching(x).length !== 0 || // Don't pin fresh bnodes - this.store.statementsMatching(undefined, x).length !== 0 || this.store.statementsMatching(undefined, undefined, x).length !== 0; - }; + }, { + key: 'holdsStatement', + value: function holdsStatement(st) { + return this.holds(st.subject, st.predicate, st.object, st.why); + } + }, { + key: 'list', + value: function list(values) { + var collection = new Collection(); + values.forEach(function (val) { + collection.append(val); + }); + return collection; + } + }, { + key: 'literal', + value: function literal(val, lang, dt) { + return new Literal('' + val, lang, dt); + } + /** + * transform a collection of NTriple URIs into their URI strings + * @param t some iterable colletion of NTriple URI strings + * @return a collection of the URIs as strings + * todo: explain why it is important to go through NT + */ - sparql.prototype._bnode_context = function (bnodes, doc) { - var context = []; - if (bnodes.length) { - this._cache_ifps(); - for (var i = 0; i < bnodes.length; i++) { - // Does this occur in old graph? - var bnode = bnodes[i]; - if (!this._mentioned(bnode)) continue; - context = context.concat(this._bnode_context_1(bnode, doc)); + }, { + key: 'NTtoURI', + value: function NTtoURI(t) { + var k, v; + var uris = {}; + for (k in t) { + if (!t.hasOwnProperty(k)) continue; + v = t[k]; + if (k[0] === '<') { + uris[k.slice(1, -1)] = v; + } } + return uris; } - return context; - }; - - /* Weird code does not make sense -- some code corruption along the line -- st undefined -- weird - sparql.prototype._bnode_context = function(bnodes) { - var context = [] - if (bnodes.length) { - if (this.store.statementsMatching(st.subject.isBlank?undefined:st.subject, - st.predicate.isBlank?undefined:st.predicate, - st.object.isBlank?undefined:st.object, - st.why).length <= 1) { - context = context.concat(st) - } else { - this._cache_ifps() - for (x in bnodes) { - context = context.concat(this._bnode_context_1(bnodes[x], st.why)) - } - } - } - return context + }, { + key: 'serialize', + value: function serialize(base, contentType, provenance) { + var documentString; + var sts; + var sz; + sz = Serializer(this); + sz.suggestNamespaces(this.namespaces); + sz.setBase(base); + if (provenance) { + sts = this.statementsMatching(void 0, void 0, void 0, provenance); + } else { + sts = this.statements; } - */ - // Returns the best context for a single statement - sparql.prototype._statement_context = function (st) { - var bnodes = this._statement_bnodes(st); - return this._bnode_context(bnodes, st.why); - }; - - sparql.prototype._context_where = function (context) { - var sparql = this; - return !context || context.length === 0 ? '' : 'WHERE { ' + context.map(function (x) { - return sparql.anonymizeNT(x); - }).join('\n') + ' }\n'; - }; - - sparql.prototype._fire = function (uri, query, callback) { - if (!uri) { - throw new Error('No URI given for remote editing operation: ' + query); + switch (contentType != null ? contentType : 'text/n3') { + case 'application/rdf+xml': + documentString = sz.statementsToXML(sts); + break; + case 'text/n3': + case 'text/turtle': + documentString = sz.statementsToN3(sts); + break; + default: + throw new Error('serialize: Content-type ' + contentType + ' not supported.'); + } + return documentString; } - console.log('sparql: sending update to <' + uri + '>'); - var xhr = Util.XMLHTTPFactory(); - xhr.options = {}; - - xhr.onreadystatechange = function () { - // dump("SPARQL update ready state for <"+uri+"> readyState="+xhr.readyState+"\n"+query+"\n") - if (xhr.readyState === 4) { - var success = !xhr.status || xhr.status >= 200 && xhr.status < 300; - if (!success) { - console.log('sparql: update failed for <' + uri + '> status=' + xhr.status + ', ' + xhr.statusText + ', body length=' + xhr.responseText.length + '\n for query: ' + query); - } else { - console.log('sparql: update Ok for <' + uri + '>'); - } - callback(uri, success, xhr.responseText, xhr); + }, { + key: 'substitute', + value: function substitute(bindings) { + var statementsCopy = this.statements.map(function (ea) { + return ea.substitute(bindings); + }); + console.log('Formula subs statmnts:' + statementsCopy); + var y = new Formula(); + y.add(statementsCopy); + console.log('indexed-form subs formula:' + y); + return y; + } + }, { + key: 'sym', + value: function sym(uri, name) { + if (name) { + throw new Error('This feature (kb.sym with 2 args) is removed. Do not assume prefix mappings.'); } - }; - - xhr.open('PATCH', uri, true); // async=true - xhr.setRequestHeader('Content-type', 'application/sparql-update'); - xhr.send(query); - }; - - // This does NOT update the statement. - // It returns an object whcih includes - // function which can be used to change the object of the statement. - // - sparql.prototype.update_statement = function (statement) { - if (statement && !statement.why) { - return; + return new NamedNode(uri); } - var sparql = this; - var context = this._statement_context(statement); - - return { - statement: statement ? [statement.subject, statement.predicate, statement.object, statement.why] : undefined, - statementNT: statement ? this.anonymizeNT(statement) : undefined, - where: sparql._context_where(context), - - set_object: function set_object(obj, callback) { - var query = this.where; - query += 'DELETE DATA { ' + this.statementNT + ' } ;\n'; - query += 'INSERT DATA { ' + this.anonymize(this.statement[0]) + ' ' + this.anonymize(this.statement[1]) + ' ' + this.anonymize(obj) + ' ' + ' . }\n'; - - sparql._fire(this.statement[3].uri, query, callback); + }, { + key: 'the', + value: function the(s, p, o, g) { + var x = this.any(s, p, o, g); + if (x == null) { + log.error('No value found for the() {' + s + ' ' + p + ' ' + o + '}.'); } - }; - }; - - sparql.prototype.insert_statement = function (st, callback) { - var st0 = st instanceof Array ? st[0] : st; - var query = this._context_where(this._statement_context(st0)); - - if (st instanceof Array) { - var stText = ''; - for (var i = 0; i < st.length; i++) { - stText += st[i] + '\n'; - }query += 'INSERT DATA { ' + stText + ' }\n'; - } else { - query += 'INSERT DATA { ' + this.anonymize(st.subject) + ' ' + this.anonymize(st.predicate) + ' ' + this.anonymize(st.object) + ' ' + ' . }\n'; + return x; } + /** + * RDFS Inference + * These are hand-written implementations of a backward-chaining reasoner + * over the RDFS axioms. + * @param seeds {Object} a hash of NTs of classes to start with + * @param predicate The property to trace though + * @param inverse trace inverse direction + */ - this._fire(st0.why.uri, query, callback); - }; - - sparql.prototype.delete_statement = function (st, callback) { - var st0 = st instanceof Array ? st[0] : st; - var query = this._context_where(this._statement_context(st0)); - - if (st instanceof Array) { - var stText = ''; - for (var i = 0; i < st.length; i++) { - stText += st[i] + '\n'; - }query += 'DELETE DATA { ' + stText + ' }\n'; - } else { - query += 'DELETE DATA { ' + this.anonymize(st.subject) + ' ' + this.anonymize(st.predicate) + ' ' + this.anonymize(st.object) + ' ' + ' . }\n'; + }, { + key: 'transitiveClosure', + value: function transitiveClosure(seeds, predicate, inverse) { + var elt, i, len, s, sups, t; + var agenda = {}; + Object.assign(agenda, seeds); // make a copy + var done = {}; // classes we have looked up + while (true) { + t = function () { + for (var p in agenda) { + if (!agenda.hasOwnProperty(p)) continue; + return p; + } + }(); + if (t == null) { + return done; + } + sups = inverse ? this.each(void 0, predicate, this.fromNT(t)) : this.each(this.fromNT(t), predicate); + for (i = 0, len = sups.length; i < len; i++) { + elt = sups[i]; + s = elt.toNT(); + if (s in done) { + continue; + } + if (s in agenda) { + continue; + } + agenda[s] = agenda[t]; + } + done[t] = agenda[t]; + delete agenda[t]; + } } + /** + * Finds the types in the list which have no *stored* supertypes + * We exclude the universal class, owl:Things and rdf:Resource, as it is + * information-free. + */ - this._fire(st0.why.uri, query, callback); - }; - - // Request a now or future action to refresh changes coming downstream - // - // This is designed to allow the system to re-request the server version, - // when a websocket has pinged to say there are changes. - // If thewebsocket, by contrast, has sent a patch, then this may not be necessary. - // This may be called out of context so *this* cannot be used. - - sparql.prototype.requestDownstreamAction = function (doc, action) { - var control = this.patchControlFor(doc); - if (!control.pendingUpstream) { - action(doc); - } else { - if (control.downstreamAction) { - if (control.downstreamAction === action) { - return; - } else { - throw new Error("Can't wait for > 1 differnt downstream actions"); + }, { + key: 'topTypeURIs', + value: function topTypeURIs(types) { + var i; + var j; + var k; + var len; + var n; + var ref; + var tops; + var v; + tops = []; + for (k in types) { + if (!types.hasOwnProperty(k)) continue; + v = types[k]; + n = 0; + ref = this.each(this.sym(k), this.sym('http://www.w3.org/2000/01/rdf-schema#subClassOf')); + for (i = 0, len = ref.length; i < len; i++) { + j = ref[i]; + if (j.uri !== 'http://www.w3.org/2000/01/rdf-schema#Resource') { + n++; + break; + } + } + if (!n) { + tops[k] = v; } - } else { - control.downstreamAction = action; } + if (tops['http://www.w3.org/2000/01/rdf-schema#Resource']) { + delete tops['http://www.w3.org/2000/01/rdf-schema#Resource']; + } + if (tops['http://www.w3.org/2002/07/owl#Thing']) { + delete tops['http://www.w3.org/2002/07/owl#Thing']; + } + return tops; } - }; - - // We want to start counting websockt notifications - // to distinguish the ones from others from our own. - sparql.prototype.clearUpstreamCount = function (doc) { - var control = this.patchControlFor(doc); - control.upstreamCount = 0; - }; + }, { + key: 'toString', + value: function toString() { + return '{' + this.statements.join('\n') + '}'; + } + }, { + key: 'whether', + value: function whether(s, p, o, g) { + return this.statementsMatching(s, p, o, g, false).length; + } + }]); - sparql.prototype.getUpdatesVia = function (doc) { - var linkHeaders = this.store.fetcher.getHeader(doc, 'updates-via'); - if (!linkHeaders || !linkHeaders.length) return null; - return linkHeaders[0].trim(); - }; + return Formula; +}(Node); - sparql.prototype.addDownstreamChangeListener = function (doc, listener) { - var control = this.patchControlFor(doc); - if (!control.downstreamChangeListeners) control.downstreamChangeListeners = []; - control.downstreamChangeListeners.push(listener); - var self = this; - this.setRefreshHandler(doc, function (doc) { - // a function not a method - self.reloadAndSync(doc); - }); - }; +Formula.termType = 'Graph'; - sparql.prototype.reloadAndSync = function (doc) { - var control = this.patchControlFor(doc); - var updater = this; +Formula.prototype.classOrder = ClassOrder['Graph']; +Formula.prototype.isVar = 0; - if (control.reloading) { - console.log(' Already reloading - stop'); - return; // once only needed - } - control.reloading = true; - var retryTimeout = 1000; // ms - var tryReload = function tryReload() { - console.log('try reload - timeout = ' + retryTimeout); - updater.reload(updater.store, doc, function (ok, message, xhr) { - control.reloading = false; - if (ok) { - if (control.downstreamChangeListeners) { - for (var i = 0; i < control.downstreamChangeListeners.length; i++) { - console.log(' Calling downstream listener ' + i); - control.downstreamChangeListeners[i](); - } - } - } else { - if (xhr.status === 0) { - console.log('Network error refreshing the data. Retrying in ' + retryTimeout / 1000); - control.reloading = true; - retryTimeout = retryTimeout * 2; - setTimeout(tryReload, retryTimeout); - } else { - console.log('Error ' + xhr.status + 'refreshing the data:' + message + '. Stopped' + doc); - } - } - }); - }; - tryReload(); - }; +Formula.prototype.ns = _dereq_('./namespace'); +Formula.prototype.variable = function (name) { + return new Variable(name); +}; - // Set up websocket to listen on - // - // There is coordination between upstream changes and downstream ones - // so that a reload is not done in the middle of an upsteeam patch. - // If you usie this API then you get called when a change happens, and you - // have to reload the file yourself, and then refresh the UI. - // Alternative is addDownstreamChangeListener(), where you do not - // have to do the reload yourslf. Do mot mix them. - // - // kb contains the HTTP metadata from prefvious operations - // - sparql.prototype.setRefreshHandler = function (doc, handler) { - var wssURI = this.getUpdatesVia(doc); // relative - // var kb = this.store - var theHandler = handler; - var self = this; - var updater = this; - var retryTimeout = 1500; // *2 will be 3 Seconds, 6, 12, etc - var retries = 0; +module.exports = Formula; +},{"./blank-node":239,"./class-order":240,"./collection":241,"./literal":251,"./log":252,"./named-node":254,"./namespace":255,"./node":256,"./serialize":263,"./statement":266,"./variable":271}],248:[function(_dereq_,module,exports){ +'use strict'; - if (!wssURI) { - console.log('Server doies not support live updates thoughUpdates-Via :-('); - return false; - } +var _indexedFormula = _dereq_('./indexed-formula'); - wssURI = uriJoin(wssURI, doc.uri); - wssURI = wssURI.replace(/^http:/, 'ws:').replace(/^https:/, 'wss:'); - console.log('Web socket URI ' + wssURI); +var _indexedFormula2 = _interopRequireDefault(_indexedFormula); - var openWebsocket = function openWebsocket() { - // From https://github.com/solid/solid-spec#live-updates - var socket; - if (typeof WebSocket !== 'undefined') { - socket = new WebSocket(wssURI); - } else if (typeof Services !== 'undefined') { - // Firefox add on http://stackoverflow.com/questions/24244886/is-websocket-supported-in-firefox-for-android-addons - socket = Services.wm.getMostRecentWindow('navigator:browser').WebSocket(wssURI); - } else if (typeof window !== 'undefined' && window.WebSocket) { - socket = window.WebSocket(wssURI); - } else { - console.log('Live update disabled, as WebSocket not supported by platform :-('); - return; - } - socket.onopen = function () { - console.log(' websocket open'); - retryTimeout = 1500; // reset timeout to fast on success - this.send('sub ' + doc.uri); - if (retries) { - console.log('Web socket has been down, better check for any news.'); - updater.requestDownstreamAction(doc, theHandler); - } - }; - var control = self.patchControlFor(doc); - control.upstreamCount = 0; +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - // https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent - // - // 1000 CLOSE_NORMAL Normal closure; the connection successfully completed whatever purpose for which it was created. - // 1001 CLOSE_GOING_AWAY The endpoint is going away, either - // because of a server failure or because the browser is navigating away from the page that opened the connection. - // 1002 CLOSE_PROTOCOL_ERROR The endpoint is terminating the connection due to a protocol error. - // 1003 CLOSE_UNSUPPORTED The connection is being terminated because the endpoint - // received data of a type it cannot accept (for example, a text-only endpoint received binary data). - // 1004 Reserved. A meaning might be defined in the future. - // 1005 CLOSE_NO_STATUS Reserved. Indicates that no status code was provided even though one was expected. - // 1006 CLOSE_ABNORMAL Reserved. Used to indicate that a connection was closed abnormally ( - // - // - socket.onclose = function (event) { - console.log('*** Websocket closed with code ' + event.code + ", reason '" + event.reason + "' clean = " + event.clean); - retryTimeout *= 2; - retries += 1; - console.log('Retrying in ' + retryTimeout + 'ms'); // (ask user?) - setTimeout(function () { - console.log('Trying websocket again'); - openWebsocket(); - }, retryTimeout); - }; - socket.onmessage = function (msg) { - if (msg.data && msg.data.slice(0, 3) === 'pub') { - if ('upstreamCount' in control) { - control.upstreamCount -= 1; - if (control.upstreamCount >= 0) { - console.log('just an echo: ' + control.upstreamCount); - return; // Just an echo - } - } - console.log('Assume a real downstream change: ' + control.upstreamCount + ' -> 0'); - control.upstreamCount = 0; - self.requestDownstreamAction(doc, theHandler); - } - }; - }; // openWebsocket - openWebsocket(); +var $rdf = { + BlankNode: _dereq_('./blank-node'), + Collection: _dereq_('./collection'), + convert: _dereq_('./convert'), + DataFactory: _dereq_('./data-factory'), + Empty: _dereq_('./empty'), + Fetcher: _dereq_('./fetcher'), + Formula: _dereq_('./formula'), + IndexedFormula: _indexedFormula2.default, + jsonParser: _dereq_('./jsonparser'), + Literal: _dereq_('./literal'), + log: _dereq_('./log'), + N3Parser: _dereq_('./n3parser'), + NamedNode: _dereq_('./named-node'), + Namespace: _dereq_('./namespace'), + Node: _dereq_('./node'), + parse: _dereq_('./parse'), + Query: _dereq_('./query').Query, + queryToSPARQL: _dereq_('./query-to-sparql'), + RDFaProcessor: _dereq_('./rdfaparser'), + RDFParser: _dereq_('./rdfxmlparser'), + serialize: _dereq_('./serialize'), + Serializer: _dereq_('./serializer'), + SPARQLToQuery: _dereq_('./sparql-to-query'), + sparqlUpdateParser: _dereq_('./patch-parser'), + Statement: _dereq_('./statement'), + term: _dereq_('./node').fromValue, + UpdateManager: _dereq_('./update-manager'), + UpdatesSocket: _dereq_('./updates-via').UpdatesSocket, + UpdatesVia: _dereq_('./updates-via').UpdatesVia, + uri: _dereq_('./uri'), + Util: _dereq_('./util'), + Variable: _dereq_('./variable') +}; - return true; - }; +$rdf.NextId = $rdf.BlankNode.nextId; - // This high-level function updates the local store iff the web is changed successfully. - // - // - deletions, insertions may be undefined or single statements or lists or formulae. - // (may contain bnodes which can be indirectly identified by a where clause) - // - // - callback is called as callback(uri, success, errorbody) - // - sparql.prototype.update = function (deletions, insertions, callback) { - try { - var kb = this.store; - var ds = !deletions ? [] : deletions instanceof _indexedFormula2.default ? deletions.statements : deletions instanceof Array ? deletions : [deletions]; - var is = !insertions ? [] : insertions instanceof _indexedFormula2.default ? insertions.statements : insertions instanceof Array ? insertions : [insertions]; - if (!(ds instanceof Array)) { - throw new Error('Type Error ' + (typeof ds === 'undefined' ? 'undefined' : _typeof(ds)) + ': ' + ds); - } - if (!(is instanceof Array)) { - throw new Error('Type Error ' + (typeof is === 'undefined' ? 'undefined' : _typeof(is)) + ': ' + is); - } - if (ds.length === 0 && is.length === 0) { - return callback(null, true); // success -- nothing needed to be done. - } - var doc = ds.length ? ds[0].why : is[0].why; - var control = this.patchControlFor(doc); - var startTime = Date.now(); +$rdf.fromNT = $rdf.Formula.prototype.fromNT; +$rdf.fetcher = $rdf.DataFactory.fetcher; +$rdf.graph = $rdf.DataFactory.graph; +$rdf.lit = $rdf.DataFactory.lit; +$rdf.st = $rdf.DataFactory.st; +$rdf.sym = $rdf.DataFactory.namedNode; +$rdf.variable = $rdf.DataFactory.variable; - var props = ['subject', 'predicate', 'object', 'why']; - var verbs = ['insert', 'delete']; - var clauses = { 'delete': ds, 'insert': is }; - verbs.map(function (verb) { - clauses[verb].map(function (st) { - if (!doc.sameTerm(st.why)) { - throw new Error('update: destination ' + doc + ' inconsistent with delete quad ' + st.why); - } - props.map(function (prop) { - if (typeof st[prop] === 'undefined') { - throw new Error('update: undefined ' + prop + ' of statement.'); - } - }); - }); - }); +// RDFJS DataFactory interface +$rdf.blankNode = $rdf.DataFactory.blankNode; +$rdf.defaultGraph = $rdf.DataFactory.defaultGraph; +$rdf.literal = $rdf.DataFactory.literal; +$rdf.namedNode = $rdf.DataFactory.namedNode; +$rdf.quad = $rdf.DataFactory.quad; +$rdf.triple = $rdf.DataFactory.triple; - var protocol = this.editable(doc.uri, kb); - if (!protocol) { - throw new Error("Can't make changes in uneditable " + doc); - } - var i; - var newSts; - var documentString; - var sz; - if (protocol.indexOf('SPARQL') >= 0) { - var bnodes = []; - if (ds.length) bnodes = this._statement_array_bnodes(ds); - if (is.length) bnodes = bnodes.concat(this._statement_array_bnodes(is)); - var context = this._bnode_context(bnodes, doc); - var whereClause = this._context_where(context); - var query = ''; - if (whereClause.length) { - // Is there a WHERE clause? - if (ds.length) { - query += 'DELETE { '; - for (i = 0; i < ds.length; i++) { - query += this.anonymizeNT(ds[i]) + '\n'; - } - query += ' }\n'; - } - if (is.length) { - query += 'INSERT { '; - for (i = 0; i < is.length; i++) { - query += this.anonymizeNT(is[i]) + '\n'; - } - query += ' }\n'; - } - query += whereClause; - } else { - // no where clause - if (ds.length) { - query += 'DELETE DATA { '; - for (i = 0; i < ds.length; i++) { - query += this.anonymizeNT(ds[i]) + '\n'; - } - query += ' } \n'; - } - if (is.length) { - if (ds.length) query += ' ; '; - query += 'INSERT DATA { '; - for (i = 0; i < is.length; i++) { - query += this.anonymizeNT(is[i]) + '\n'; - } - query += ' }\n'; - } - } - // Track pending upstream patches until they have fnished their callback - control.pendingUpstream = control.pendingUpstream ? control.pendingUpstream + 1 : 1; - if ('upstreamCount' in control) { - control.upstreamCount += 1; // count changes we originated ourselves - console.log('upstream count up to : ' + control.upstreamCount); - } +module.exports = $rdf; +},{"./blank-node":239,"./collection":241,"./convert":242,"./data-factory":243,"./empty":245,"./fetcher":246,"./formula":247,"./indexed-formula":249,"./jsonparser":250,"./literal":251,"./log":252,"./n3parser":253,"./named-node":254,"./namespace":255,"./node":256,"./parse":257,"./patch-parser":258,"./query":260,"./query-to-sparql":259,"./rdfaparser":261,"./rdfxmlparser":262,"./serialize":263,"./serializer":264,"./sparql-to-query":265,"./statement":266,"./update-manager":267,"./updates-via":268,"./uri":269,"./util":270,"./variable":271}],249:[function(_dereq_,module,exports){ +'use strict'; - this._fire(doc.uri, query, function (uri, success, body, xhr) { - xhr.elapsedTime_ms = Date.now() - startTime; - console.log(' sparql: Return ' + (success ? 'success' : 'FAILURE ' + xhr.status) + ' elapsed ' + xhr.elapsedTime_ms + 'ms'); - if (success) { - try { - kb.remove(ds); - } catch (e) { - success = false; - body = 'Remote Ok BUT error deleting ' + ds.length + ' from store!!! ' + e; - } // Add in any case -- help recover from weirdness?? - for (var i = 0; i < is.length; i++) { - kb.add(is[i].subject, is[i].predicate, is[i].object, doc); - } - } +Object.defineProperty(exports, "__esModule", { + value: true +}); - callback(uri, success, body, xhr); - control.pendingUpstream -= 1; - // When upstream patches have been sent, reload state if downstream waiting - if (control.pendingUpstream === 0 && control.downstreamAction) { - var downstreamAction = control.downstreamAction; - delete control.downstreamAction; - console.log('delayed downstream action:'); - downstreamAction(doc); - } - }); - } else if (protocol.indexOf('DAV') >= 0) { - // The code below is derived from Kenny's UpdateCenter.js - documentString; - var request = kb.any(doc, this.ns.link('request')); - if (!request) { - throw new Error('No record of our HTTP GET request for document: ' + doc); - } // should not happen - var response = kb.any(request, this.ns.link('response')); - if (!response) { - return null; // throw "No record HTTP GET response for document: "+doc - } - var content_type = kb.the(response, this.ns.httph('content-type')).value; +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - // prepare contents of revised document - newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // copy! - for (i = 0; i < ds.length; i++) { - Util.RDFArrayRemove(newSts, ds[i]); - } - for (i = 0; i < is.length; i++) { - newSts.push(is[i]); - } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - // serialize to te appropriate format - sz = Serializer(kb); - sz.suggestNamespaces(kb.namespaces); - sz.setBase(doc.uri); // ?? beware of this - kenny (why? tim) - switch (content_type) { - case 'application/rdf+xml': - documentString = sz.statementsToXML(newSts); - break; - case 'text/n3': - case 'text/turtle': - case 'application/x-turtle': // Legacy - case 'application/n3': - // Legacy - documentString = sz.statementsToN3(newSts); - break; - default: - throw new Error('Content-type ' + content_type + ' not supported for data write'); - } +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - // Write the new version back +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - var candidateTarget = kb.the(response, this.ns.httph('content-location')); - var targetURI; - if (candidateTarget) { - targetURI = uriJoin(candidateTarget.value, targetURI); - } - var xhr = Util.XMLHTTPFactory(); - xhr.options = {}; - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - // formula from sparqlUpdate.js, what about redirects? - var success = !xhr.status || xhr.status >= 200 && xhr.status < 300; - if (success) { - for (var i = 0; i < ds.length; i++) { - kb.remove(ds[i]); - } - for (i = 0; i < is.length; i++) { - kb.add(is[i].subject, is[i].predicate, is[i].object, doc); - } - } - callback(doc.uri, success, xhr.responseText); - } - }; - xhr.open('PUT', targetURI, true); - // assume the server does PUT content-negotiation. - xhr.setRequestHeader('Content-type', content_type); // OK? - xhr.send(documentString); - } else { - if (protocol.indexOf('LOCALFILE') >= 0) { - try { - console.log('Writing back to local file\n'); - // See http://simon-jung.blogspot.com/2007/10/firefox-extension-file-io.html - // prepare contents of revised document - newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // copy! - for (i = 0; i < ds.length; i++) { - Util.RDFArrayRemove(newSts, ds[i]); - } - for (i = 0; i < is.length; i++) { - newSts.push(is[i]); - } - // serialize to the appropriate format - documentString; - sz = Serializer(kb); - sz.suggestNamespaces(kb.namespaces); - sz.setBase(doc.uri); // ?? beware of this - kenny (why? tim) - var dot = doc.uri.lastIndexOf('.'); - if (dot < 1) { - throw new Error('Rewriting file: No filename extension: ' + doc.uri); - } - var ext = doc.uri.slice(dot + 1); - switch (ext) { - case 'rdf': - case 'owl': // Just my experence ...@@ we should keep the format in which it was parsed - case 'xml': - documentString = sz.statementsToXML(newSts); - break; - case 'n3': - case 'nt': - case 'ttl': - documentString = sz.statementsToN3(newSts); - break; - default: - throw new Error('File extension .' + ext + ' not supported for data write'); - } - // Write the new version back - // create component for file writing - console.log('Writing back: <<<' + documentString + '>>>'); - var filename = doc.uri.slice(7); // chop off file:// leaving /path - // console.log("Writeback: Filename: "+filename+"\n") - var file = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile); - file.initWithPath(filename); - if (!file.exists()) { - throw new Error('Rewriting file <' + doc.uri + '> but it does not exist!'); - } - // { - // file.create( Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 420) - // } - // create file output stream and use write/create/truncate mode - // 0x02 writing, 0x08 create file, 0x20 truncate length if exist - var stream = Components.classes['@mozilla.org/network/file-output-stream;1'].createInstance(Components.interfaces.nsIFileOutputStream); +// Identity management and indexing for RDF +// +// This file provides IndexedFormula a formula (set of triples) which +// indexed by predicate, subject and object. +// +// It "smushes" (merges into a single node) things which are identical +// according to owl:sameAs or an owl:InverseFunctionalProperty +// or an owl:FunctionalProperty +// +// +// 2005-10 Written Tim Berners-Lee +// 2007 Changed so as not to munge statements from documents when smushing +// +// +/* jsl:option explicit */ +var ArrayIndexOf = _dereq_('./util').ArrayIndexOf; +var Formula = _dereq_('./formula'); +// const log = require('./log') +var RDFArrayRemove = _dereq_('./util').RDFArrayRemove; +var Statement = _dereq_('./statement'); +var Node = _dereq_('./node'); +var Variable = _dereq_('./variable'); - // Various JS systems object to 0666 in struct mode as dangerous - stream.init(file, 0x02 | 0x08 | 0x20, parseInt('0666', 8), 0); +var owl_ns = 'http://www.w3.org/2002/07/owl#'; +// var link_ns = 'http://www.w3.org/2007/ont/link#' - // write data to file then close output stream - stream.write(documentString, documentString.length); - stream.close(); +// Handle Functional Property +function handle_FP(formula, subj, pred, obj) { + var o1 = formula.any(subj, pred, undefined); + if (!o1) { + return false; // First time with this value + } + // log.warn("Equating "+o1.uri+" and "+obj.uri + " because FP "+pred.uri); //@@ + formula.equate(o1, obj); + return true; +} // handle_FP - for (i = 0; i < ds.length; i++) { - kb.remove(ds[i]); - } - for (i = 0; i < is.length; i++) { - kb.add(is[i].subject, is[i].predicate, is[i].object, doc); - } - callback(doc.uri, true, ''); // success! - } catch (e) { - callback(doc.uri, false, 'Exception trying to write back file <' + doc.uri + '>\n' - // + tabulator.Util.stackString(e)) - ); - } - } else { - throw new Error("Unhandled edit method: '" + protocol + "' for " + doc); - } - } - } catch (e) { - callback(undefined, false, 'Exception in update: ' + e + '\n' + $rdf.Util.stackString(e)); +// Handle Inverse Functional Property +function handle_IFP(formula, subj, pred, obj) { + var s1 = formula.any(undefined, pred, obj); + if (!s1) { + return false; // First time with this value + } + // log.warn("Equating "+s1.uri+" and "+subj.uri + " because IFP "+pred.uri); //@@ + formula.equate(s1, subj); + return true; +} // handle_IFP + +function handleRDFType(formula, subj, pred, obj, why) { + if (formula.typeCallback) { + formula.typeCallback(formula, obj, why); + } + + var x = formula.classActions[obj.hashString()]; + var done = false; + if (x) { + for (var i = 0; i < x.length; i++) { + done = done || x[i](formula, subj, pred, obj, why); } - }; // wnd update + } + return done; // statement given is not needed if true +} - // This suitable for an inital creation of a document - // - // data: string, or array of statements - // - sparql.prototype.put = function (doc, data, content_type, callback) { - var documentString; - var kb = this.store; +var IndexedFormula = function (_Formula) { + _inherits(IndexedFormula, _Formula); - if ((typeof data === 'undefined' ? 'undefined' : _typeof(data)) === _typeof('')) { - documentString = data; - } else { - // serialize to te appropriate format - var sz = Serializer(kb); - sz.suggestNamespaces(kb.namespaces); - sz.setBase(doc.uri); - switch (content_type) { - case 'application/rdf+xml': - documentString = sz.statementsToXML(data); - break; - case 'text/n3': - case 'text/turtle': - case 'application/x-turtle': // Legacy - case 'application/n3': - // Legacy - documentString = sz.statementsToN3(data); - break; - default: - throw new Error('Content-type ' + content_type + ' not supported for data PUT'); - } + // IN future - allow pass array of statements to constructor + function IndexedFormula(features) { + _classCallCheck(this, IndexedFormula); + + // this.statements = [] // As in Formula NO don't overwrite inherited + // this.optional = [] + + var _this = _possibleConstructorReturn(this, (IndexedFormula.__proto__ || Object.getPrototypeOf(IndexedFormula)).call(this)); + + _this.propertyActions = []; // Array of functions to call when getting statement with {s X o} + // maps to [f(F,s,p,o),...] + _this.classActions = []; // Array of functions to call when adding { s type X } + _this.redirections = []; // redirect to lexically smaller equivalent symbol + _this.aliases = []; // reverse mapping to redirection: aliases for this + _this.HTTPRedirects = []; // redirections we got from HTTP + _this.subjectIndex = []; // Array of statements with this X as subject + _this.predicateIndex = []; // Array of statements with this X as subject + _this.objectIndex = []; // Array of statements with this X as object + _this.whyIndex = []; // Array of statements with X as provenance + _this.index = [_this.subjectIndex, _this.predicateIndex, _this.objectIndex, _this.whyIndex]; + _this.namespaces = {}; // Dictionary of namespace prefixes + _this.features = features || ['sameAs', 'InverseFunctionalProperty', 'FunctionalProperty']; + _this.initPropertyActions(_this.features); + return _this; + } + + _createClass(IndexedFormula, [{ + key: 'substitute', + value: function substitute(bindings) { + var statementsCopy = this.statements.map(function (ea) { + return ea.substitute(bindings); + }); + // console.log('IndexedFormula subs statemnts:' + statementsCopy) + var y = new IndexedFormula(); + y.add(statementsCopy); + // console.log('indexed-form subs formula:' + y) + return y; } - var xhr = Util.XMLHTTPFactory(); - xhr.options = {}; - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - // formula from sparqlUpdate.js, what about redirects? - var success = !xhr.status || xhr.status >= 200 && xhr.status < 300; - if (success && typeof data !== 'string') { - data.map(function (st) { - kb.addStatement(st); + }, { + key: 'applyPatch', + value: function applyPatch(patch, target, patchCallback) { + // patchCallback(err) + var Query = _dereq_('./query').Query; + var targetKB = this; + var ds; + var binding = null; + + // /////////// Debug strings + /* + var bindingDebug = function (b) { + var str = '' + var v + for (v in b) { + if (b.hasOwnProperty(v)) { + str += ' ' + v + ' -> ' + b[v] + } + } + return str + } + */ + var doPatch = function doPatch(onDonePatch) { + if (patch['delete']) { + ds = patch['delete']; + // console.log(bindingDebug(binding)) + // console.log('ds before substitute: ' + ds) + if (binding) ds = ds.substitute(binding); + // console.log('applyPatch: delete: ' + ds) + ds = ds.statements; + var bad = []; + var ds2 = ds.map(function (st) { + // Find the actual statemnts in the store + var sts = targetKB.statementsMatching(st.subject, st.predicate, st.object, target); + if (sts.length === 0) { + // log.info("NOT FOUND deletable " + st) + bad.push(st); + return null; + } else { + // log.info("Found deletable " + st) + return sts[0]; + } + }); + if (bad.length) { + // console.log('Could not find to delete ' + bad.length + 'statements') + // console.log('despite ' + targetKB.statementsMatching(bad[0].subject, bad[0].predicate)[0]) + return patchCallback('Could not find to delete: ' + bad.join('\n or ')); + } + ds2.map(function (st) { + targetKB.remove(st); }); - // kb.fetcher.requested[doc.uri] = true // as though fetched } - if (success) { - delete kb.fetcher.nonexistant[doc.uri]; - delete kb.fetcher.requested[doc.uri]; - // @@ later we can fake it has been requestd if put gives us the header sand we save them. + if (patch['insert']) { + // log.info("doPatch insert "+patch['insert']) + ds = patch['insert']; + if (binding) ds = ds.substitute(binding); + ds = ds.statements; + ds.map(function (st) { + st.why = target; + targetKB.add(st.subject, st.predicate, st.object, st.why); + }); } - callback(doc.uri, success, xhr.responseText, xhr); - } - }; - xhr.open('PUT', doc.uri, true); - xhr.setRequestHeader('Content-type', content_type); - xhr.send(documentString); - }; + onDonePatch(); + }; + if (patch.where) { + // log.info("Processing WHERE: " + patch.where + '\n') + var query = new Query('patch'); + query.pat = patch.where; + query.pat.statements.map(function (st) { + st.why = target; + }); - // Reload a document. - // - // Fast and cheap, no metaata - // Measure times for the document - // Load it provisionally - // Don't delete the statemenst before the load, or it will leave a broken document - // in the meantime. + var bindingsFound = []; - sparql.prototype.reload = function (kb, doc, callback) { - var startTime = Date.now(); - // force sets no-cache and - kb.fetcher.nowOrWhenFetched(doc.uri, { force: true, noMeta: true, clearPreviousData: true }, function (ok, body, xhr) { - if (!ok) { - console.log(' ERROR reloading data: ' + body); - callback(false, 'Error reloading data: ' + body, xhr); - } else if (xhr.onErrorWasCalled || xhr.status !== 200) { - console.log(' Non-HTTP error reloading data! onErrorWasCalled=' + xhr.onErrorWasCalled + ' status: ' + xhr.status); - callback(false, 'Non-HTTP error reloading data: ' + body, xhr); + targetKB.query(query, function onBinding(binding) { + bindingsFound.push(binding); + // console.log(' got a binding: ' + bindingDebug(binding)) + }, targetKB.fetcher, function onDone() { + if (bindingsFound.length === 0) { + return patchCallback('No match found to be patched:' + patch.where); + } + if (bindingsFound.length > 1) { + return patchCallback('Patch ambiguous. No patch done.'); + } + binding = bindingsFound[0]; + doPatch(patchCallback); + }); } else { - var elapsedTime_ms = Date.now() - startTime; - if (!doc.reloadTime_total) doc.reloadTime_total = 0; - if (!doc.reloadTime_count) doc.reloadTime_count = 0; - doc.reloadTime_total += elapsedTime_ms; - doc.reloadTime_count += 1; - console.log(' Fetch took ' + elapsedTime_ms + 'ms, av. of ' + doc.reloadTime_count + ' = ' + doc.reloadTime_total / doc.reloadTime_count + 'ms.'); - callback(true); + doPatch(patchCallback); } - }); - }; + } + }, { + key: 'declareExistential', + value: function declareExistential(x) { + if (!this._existentialVariables) this._existentialVariables = []; + this._existentialVariables.push(x); + return x; + } + }, { + key: 'initPropertyActions', + value: function initPropertyActions(features) { + // If the predicate is #type, use handleRDFType to create a typeCallback on the object + this.propertyActions[''] = [handleRDFType]; - sparql.prototype.oldReload = function (kb, doc, callback) { - var g2 = graph(); // A separate store to hold the data as we load it - var f2 = fetcher(g2); - var startTime = Date.now(); - // force sets no-cache and - f2.nowOrWhenFetched(doc.uri, { force: true, noMeta: true, clearPreviousData: true }, function (ok, body, xhr) { - if (!ok) { - console.log(' ERROR reloading data: ' + body); - callback(false, 'Error reloading data: ' + body, xhr); - } else if (xhr.onErrorWasCalled || xhr.status !== 200) { - console.log(' Non-HTTP error reloading data! onErrorWasCalled=' + xhr.onErrorWasCalled + ' status: ' + xhr.status); - callback(false, 'Non-HTTP error reloading data: ' + body, xhr); - } else { - var sts1 = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // Take a copy!! - var sts2 = g2.statementsMatching(undefined, undefined, undefined, doc).slice(); - console.log(' replacing ' + sts1.length + ' with ' + sts2.length + ' out of total statements ' + kb.statements.length); - kb.remove(sts1); - kb.add(sts2); - var elapsedTime_ms = Date.now() - startTime; - if (sts2.length === 0) { - console.log('????????????????? 0000000'); - } - if (!doc.reloadTime_total) doc.reloadTime_total = 0; - if (!doc.reloadTime_count) doc.reloadTime_count = 0; - doc.reloadTime_total += elapsedTime_ms; - doc.reloadTime_count += 1; - console.log(' fetch took ' + elapsedTime_ms + 'ms, av. of ' + doc.reloadTime_count + ' = ' + doc.reloadTime_total / doc.reloadTime_count + 'ms.'); - callback(true); + // Assumption: these terms are not redirected @@fixme + if (ArrayIndexOf(features, 'sameAs') >= 0) { + this.propertyActions[''] = [function (formula, subj, pred, obj, why) { + // log.warn("Equating "+subj.uri+" sameAs "+obj.uri); //@@ + formula.equate(subj, obj); + return true; // true if statement given is NOT needed in the store + }]; // sameAs -> equate & don't add to index + } + if (ArrayIndexOf(features, 'InverseFunctionalProperty') >= 0) { + this.classActions['<' + owl_ns + 'InverseFunctionalProperty>'] = [function (formula, subj, pred, obj, addFn) { + // yes subj not pred! + return formula.newPropertyAction(subj, handle_IFP); + }]; // IFP -> handle_IFP, do add to index + } + if (ArrayIndexOf(features, 'FunctionalProperty') >= 0) { + this.classActions['<' + owl_ns + 'FunctionalProperty>'] = [function (formula, subj, proj, obj, addFn) { + return formula.newPropertyAction(subj, handle_FP); + }]; // FP => handleFP, do add to index } - }); - }; - return sparql; -}(); - -module.exports = UpdateManager; -},{"./data-factory":46,"./fetcher":49,"./indexed-formula":52,"./namespace":58,"./serializer":67,"./uri":72,"./util":73}],71:[function(_dereq_,module,exports){ -'use strict'; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -/* - * Updates-Via - */ -var namedNode = _dereq_('./data-factory').namedNode; - -var UpdatesSocket = function () { - function UpdatesSocket(parent, via) { - _classCallCheck(this, UpdatesSocket); - - this.parent = parent; - this.via = via; - this.connected = false; - this.pending = {}; - this.subscribed = {}; - this.socket = {}; - try { - this.socket = new WebSocket(via); - this.socket.onopen = this.onOpen; - this.socket.onclose = this.onClose; - this.socket.onmessage = this.onMessage; - this.socket.onerror = this.onError; - } catch (error) { - this.onError(error); } - } - _createClass(UpdatesSocket, [{ - key: '_decode', - value: function _decode(q) { - var elt; + /** + * Adds a triple to the store. + * Returns the statement added + * (would it be better to return the original formula for chaining?) + */ + + }, { + key: 'add', + value: function add(subj, pred, obj, why) { var i; - var k; - var r; - var ref; - var ref1; - var v; - r = {}; - ref = function () { - var j, len, ref, results; - ref = q.split('&'); - results = []; - for (j = 0, len = ref.length; j < len; j++) { - elt = ref[j]; - results.push(elt.split('=')); + if (arguments.length === 1) { + if (subj instanceof Array) { + for (i = 0; i < subj.length; i++) { + this.add(subj[i]); + } + } else if (subj instanceof Statement) { + this.add(subj.subject, subj.predicate, subj.object, subj.why); + } else if (subj instanceof IndexedFormula) { + this.add(subj.statements); } - return results; - }(); - for (i in ref) { - elt = ref[i]; - ref1 = [decodeURIComponent(elt[0]), decodeURIComponent(elt[1])]; - k = ref1[0]; - v = ref1[1]; - if (r[k] == null) { - r[k] = []; + return this; + } + var actions; + var st; + if (!why) { + // system generated + why = this.fetcher ? this.fetcher.appNode : this.sym('chrome:theSession'); + } + subj = Node.fromValue(subj); + pred = Node.fromValue(pred); + obj = Node.fromValue(obj); + why = Node.fromValue(why); + if (this.predicateCallback) { + this.predicateCallback(this, pred, why); + } + // Action return true if the statement does not need to be added + var predHash = this.canon(pred).hashString(); + actions = this.propertyActions[predHash]; // Predicate hash + var done = false; + if (actions) { + // alert('type: '+typeof actions +' @@ actions='+actions) + for (i = 0; i < actions.length; i++) { + done = done || actions[i](this, subj, pred, obj, why); } - r[k].push(v); } - return r; - } - }, { - key: '_send', - value: function _send(method, uri, data) { - var base, message; - message = [method, uri, data].join(' '); - return typeof (base = this.socket).send === 'function' ? base.send(message) : void 0; + if (this.holds(subj, pred, obj, why)) { + // Takes time but saves duplicates + // console.log('rdflib: Ignoring dup! {' + subj + ' ' + pred + ' ' + obj + ' ' + why + '}') + return null; // @@better to return self in all cases? + } + // If we are tracking provenance, every thing should be loaded into the store + // if (done) return new Statement(subj, pred, obj, why) + // Don't put it in the store + // still return this statement for owl:sameAs input + var hash = [this.canon(subj).hashString(), predHash, this.canon(obj).hashString(), this.canon(why).hashString()]; + st = new Statement(subj, pred, obj, why); + for (i = 0; i < 4; i++) { + var ix = this.index[i]; + var h = hash[i]; + if (!ix[h]) { + ix[h] = []; + } + ix[h].push(st); // Set of things with this as subject, etc + } + + // log.debug("ADDING {"+subj+" "+pred+" "+obj+"} "+why) + this.statements.push(st); + return st; } }, { - key: '_subscribe', - value: function _subscribe(uri) { - this._send('sub', uri, ''); - this.subscribed[uri] = true; - return this.subscribed[uri]; + key: 'addAll', + value: function addAll(statements) { + var _this2 = this; + + statements.forEach(function (quad) { + _this2.add(quad.subject, quad.predicate, quad.object, quad.graph); + }); } }, { - key: 'onClose', - value: function onClose(e) { - var uri; - this.connected = false; - for (uri in this.subscribed) { - this.pending[uri] = true; + key: 'any', + value: function any(s, p, o, g) { + var st = this.anyStatementMatching(s, p, o, g); + if (st == null) { + return void 0; + } else if (s == null) { + return st.subject; + } else if (p == null) { + return st.predicate; + } else if (o == null) { + return st.object; } - this.subscribed = {}; - return this.subscribed; + return void 0; } }, { - key: 'onError', - value: function onError(e) { - throw new Error('onError' + e); + key: 'anyValue', + value: function anyValue(s, p, o, g) { + var y = this.any(s, p, o, g); + return y ? y.value : void 0; } }, { - key: 'onMessage', - value: function onMessage(e) { - var base, message; - message = e.data.split(' '); - if (message[0] === 'ping') { - return typeof (base = this.socket).send === 'function' ? base.send('pong ' + message.slice(1).join(' ')) : void 0; - } else if (message[0] === 'pub') { - return this.parent.onUpdate(message[1], this._decode(message[2])); + key: 'anyStatementMatching', + value: function anyStatementMatching(subj, pred, obj, why) { + var x = this.statementsMatching(subj, pred, obj, why, true); + if (!x || x.length === 0) { + return undefined; } + return x[0]; } + + /** + * Returns the symbol with canonical URI as smushed + */ + }, { - key: 'onOpen', - value: function onOpen(e) { - var results, uri; - this.connected = true; - results = []; - for (uri in this.pending) { - delete this.pending[uri]; - results.push(this._subscribe(uri)); + key: 'canon', + value: function canon(term) { + if (!term) { + return term; } - return results; + var y = this.redirections[term.hashString()]; + if (!y) { + return term; + } + return y; } }, { - key: 'subscribe', - value: function subscribe(uri) { - if (this.connected) { - return this._subscribe(uri); - } else { - this.pending[uri] = true; - return this.pending[uri]; + key: 'check', + value: function check() { + this.checkStatementList(this.statements); + for (var p = 0; p < 4; p++) { + var ix = this.index[p]; + for (var key in ix) { + if (ix.hasOwnProperty(key)) { + this.checkStatementList(ix[key], p); + } + } } } - }]); - - return UpdatesSocket; -}(); - -var UpdatesVia = function () { - function UpdatesVia(fetcher) { - _classCallCheck(this, UpdatesVia); - this.fetcher = fetcher; - this.graph = {}; - this.via = {}; - this.fetcher.addCallback('headers', this.onHeaders); - } + /** + * Self-consistency checking for diagnostis only + * Is each statement properly indexed? + */ - _createClass(UpdatesVia, [{ - key: 'onHeaders', - value: function onHeaders(d) { - var etag, uri, via; - if (d.headers == null) { - return true; - } - if (typeof WebSocket === 'undefined' || WebSocket === null) { - return true; - } - etag = d.headers['etag']; - via = d.headers['updates-via']; - uri = d.uri; - if (etag && via) { - this.graph[uri] = { - etag: etag, - via: via + }, { + key: 'checkStatementList', + value: function checkStatementList(sts, from) { + var names = ['subject', 'predicate', 'object', 'why']; + var origin = ' found in ' + names[from] + ' index.'; + var st; + for (var j = 0; j < sts.length; j++) { + st = sts[j]; + var term = [st.subject, st.predicate, st.object, st.why]; + var arrayContains = function arrayContains(a, x) { + for (var i = 0; i < a.length; i++) { + if (a[i].subject.sameTerm(x.subject) && a[i].predicate.sameTerm(x.predicate) && a[i].object.sameTerm(x.object) && a[i].why.sameTerm(x.why)) { + return true; + } + } }; - this.register(via, uri); + for (var p = 0; p < 4; p++) { + var c = this.canon(term[p]); + var h = c.hashString(); + if (!this.index[p][h]) { + // throw new Error('No ' + name[p] + ' index for statement ' + st + '@' + st.why + origin) + } else { + if (!arrayContains(this.index[p][h], st)) { + // throw new Error('Index for ' + name[p] + ' does not have statement ' + st + '@' + st.why + origin) + } + } + } + if (!arrayContains(this.statements, st)) { + throw new Error('Statement list does not statement ' + st + '@' + st.why + origin); + } } - return true; } }, { - key: 'onUpdate', - value: function onUpdate(uri, d) { - return this.fetcher.refresh(namedNode(uri)); + key: 'close', + value: function close() { + return this; } + + /** + * replaces @template with @target and add appropriate triples (no triple + * removed) + * one-direction replication + * @method copyTo + */ + }, { - key: 'register', - value: function register(via, uri) { - if (this.via[via] == null) { - this.via[via] = new UpdatesSocket(this, via); + key: 'copyTo', + value: function copyTo(template, target, flags) { + if (!flags) flags = []; + var statList = this.statementsMatching(template); + if (ArrayIndexOf(flags, 'two-direction') !== -1) { + statList.concat(this.statementsMatching(undefined, undefined, template)); + } + for (var i = 0; i < statList.length; i++) { + var st = statList[i]; + switch (st.object.termType) { + case 'NamedNode': + this.add(target, st.predicate, st.object); + break; + case 'Literal': + case 'BlankNode': + case 'Collection': + this.add(target, st.predicate, st.object.copy(this)); + } + if (ArrayIndexOf(flags, 'delete') !== -1) { + this.remove(st); + } } - return this.via[via].subscribe(uri); } - }]); - - return UpdatesVia; -}(); - -module.exports.UpdatesSocket = UpdatesSocket; -module.exports.UpdatesVia = UpdatesVia; -},{"./data-factory":46}],72:[function(_dereq_,module,exports){ -'use strict'; - -/* - * Implements URI-specific functions - * - * See RFC 2386 - * - * See also: - * http://www.w3.org/2005/10/ajaw/uri.js - * http://www.w3.org/2000/10/swap/uripath.py - * - */ -var alert = alert || console.log; - -module.exports.docpart = docpart; -module.exports.document = document; -module.exports.hostpart = hostpart; -module.exports.join = join; -module.exports.protocol = protocol; -module.exports.refTo = refTo; - -var NamedNode = _dereq_('./named-node'); -function docpart(uri) { - var i; - i = uri.indexOf('#'); - if (i < 0) { - return uri; - } else { - return uri.slice(0, i); - } -} - -function document(x) { - return new NamedNode(docpart(x.uri)); -} - -function hostpart(u) { - var m = /[^\/]*\/\/([^\/]*)\//.exec(u); - if (m) { - return m[1]; - } else { - return ''; - } -} + /** + * simplify graph in store when we realize two identifiers are equivalent + * We replace the bigger with the smaller. + */ -function join(given, base) { - var baseColon, baseScheme, baseSingle; - var colon, lastSlash, path; - var baseHash = base.indexOf('#'); - if (baseHash > 0) { - base = base.slice(0, baseHash); - } - if (given.length === 0) { - return base; - } - if (given.indexOf('#') === 0) { - return base + given; - } - colon = given.indexOf(':'); - if (colon >= 0) { - return given; - } - baseColon = base.indexOf(':'); - if (base.length === 0) { - return given; - } - if (baseColon < 0) { - alert('Invalid base: ' + base + ' in join with given: ' + given); - return given; - } - baseScheme = base.slice(0, +baseColon + 1 || 9e9); - if (given.indexOf('//') === 0) { - return baseScheme + given; - } - if (base.indexOf('//', baseColon) === baseColon + 1) { - baseSingle = base.indexOf('/', baseColon + 3); - if (baseSingle < 0) { - if (base.length - baseColon - 3 > 0) { - return base + '/' + given; - } else { - return baseScheme + given; + }, { + key: 'equate', + value: function equate(u1, u2) { + // log.warn("Equating "+u1+" and "+u2); // @@ + // @@JAMBO Must canonicalize the uris to prevent errors from a=b=c + // 03-21-2010 + u1 = this.canon(u1); + u2 = this.canon(u2); + var d = u1.compareTerm(u2); + if (!d) { + return true; // No information in {a = a} } - } - } else { - baseSingle = base.indexOf('/', baseColon + 1); - if (baseSingle < 0) { - if (base.length - baseColon - 1 > 0) { - return base + '/' + given; + // var big + // var small + if (d < 0) { + // u1 less than u2 + return this.replaceWith(u2, u1); } else { - return baseScheme + given; + return this.replaceWith(u1, u2); } } - } - if (given.indexOf('/') === 0) { - return base.slice(0, baseSingle) + given; - } - path = base.slice(baseSingle); - lastSlash = path.lastIndexOf('/'); - if (lastSlash < 0) { - return baseScheme + given; - } - if (lastSlash >= 0 && lastSlash < path.length - 1) { - path = path.slice(0, +lastSlash + 1 || 9e9); - } - path += given; - while (path.match(/[^\/]*\/\.\.\//)) { - path = path.replace(/[^\/]*\/\.\.\//, ''); - } - path = path.replace(/\.\//g, ''); - path = path.replace(/\/\.$/, '/'); - return base.slice(0, baseSingle) + path; -} + }, { + key: 'formula', + value: function formula(features) { + return new IndexedFormula(features); + } -function protocol(uri) { - var i; - i = uri.indexOf(':'); - if (i < 0) { - return null; - } else { - return uri.slice(0, i); - } -} + /** + * Returns the number of statements contained in this IndexedFormula. + * (Getter proxy to this.statements). + * Usage: + * ``` + * var kb = rdf.graph() + * kb.length // -> 0 + * ``` + * @return {Number} + */ -function refTo(base, uri) { - var c, i, k, l, len, len1, n, o, p, q, ref, ref1, s; - var commonHost = new RegExp('^[-_a-zA-Z0-9.]+:(//[^/]*)?/[^/]*$'); - if (!base) { - return uri; - } - if (base === uri) { - return ''; - } - for (i = o = 0, len = uri.length; o < len; i = ++o) { - c = uri[i]; - if (c !== base[i]) { - break; - } - } - if (base.slice(0, i).match(commonHost)) { - k = uri.indexOf('//'); - if (k < 0) { - k = -2; - } - l = uri.indexOf('/', k + 2); - if (uri[l + 1] !== '/' && base[l + 1] !== '/' && uri.slice(0, l) === base.slice(0, l)) { - return uri.slice(l); - } - } - if (uri[i] === '#' && base.length === i) { - return uri.slice(i); - } - while (i > 0 && uri[i - 1] !== '/') { - i--; - } - if (i < 3) { - return uri; - } - if (base.indexOf('//', i - 2) > 0 || uri.indexOf('//', i - 2) > 0) { - return uri; - } - if (base.indexOf(':', i) > 0) { - return uri; - } - n = 0; - ref = base.slice(i); - for (p = 0, len1 = ref.length; p < len1; p++) { - c = ref[p]; - if (c === '/') { - n++; - } - } - if (n === 0 && i < uri.length && uri[i] === '#') { - return './' + uri.slice(i); - } - if (n === 0 && i === uri.length) { - return './'; - } - s = ''; - if (n > 0) { - for (q = 1, ref1 = n; ref1 >= 1 ? q <= ref1 : q >= ref1; ref1 >= 1 ? ++q : --q) { - s += '../'; - } - } - return s + uri.slice(i); -} -},{"./named-node":57}],73:[function(_dereq_,module,exports){ -'use strict'; + }, { + key: 'match', -/** - * Utility functions for $rdf - * @module util - */ -var docpart = _dereq_('./uri').docpart; -var log = _dereq_('./log'); -var NamedNode = _dereq_('./named-node'); -module.exports.AJAR_handleNewTerm = ajarHandleNewTerm; -module.exports.ArrayIndexOf = arrayIndexOf; -module.exports.callbackify = callbackify; -module.exports.dtstamp = dtstamp; -module.exports.DOMParserFactory = domParser; -module.exports.domToString = domToString; -module.exports.dumpNode = dumpNode; -module.exports.getHTTPHeaders = getHTTPHeaders; -module.exports.heavyCompare = heavyCompare; -module.exports.heavyCompareSPO = heavyCompareSPO; -module.exports.output = output; -module.exports.parseXML = parseXML; -module.exports.RDFArrayRemove = rdfArrayRemove; -module.exports.stackString = stackString; -module.exports.string_startswith = stringStartsWith; -module.exports.string = {}; -module.exports.string.template = stringTemplate; -module.exports.uri = _dereq_('./uri'); // TODO: Remove this mixed usage -// module.exports.variablesIn = variablesIn -module.exports.XMLHTTPFactory = xhr; -module.exports.log = log; + /** + * Returns any quads matching the given arguments. + * Standard RDFJS Taskforce method for Source objects, implemented as an + * alias to `statementsMatching()` + * @method match + * @param subject {Node|String|Object} + * @param predicate {Node|String|Object} + * @param object {Node|String|Object} + * @param graph {NamedNode|String} + */ + value: function match(subject, predicate, object, graph) { + return this.statementsMatching(Node.fromValue(subject), Node.fromValue(predicate), Node.fromValue(object), Node.fromValue(graph)); + } -module.exports.mediaTypeClass = function (mediaType) { - mediaType = mediaType.split(';')[0].trim(); // remove media type parameters - return new NamedNode('http://www.w3.org/ns/iana/media-types/' + mediaType + '#Resource'); -}; + /** + * Find out whether a given URI is used as symbol in the formula + */ -/** - * Loads ontologies of the data we load (this is the callback from the kb to - * the fetcher). Exports as `AJAR_handleNewTerm` - */ -function ajarHandleNewTerm(kb, p, requestedBy) { - var sf = null; - if (typeof kb.fetcher !== 'undefined') { - sf = kb.fetcher; - } else { - return; - } - if (p.termType !== 'NamedNode') return; - var docuri = docpart(p.uri); - var fixuri; - if (p.uri.indexOf('#') < 0) { - // No hash - // @@ major hack for dbpedia Categories, which spread indefinitely - if (stringStartsWith(p.uri, 'http://dbpedia.org/resource/Category:')) return; + }, { + key: 'mentionsURI', + value: function mentionsURI(uri) { + var hash = '<' + uri + '>'; + return !!this.subjectIndex[hash] || !!this.objectIndex[hash] || !!this.predicateIndex[hash]; + } - /* - if (string_startswith(p.uri, 'http://xmlns.com/foaf/0.1/')) { - fixuri = "http://dig.csail.mit.edu/2005/ajar/ajaw/test/foaf" - // should give HTTP 303 to ontology -- now is :-) - } else - */ - if (stringStartsWith(p.uri, 'http://purl.org/dc/elements/1.1/') || stringStartsWith(p.uri, 'http://purl.org/dc/terms/')) { - fixuri = 'http://dublincore.org/2005/06/13/dcq'; - // dc fetched multiple times - } else if (stringStartsWith(p.uri, 'http://xmlns.com/wot/0.1/')) { - fixuri = 'http://xmlns.com/wot/0.1/index.rdf'; - } else if (stringStartsWith(p.uri, 'http://web.resource.org/cc/')) { - // log.warn("creative commons links to html instead of rdf. doesn't seem to content-negotiate.") - fixuri = 'http://web.resource.org/cc/schema.rdf'; + // Existentials are BNodes - something exists without naming + + }, { + key: 'newExistential', + value: function newExistential(uri) { + if (!uri) return this.bnode(); + var x = this.sym(uri); + return this.declareExistential(x); + } + }, { + key: 'newPropertyAction', + value: function newPropertyAction(pred, action) { + // log.debug("newPropertyAction: "+pred) + var hash = pred.hashString(); + if (!this.propertyActions[hash]) { + this.propertyActions[hash] = []; + } + this.propertyActions[hash].push(action); + // Now apply the function to to statements already in the store + var toBeFixed = this.statementsMatching(undefined, pred, undefined); + var done = false; + for (var i = 0; i < toBeFixed.length; i++) { + // NOT optimized - sort toBeFixed etc + done = done || action(this, toBeFixed[i].subject, pred, toBeFixed[i].object); + } + return done; } - } - if (fixuri) { - docuri = fixuri; - } - if (sf && sf.getState(docuri) !== 'unrequested') return; - if (fixuri) { - // only give warning once: else happens too often - log.warn('Assuming server still broken, faking redirect of <' + p.uri + '> to <' + docuri + '>'); - } - sf.requestURI(docuri, requestedBy); -} + // Universals are Variables -/** - * Exports as `ArrayIndexOf`. - */ -function arrayIndexOf(arr, item, i) { - i || (i = 0); - var length = arr.length; - if (i < 0) i = length + i; - for (; i < length; i++) { - if (arr[i] === item) { - return i; + }, { + key: 'newUniversal', + value: function newUniversal(uri) { + var x = this.sym(uri); + if (!this._universalVariables) this._universalVariables = []; + this._universalVariables.push(x); + return x; } - } - return -1; -} -/** - * Adds callback functionality to an object. - * Callback functions are indexed by a 'hook' string. - * They return true if they want to be called again. - * @method callbackify - * @param obj {Object} - * @param callbacks {Array} - */ -function callbackify(obj, callbacks) { - obj.callbacks = {}; - for (var x = callbacks.length - 1; x >= 0; x--) { - obj.callbacks[callbacks[x]] = []; - } + // convenience function used by N3 parser - obj.addHook = function (hook) { - if (!obj.callbacks[hook]) { - obj.callbacks[hook] = []; + }, { + key: 'variable', + value: function variable(name) { + return new Variable(name); } - }; - obj.addCallback = function (hook, func) { - obj.callbacks[hook].push(func); - }; + /** + * Find an unused id for a file being edited: return a symbol + * (Note: Slow iff a lot of them -- could be O(log(k)) ) + */ - obj.removeCallback = function (hook, funcName) { - for (var i = 0; i < obj.callbacks[hook].length; i++) { - if (obj.callbacks[hook][i].name === funcName) { - obj.callbacks[hook].splice(i, 1); - return true; + }, { + key: 'nextSymbol', + value: function nextSymbol(doc) { + for (var i = 0;; i++) { + var uri = doc.uri + '#n' + i; + if (!this.mentionsURI(uri)) return this.sym(uri); } } - return false; - }; + }, { + key: 'query', + value: function query(myQuery, callback, fetcher, onDone) { + var indexedFormulaQuery = _dereq_('./query').indexedFormulaQuery; + return indexedFormulaQuery.call(this, myQuery, callback, fetcher, onDone); + } - obj.insertCallback = function (hook, func) { - obj.callbacks[hook].unshift(func); - }; + /** + * Finds a statement object and removes it + */ - obj.fireCallbacks = function (hook, args) { - var newCallbacks = []; - var replaceCallbacks = []; - var len = obj.callbacks[hook].length; - var x; - // log.info('!@$ Firing '+hook+' call back with length'+len) - for (x = len - 1; x >= 0; x--) { - // log.info('@@ Firing '+hook+' callback '+ obj.callbacks[hook][x]) - if (obj.callbacks[hook][x].apply(obj, args)) { - newCallbacks.push(obj.callbacks[hook][x]); + }, { + key: 'remove', + value: function remove(st) { + if (st instanceof Array) { + for (var i = 0; i < st.length; i++) { + this.remove(st[i]); + } + return this; + } + if (st instanceof IndexedFormula) { + return this.remove(st.statements); + } + var sts = this.statementsMatching(st.subject, st.predicate, st.object, st.why); + if (!sts.length) { + throw new Error('Statement to be removed is not on store: ' + st); } + this.removeStatement(sts[0]); + return this; } - for (x = newCallbacks.length - 1; x >= 0; x--) { - replaceCallbacks.push(newCallbacks[x]); - } + /** + * Removes all statemnts in a doc + */ - for (x = len; x < obj.callbacks[hook].length; x++) { - replaceCallbacks.push(obj.callbacks[hook][x]); + }, { + key: 'removeDocument', + value: function removeDocument(doc) { + var sts = this.statementsMatching(undefined, undefined, undefined, doc).slice(); // Take a copy as this is the actual index + for (var i = 0; i < sts.length; i++) { + this.removeStatement(sts[i]); + } + return this; } - obj.callbacks[hook] = replaceCallbacks; - }; -} - -/** - * Returns a DOM parser based on current runtime environment. - * Exports as `DOMParserFactory` - */ -function domParser() { - if (tabulator && tabulator.isExtension) { - return Components.classes['@mozilla.org/xmlextras/domparser;1'].getService(Components.interfaces.nsIDOMParser); - } else if (window.DOMParser) { - return new DOMParser(); - } else if (window.ActiveXObject) { - return new ActiveXObject('Microsoft.XMLDOM'); - } else { - return false; - } -} + /** + * remove all statements matching args (within limit) * + */ -// From https://github.com/linkeddata/dokieli -function domToString(node, options) { - options = options || {}; - var selfClosing = []; - if ('selfClosing' in options) { - options.selfClosing.split(' ').forEach(function (n) { - selfClosing[n] = true; - }); - } - var skipAttributes = []; - if ('skipAttributes' in options) { - options.skipAttributes.split(' ').forEach(function (n) { - skipAttributes[n] = true; - }); - } - return dumpNode(node, options, selfClosing, skipAttributes); -} + }, { + key: 'removeMany', + value: function removeMany(subj, pred, obj, why, limit) { + // log.debug("entering removeMany w/ subj,pred,obj,why,limit = " + subj +", "+ pred+", " + obj+", " + why+", " + limit) + var sts = this.statementsMatching(subj, pred, obj, why, false); + // This is a subtle bug that occcured in updateCenter.js too. + // The fact is, this.statementsMatching returns this.whyIndex instead of a copy of it + // but for perfromance consideration, it's better to just do that + // so make a copy here. + var statements = []; + for (var i = 0; i < sts.length; i++) { + statements.push(sts[i]); + }if (limit) statements = statements.slice(0, limit); + for (i = 0; i < statements.length; i++) { + this.remove(statements[i]); + } + } + }, { + key: 'removeMatches', + value: function removeMatches(subject, predicate, object, why) { + this.removeStatements(this.statementsMatching(subject, predicate, object, why)); + return this; + } -function dumpNode(node, options, selfClosing, skipAttributes) { - var i; - var out = ''; - var noEsc = [false]; - if (typeof node.nodeType === 'undefined') return out; - if (node.nodeType === 1) { - if (node.hasAttribute('class') && 'classWithChildText' in options && node.matches(options.classWithChildText.class)) { - out += node.querySelector(options.classWithChildText.element).textContent; - } else if (!('skipNodeWithClass' in options && node.matches('.' + options.skipNodeWithClass))) { - var ename = node.nodeName.toLowerCase(); - out += '<' + ename; + /** + * Remove a particular statement object from the store + * + * st a statement which is already in the store and indexed. + * Make sure you only use this for these. + * Otherwise, you should use remove() above. + */ - var attrList = []; - for (i = node.attributes.length - 1; i >= 0; i--) { - var atn = node.attributes[i]; - if (skipAttributes.length > 0 && skipAttributes[atn.name]) continue; - if (/^\d+$/.test(atn.name)) continue; - if (atn.name === 'class' && 'replaceClassItemWith' in options && atn.value.split(' ').indexOf(options.replaceClassItemWith.source) > -1) { - var re = new RegExp(options.replaceClassItemWith.source, 'g'); - atn.value = atn.value.replace(re, options.replaceClassItemWith.target).trim(); - } - if (!(atn.name === 'class' && 'skipClassWithValue' in options && options.skipClassWithValue === atn.value)) { - attrList.push(atn.name + '=\'' + atn.value.replace(/&/g, '&').replace(//g, '>').replace(/'/g, '"') + '\''); - } - } - if (attrList.length > 0) { - if ('sortAttributes' in options && options.sortAttributes) { - attrList.sort(function (a, b) { - return a.toLowerCase().localeCompare(b.toLowerCase()); - }); + }, { + key: 'removeStatement', + value: function removeStatement(st) { + // log.debug("entering remove w/ st=" + st) + var term = [st.subject, st.predicate, st.object, st.why]; + for (var p = 0; p < 4; p++) { + var c = this.canon(term[p]); + var h = c.hashString(); + if (!this.index[p][h]) { + // log.warn ("Statement removal: no index '+p+': "+st) + } else { + RDFArrayRemove(this.index[p][h], st); } - out += ' ' + attrList.join(' '); } - if (selfClosing[ename]) { - out += ' />'; - } else { - out += '>'; - out += ename === 'html' ? '\n ' : ''; - noEsc.push(ename === 'style' || ename === 'script'); - for (i = 0; i < node.childNodes.length; i++) { - out += dumpNode(node.childNodes[i]); - }noEsc.pop(); - out += ename === 'body' ? '' + '\n' : ''; + RDFArrayRemove(this.statements, st); + return this; + } + }, { + key: 'removeStatements', + value: function removeStatements(sts) { + for (var i = 0; i < sts.length; i++) { + this.remove(sts[i]); } + return this; } - } else if (node.nodeType === 8) { - // FIXME: If comments are not tabbed in source, a new line is not prepended - out += ''; - } else if (node.nodeType === 3 || node.nodeType === 4) { - // XXX: Remove new lines which were added after DOM ready - var nl = node.nodeValue.replace(/\n+$/, ''); - out += noEsc[noEsc.length - 1] ? nl : nl.replace(/&/g, '&').replace(//g, '>'); - } else { - console.log('Warning; Cannot handle serialising nodes of type: ' + node.nodeType); - console.log(node); - } - return out; -} -function dtstamp() { - var now = new Date(); - var year = now.getYear() + 1900; - var month = now.getMonth() + 1; - var day = now.getDate(); - var hour = now.getUTCHours(); - var minute = now.getUTCMinutes(); - var second = now.getSeconds(); - if (month < 10) month = '0' + month; - if (day < 10) day = '0' + day; - if (hour < 10) hour = '0' + hour; - if (minute < 10) minute = '0' + minute; - if (second < 10) second = '0' + second; - return year + '-' + month + '-' + day + 'T' + hour + ':' + minute + ':' + second + 'Z'; -} + /** + * Replace big with small, obsoleted with obsoleting. + */ -/** - * Returns a hashmap of HTTP headers and their values. - * @@ Bug: Assumes that each header only occurs once. - * Also note that a , in a header value is just the same as having two headers. - */ -function getHTTPHeaders(xhr) { - var lines = xhr.getAllResponseHeaders().split('\n'); - var headers = {}; - var last; - for (var x = 0; x < lines.length; x++) { - if (lines[x].length > 0) { - var pair = lines[x].split(': '); - if (typeof pair[1] === 'undefined') { - // continuation - headers[last] += '\n' + pair[0]; - } else { - last = pair[0].toLowerCase(); - headers[last] = pair[1]; + }, { + key: 'replaceWith', + value: function replaceWith(big, small) { + // log.debug("Replacing "+big+" with "+small) // @@ + var oldhash = big.hashString(); + var newhash = small.hashString(); + var moveIndex = function moveIndex(ix) { + var oldlist = ix[oldhash]; + if (!oldlist) { + return; // none to move + } + var newlist = ix[newhash]; + if (!newlist) { + ix[newhash] = oldlist; + } else { + ix[newhash] = oldlist.concat(newlist); + } + delete ix[oldhash]; + }; + // the canonical one carries all the indexes + for (var i = 0; i < 4; i++) { + moveIndex(this.index[i]); } + this.redirections[oldhash] = small; + if (big.uri) { + // @@JAMBO: must update redirections,aliases from sub-items, too. + if (!this.aliases[newhash]) { + this.aliases[newhash] = []; + } + this.aliases[newhash].push(big); // Back link + if (this.aliases[oldhash]) { + for (i = 0; i < this.aliases[oldhash].length; i++) { + this.redirections[this.aliases[oldhash][i].hashString()] = small; + this.aliases[newhash].push(this.aliases[oldhash][i]); + } + } + this.add(small, this.sym('http://www.w3.org/2007/ont/link#uri'), big.uri); + // If two things are equal, and one is requested, we should request the other. + if (this.fetcher) { + this.fetcher.nowKnownAs(big, small); + } + } + moveIndex(this.classActions); + moveIndex(this.propertyActions); + // log.debug("Equate done. "+big+" to be known as "+small) + return true; // true means the statement does not need to be put in } - } - return headers; -} - -/** - * Compares statements (heavy comparison for repeatable canonical ordering) - */ -function heavyCompare(x, y, g, uriMap) { - var nonBlank = function nonBlank(x) { - return x.termType === 'BlankNode' ? null : x; - }; - var signature = function signature(x) { - var lis = g.statementsMatching(x).map(function (st) { - return '' + nonBlank(st.subject) + ' ' + nonBlank(st.predicate) + ' ' + nonBlank(st.object); - }).concat(g.statementsMatching(undefined, undefined, x).map(function (st) { - return '' + nonBlank(st.subject) + ' ' + nonBlank(st.predicate) + ' ' + nonBlank(st.object); - })); - lis.sort(); - return lis.join('\n'); - }; - if (x.termType === 'BlankNode' && y.termType === 'BlankNode') { - if (x.compareTerm(y) === 0) return 0; // Same - if (signature(x) > signature(y)) return +1; - if (signature(x) < signature(y)) return -1; - return x.compareTerm(y); // Too bad -- this order not canonical. - // throw "different bnodes indistinquishable for sorting" - } else { - if (uriMap && x.uri && y.uri) { - return (uriMap[x.uri] || x.uri).localeCompare(uriMap[y.uri] || y.uri); - } - return x.compareTerm(y); - } -} - -function heavyCompareSPO(x, y, g, uriMap) { - return heavyCompare(x.subject, y.subject, g, uriMap) || heavyCompare(x.predicate, y.predicate, g, uriMap) || heavyCompare(x.object, y.object, g, uriMap); -} -/** - * Defines a simple debugging function - * @method output - * @param o {String} - */ -function output(o) { - var k = document.createElement('div'); - k.textContent = o; - document.body.appendChild(k); -} + /** + * Return all equivalent URIs by which this is known + */ -/** - * Returns a DOM from parsex XML. - */ -function parseXML(str, options) { - var dparser; - options = options || {}; - if (typeof tabulator !== 'undefined' && tabulator.isExtension) { - dparser = Components.classes['@mozilla.org/xmlextras/domparser;1'].getService(Components.interfaces.nsIDOMParser); - } else if (typeof module !== 'undefined' && module && module.exports) { - // Node.js - // var libxmljs = require('libxmljs'); // Was jsdom before 2012-01 then libxmljs but that nonstandard - // return libxmljs.parseXmlString(str) + }, { + key: 'allAliases', + value: function allAliases(x) { + var a = this.aliases[this.canon(x).hashString()] || []; + a.push(this.canon(x)); + return a; + } - // var jsdom = require('jsdom'); 2012-01 though 2015-08 no worky with new Node - // var dom = jsdom.jsdom(str, undefined, {} );// html, level, options + /** + * Compare by canonical URI as smushed + */ - var DOMParser = _dereq_('xmldom').DOMParser; // 2015-08 on https://github.com/jindw/xmldom - var dom = new DOMParser().parseFromString(str, options.contentType || 'application/xhtml+xml'); - return dom; - } else { - if (typeof window !== 'undefined' && window.DOMParser) { - dparser = new window.DOMParser(); // seems to actually work - } else { - dparser = new DOMParser(); // Doc says this works + }, { + key: 'sameThings', + value: function sameThings(x, y) { + if (x.sameTerm(y)) { + return true; + } + var x1 = this.canon(x); + // alert('x1='+x1) + if (!x1) return false; + var y1 = this.canon(y); + // alert('y1='+y1); //@@ + if (!y1) return false; + return x1.uri === y1.uri; } - } - return dparser.parseFromString(str, 'application/xml'); -} - -/** - * Removes all statements equal to x from a - * Exports as `RDFArrayRemove` - */ -function rdfArrayRemove(a, x) { - for (var i = 0; i < a.length; i++) { - // TODO: This used to be the following, which didnt always work..why - // if(a[i] === x) - if (a[i].subject.sameTerm(x.subject) && a[i].predicate.sameTerm(x.predicate) && a[i].object.sameTerm(x.object) && a[i].why.sameTerm(x.why)) { - a.splice(i, 1); - return; + }, { + key: 'setPrefixForURI', + value: function setPrefixForURI(prefix, nsuri) { + // TODO: This is a hack for our own issues, which ought to be fixed + // post-release + // See http://dig.csail.mit.edu/cgi-bin/roundup.cgi/$rdf/issue227 + if (prefix === 'tab' && this.namespaces['tab']) { + return; + } // There are files around with long badly generated prefixes like this + if (prefix.slice(0, 2) === 'ns' || prefix.slice(0, 7) === 'default') { + return; + } + this.namespaces[prefix] = nsuri; } - } - throw new Error('RDFArrayRemove: Array did not contain ' + x + ' ' + x.why); -} -function stringStartsWith(str, pref) { - // missing library routines - return str.slice(0, pref.length) === pref; -} + /** + * Return statements matching a pattern + * ALL CONVENIENCE LOOKUP FUNCTIONS RELY ON THIS! + */ + + }, { + key: 'statementsMatching', + value: function statementsMatching(subj, pred, obj, why, justOne) { + // log.debug("Matching {"+subj+" "+pred+" "+obj+"}") + var pat = [subj, pred, obj, why]; + var pattern = []; + var hash = []; + var wild = []; // wildcards + var given = []; // Not wild + var p; + var list; + for (p = 0; p < 4; p++) { + pattern[p] = this.canon(Node.fromValue(pat[p])); + if (!pattern[p]) { + wild.push(p); + } else { + given.push(p); + hash[p] = pattern[p].hashString(); + } + } + if (given.length === 0) { + return this.statements; + } + if (given.length === 1) { + // Easy too, we have an index for that + p = given[0]; + list = this.index[p][hash[p]]; + if (list && justOne) { + if (list.length > 1) { + list = list.slice(0, 1); + } + } + list = list || []; + return list; + } + // Now given.length is 2, 3 or 4. + // We hope that the scale-free nature of the data will mean we tend to get + // a short index in there somewhere! + var best = 1e10; // really bad + var best_i; + var i; + for (i = 0; i < given.length; i++) { + p = given[i]; // Which part we are dealing with + list = this.index[p][hash[p]]; + if (!list) { + return []; // No occurrences + } + if (list.length < best) { + best = list.length; + best_i = i; // (not p!) + } + } + // Ok, we have picked the shortest index but now we have to filter it + var best_p = given[best_i]; + var possibles = this.index[best_p][hash[best_p]]; + var check = given.slice(0, best_i).concat(given.slice(best_i + 1)); // remove best_i + var results = []; + var parts = ['subject', 'predicate', 'object', 'why']; + for (var j = 0; j < possibles.length; j++) { + var st = possibles[j]; -/** - * C++, python style %s -> subs - */ -function stringTemplate(base, subs) { - var baseA = base.split('%s'); - var result = ''; - for (var i = 0; i < subs.length; i++) { - subs[i] += ''; - result += baseA[i] + subs[i]; - } - return result + baseA.slice(subs.length).join(); -} + for (i = 0; i < check.length; i++) { + // for each position to be checked + p = check[i]; + if (!this.canon(st[parts[p]]).sameTerm(pattern[p])) { + st = null; + break; + } + } + if (st != null) { + results.push(st); + if (justOne) break; + } + } + return results; + } -// Stack dump on errors - to pass errors back + /** + * A list of all the URIs by which this thing is known + */ -function stackString(e) { - var str = '' + e + '\n'; - if (!e.stack) { - return str + 'No stack available.\n'; - } - var lines = e.stack.toString().split('\n'); - var toprint = []; - for (var i = 0; i < lines.length; i++) { - var line = lines[i]; - if (line.indexOf('ecmaunit.js') > -1) { - // remove useless bit of traceback - break; + }, { + key: 'uris', + value: function uris(term) { + var cterm = this.canon(term); + var terms = this.aliases[cterm.hashString()]; + if (!cterm.uri) return []; + var res = [cterm.uri]; + if (terms) { + for (var i = 0; i < terms.length; i++) { + res.push(terms[i].uri); + } + } + return res; } - if (line.charAt(0) == '(') { - line = 'function' + line; + }, { + key: 'length', + get: function get() { + return this.statements.length; } - var chunks = line.split('@'); - toprint.push(chunks); - } - // toprint.reverse(); No - I prefer the latest at the top by the error message -tbl + }]); - for (var i = 0; i < toprint.length; i++) { - str += ' ' + toprint[i][1] + '\n ' + toprint[i][0]; - } - return str; -} + return IndexedFormula; +}(Formula); -/** - * Finds the variables in a graph (shallow). - * Note: UNUSED. - */ -// function variablesIn (g) { -// for (var i = 0; i < g.statements.length; i++) { -// var st = g.statatements[i] -// var vars = {} -// if (st.subject instanceof $rdf.Variable) { -// vars[st.subject.toNT()] = true -// } -// if (st.predicate instanceof $rdf.Variable) { -// vars[st.predicate.toNT()] = true -// } -// if (st.object instanceof $rdf.Variable) { -// vars[st.object.toNT()] = true -// } -// } -// return vars -// } +exports.default = IndexedFormula; -/** - * Returns an XMLHttpRequest object for the appropriate current runtime - * environment. Exports as `XMLHTTPFactory` - */ -function xhr() { - var XMLHttpRequest; - // Running inside the Tabulator Firefox extension - if (typeof tabulator !== 'undefined' && tabulator.isExtension) { - // Cannot use XMLHttpRequest natively, must request it through SDK - return Components.classes['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance().QueryInterface(Components.interfaces.nsIXMLHttpRequest); - } else if (typeof window !== 'undefined' && 'XMLHttpRequest' in window) { - // Running inside the browser - XMLHttpRequest = window.XMLHttpRequest; - return new XMLHttpRequest(); - } else if (typeof module !== 'undefined' && module && module.exports) { - // Running in Node.js - XMLHttpRequest = _dereq_('xmlhttprequest').XMLHttpRequest; - return new XMLHttpRequest(); - } else if (window.ActiveXObject) { - try { - return new ActiveXObject('Msxml2.XMLHTTP'); - } catch (e) { - return new ActiveXObject('Microsoft.XMLHTTP'); + +IndexedFormula.handleRDFType = handleRDFType; +},{"./formula":247,"./node":256,"./query":260,"./statement":266,"./util":270,"./variable":271}],250:[function(_dereq_,module,exports){ +'use strict'; + +var jsonParser = function () { + return { + parseJSON: function parseJSON(data, source, store) { + var subject, predicate, object; + var bnodes = {}; + var why = store.sym(source); + for (var x in data) { + if (x.indexOf('_:') === 0) { + if (bnodes[x]) { + subject = bnodes[x]; + } else { + subject = store.bnode(x); + bnodes[x] = subject; + } + } else { + subject = store.sym(x); + } + var preds = data[x]; + for (var y in preds) { + var objects = preds[y]; + predicate = store.sym(y); + for (var z in objects) { + var obj = objects[z]; + if (obj.type === 'uri') { + object = store.sym(obj.value); + store.add(subject, predicate, object, why); + } else if (obj.type === 'BlankNode') { + if (bnodes[obj.value]) { + object = bnodes[obj.value]; + } else { + object = store.bnode(obj.value); + bnodes[obj.value] = object; + } + store.add(subject, predicate, object, why); + } else if (obj.type === 'Literal') { + // var datatype + if (obj.datatype) { + object = store.literal(obj.value, undefined, store.sym(obj.datatype)); + } else if (obj.lang) { + object = store.literal(obj.value, obj.lang); + } else { + object = store.literal(obj.value); + } + store.add(subject, predicate, object, why); + } else { + throw new Error('error: unexpected termtype: ' + z.type); + } + } + } + } } - } else { - return false; - } -} -},{"./log":55,"./named-node":57,"./uri":72,"xmldom":141,"xmlhttprequest":144}],74:[function(_dereq_,module,exports){ + }; +}(); + +module.exports = jsonParser; +},{}],251:[function(_dereq_,module,exports){ 'use strict'; +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -31610,8598 +36282,11331 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var ClassOrder = _dereq_('./class-order'); +var NamedNode = _dereq_('./named-node'); var Node = _dereq_('./node'); -var Uri = _dereq_('./uri'); - -/** - * Variables are placeholders used in patterns to be matched. - * In cwm they are symbols which are the formula's list of quantified variables. - * In sparql they are not visibly URIs. Here we compromise, by having - * a common special base URI for variables. Their names are uris, - * but the ? notation has an implicit base uri of 'varid:' - * @class Variable - */ - -var Variable = function (_Node) { - _inherits(Variable, _Node); +var XSD = _dereq_('./xsd'); - function Variable() { - var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; +var Literal = function (_Node) { + _inherits(Literal, _Node); - _classCallCheck(this, Variable); + function Literal(value, language, datatype) { + _classCallCheck(this, Literal); - var _this = _possibleConstructorReturn(this, (Variable.__proto__ || Object.getPrototypeOf(Variable)).call(this)); + var _this = _possibleConstructorReturn(this, (Literal.__proto__ || Object.getPrototypeOf(Literal)).call(this)); - _this.termType = Variable.termType; - _this.value = name; - _this.base = 'varid:'; - _this.uri = Uri.join(name, _this.base); + _this.termType = Literal.termType; + _this.value = value; + if (language) { + _this.lang = language; + datatype = XSD.langString; + } + // If not specified, a literal has the implied XSD.string default datatype + if (datatype) { + _this.datatype = NamedNode.fromValue(datatype); + } return _this; } - _createClass(Variable, [{ + _createClass(Literal, [{ + key: 'copy', + value: function copy() { + return new Literal(this.value, this.lang, this.datatype); + } + }, { key: 'equals', value: function equals(other) { if (!other) { return false; } - return this.termType === other.termType && this.value === other.value; - } - }, { - key: 'hashString', - value: function hashString() { - return this.toString(); + return this.termType === other.termType && this.value === other.value && this.language === other.language && (!this.datatype && !other.datatype || this.datatype && this.datatype.equals(other.datatype)); } }, { - key: 'substitute', - value: function substitute(bindings) { - var ref; - return (ref = bindings[this.toNT()]) != null ? ref : this; + key: 'toNT', + value: function toNT() { + if (typeof this.value === 'number') { + return this.toString(); + } else if (typeof this.value !== 'string') { + throw new Error('Value of RDF literal is not string or number: ' + this.value); + } + var str = this.value; + str = str.replace(/\\/g, '\\\\'); + str = str.replace(/\"/g, '\\"'); + str = str.replace(/\n/g, '\\n'); + str = '"' + str + '"'; + + if (this.language) { + str += '@' + this.language; + } else if (!this.datatype.equals(XSD.string)) { + // Only add datatype if it's not a string + str += '^^' + this.datatype.toCanonical(); + } + return str; } }, { key: 'toString', value: function toString() { - if (this.uri.slice(0, this.base.length) === this.base) { - return '?' + this.uri.slice(this.base.length); + return '' + this.value; + } + /** + * @method fromBoolean + * @static + * @param value {Boolean} + * @return {Literal} + */ + + }, { + key: 'language', + get: function get() { + return this.lang; + }, + set: function set(language) { + this.lang = language || ''; + } + }], [{ + key: 'fromBoolean', + value: function fromBoolean(value) { + var strValue = value ? '1' : '0'; + return new Literal(strValue, null, XSD.boolean); + } + /** + * @method fromDate + * @static + * @param value {Date} + * @return {Literal} + */ + + }, { + key: 'fromDate', + value: function fromDate(value) { + if (!(value instanceof Date)) { + throw new TypeError('Invalid argument to Literal.fromDate()'); } - return '?' + this.uri; + var d2 = function d2(x) { + return ('' + (100 + x)).slice(1, 3); + }; + var date = '' + value.getUTCFullYear() + '-' + d2(value.getUTCMonth() + 1) + '-' + d2(value.getUTCDate()) + 'T' + d2(value.getUTCHours()) + ':' + d2(value.getUTCMinutes()) + ':' + d2(value.getUTCSeconds()) + 'Z'; + return new Literal(date, null, XSD.dateTime); + } + /** + * @method fromNumber + * @static + * @param value {Number} + * @return {Literal} + */ + + }, { + key: 'fromNumber', + value: function fromNumber(value) { + if (typeof value !== 'number') { + throw new TypeError('Invalid argument to Literal.fromNumber()'); + } + var datatype = void 0; + var strValue = value.toString(); + if (strValue.indexOf('e') < 0 && Math.abs(value) <= Number.MAX_SAFE_INTEGER) { + datatype = Number.isInteger(value) ? XSD.integer : XSD.decimal; + } else { + datatype = XSD.double; + } + return new Literal(strValue, null, datatype); + } + /** + * @method fromValue + * @param value + * @return {Literal} + */ + + }, { + key: 'fromValue', + value: function fromValue(value) { + if (typeof value === 'undefined' || value === null) { + return value; + } + if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && value.termType) { + // this is a Node instance + return value; + } + switch (typeof value === 'undefined' ? 'undefined' : _typeof(value)) { + case 'object': + if (value instanceof Date) { + return Literal.fromDate(value); + } + case 'boolean': + return Literal.fromBoolean(value); + case 'number': + return Literal.fromNumber(value); + case 'string': + return new Literal(value); + } + throw new Error("Can't make literal from " + value + ' of type ' + (typeof value === 'undefined' ? 'undefined' : _typeof(value))); } }]); - return Variable; + return Literal; }(Node); -Variable.termType = 'Variable'; -Variable.prototype.classOrder = ClassOrder['Variable']; -Variable.prototype.isVar = 1; +Literal.termType = 'Literal'; +Literal.prototype.classOrder = ClassOrder['Literal']; +Literal.prototype.datatype = XSD.string; +Literal.prototype.lang = ''; +Literal.prototype.isVar = 0; -module.exports = Variable; -},{"./class-order":43,"./node":59,"./uri":72}],75:[function(_dereq_,module,exports){ +module.exports = Literal; +},{"./class-order":240,"./named-node":254,"./node":256,"./xsd":272}],252:[function(_dereq_,module,exports){ +"use strict"; + +/** + * A Dummy log + * @module log + */ +module.exports = { + debug: function debug(x) { + return; + }, + warn: function warn(x) { + return; + }, + info: function info(x) { + return; + }, + error: function error(x) { + return; + }, + success: function success(x) { + return; + }, + msg: function msg(x) { + return; + } +}; +},{}],253:[function(_dereq_,module,exports){ 'use strict'; -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; -var NamedNode = _dereq_('./named-node'); +/** +* +* UTF-8 data encode / decode +* http://www.webtoolkit.info/ +* +**/ +var Uri = _dereq_('./uri'); +var ArrayIndexOf = _dereq_('./util').ArrayIndexOf; -var XSD = function XSD() { - _classCallCheck(this, XSD); -}; +var N3Parser = function () { -XSD.boolean = new NamedNode('http://www.w3.org/2001/XMLSchema#boolean'); -XSD.dateTime = new NamedNode('http://www.w3.org/2001/XMLSchema#dateTime'); -XSD.decimal = new NamedNode('http://www.w3.org/2001/XMLSchema#decimal'); -XSD.double = new NamedNode('http://www.w3.org/2001/XMLSchema#double'); -XSD.integer = new NamedNode('http://www.w3.org/2001/XMLSchema#integer'); -XSD.langString = new NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'); -XSD.string = new NamedNode('http://www.w3.org/2001/XMLSchema#string'); + function hexify(str) { + // also used in parser + return encodeURI(str); + } -module.exports = XSD; -},{"./named-node":57}],76:[function(_dereq_,module,exports){ -arguments[4][25][0].apply(exports,arguments) -},{"./lib/N3Lexer":77,"./lib/N3Parser":78,"./lib/N3Store":79,"./lib/N3StreamParser":80,"./lib/N3StreamWriter":81,"./lib/N3Util":82,"./lib/N3Writer":83,"dup":25}],77:[function(_dereq_,module,exports){ -// **N3Lexer** tokenizes N3 documents. -var fromCharCode = String.fromCharCode; -var immediately = typeof setImmediate === 'function' ? setImmediate : - function setImmediate(func) { setTimeout(func, 0); }; + var Utf8 = { + // public method for url encoding + encode: function encode(string) { + string = string.replace(/\r\n/g, "\n"); + var utftext = ""; -// Regular expression and replacement string to escape N3 strings. -// Note how we catch invalid unicode sequences separately (they will trigger an error). -var escapeSequence = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{8})|\\[uU]|\\(.)/g; -var escapeReplacements = { '\\': '\\', "'": "'", '"': '"', - 'n': '\n', 'r': '\r', 't': '\t', 'f': '\f', 'b': '\b', - '_': '_', '~': '~', '.': '.', '-': '-', '!': '!', '$': '$', '&': '&', - '(': '(', ')': ')', '*': '*', '+': '+', ',': ',', ';': ';', '=': '=', - '/': '/', '?': '?', '#': '#', '@': '@', '%': '%' }; -var illegalIriChars = /[\x00-\x20<>\\"\{\}\|\^\`]/; + for (var n = 0; n < string.length; n++) { -// ## Constructor -function N3Lexer(options) { - if (!(this instanceof N3Lexer)) - return new N3Lexer(options); + var c = string.charCodeAt(n); - // In line mode (N-Triples or N-Quads), only simple features may be parsed - if (options && options.lineMode) { - // Don't tokenize special literals - this._tripleQuotedString = this._number = this._boolean = /$0^/; - // Swap the tokenize method for a restricted version - var self = this; - this._tokenize = this.tokenize; - this.tokenize = function (input, callback) { - this._tokenize(input, function (error, token) { - if (!error && /^(?:IRI|prefixed|literal|langcode|type|\.|eof)$/.test(token.type)) - callback && callback(error, token); - else - callback && callback(error || self._syntaxError(token.type, callback = null)); - }); - }; - } -} + if (c < 128) { + utftext += String.fromCharCode(c); + } else if (c > 127 && c < 2048) { + utftext += String.fromCharCode(c >> 6 | 192); + utftext += String.fromCharCode(c & 63 | 128); + } else { + utftext += String.fromCharCode(c >> 12 | 224); + utftext += String.fromCharCode(c >> 6 & 63 | 128); + utftext += String.fromCharCode(c & 63 | 128); + } + } -N3Lexer.prototype = { - // ## Regular expressions - // It's slightly faster to have these as properties than as in-scope variables. + return utftext; + }, + // public method for url decoding + decode: function decode(utftext) { + var string = ""; + var i = 0; - _iri: /^<((?:[^>\\]|\\[uU])+)>/, // IRI with escape sequences; needs sanity check after unescaping - _unescapedIri: /^<([^\x00-\x20<>\\"\{\}\|\^\`]*)>/, // IRI without escape sequences; no unescaping - _unescapedString: /^"[^"\\]+"(?=[^"\\])/, // non-empty string without escape sequences - _singleQuotedString: /^"[^"\\]*(?:\\.[^"\\]*)*"(?=[^"\\])|^'[^'\\]*(?:\\.[^'\\]*)*'(?=[^'\\])/, - _tripleQuotedString: /^""("[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*")""|^''('[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*')''/, - _langcode: /^@([a-z]+(?:-[a-z0-9]+)*)(?=[^a-z0-9\-])/i, - _prefix: /^((?:[A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:(?=[#\s<])/, - _prefixed: /^((?:[A-Za-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)?:((?:(?:[0-:A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])(?:(?:[\.\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~])*(?:[\-0-:A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff]|%[0-9a-fA-F]{2}|\\[!#-\/;=?\-@_~]))?)?)(?=\.?[,;\s#()\[\]\{\}"'<])/, - _blank: /^_:((?:[0-9A-Z_a-z\xc0-\xd6\xd8-\xf6\xf8-\u02ff\u0370-\u037d\u037f-\u1fff\u200c\u200d\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])(?:\.?[\-0-9A-Z_a-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]|[\ud800-\udb7f][\udc00-\udfff])*)(?=\.?[,;:\s#()\[\]\{\}"'<])/, - _number: /^[\-+]?(?:\d+\.?\d*([eE](?:[\-\+])?\d+)|\d*\.?\d+)(?=[.,;:\s#()\[\]\{\}"'<])/, - _boolean: /^(?:true|false)(?=[.,;:\s#()\[\]\{\}"'<])/, - _keyword: /^@[a-z]+(?=[\s#<:])/, - _sparqlKeyword: /^(?:PREFIX|BASE|GRAPH)(?=[\s#<:])/i, - _shortPredicates: /^a(?=\s+|<)/, - _newline: /^[ \t]*(?:#[^\n\r]*)?(?:\r\n|\n|\r)[ \t]*/, - _whitespace: /^[ \t]+/, - _endOfFile: /^(?:#[^\n\r]*)?$/, + while (i < utftext.length) { + + var c = utftext.charCodeAt(i); + if (c < 128) { + string += String.fromCharCode(c); + i++; + } else if (c > 191 && c < 224) { + string += String.fromCharCode((c & 31) << 6 | utftext.charCodeAt(i + 1) & 63); + i += 2; + } else { + string += String.fromCharCode((c & 15) << 12 | (utftext.charCodeAt(i + 1) & 63) << 6 | utftext.charCodeAt(i + 2) & 63); + i += 3; + } + } + return string; + } + }; // Things we need to define to make converted pythn code work in js + // environment of $rdf - // ## Private methods + var RDFSink_forSomeSym = "http://www.w3.org/2000/10/swap/log#forSome"; + var RDFSink_forAllSym = "http://www.w3.org/2000/10/swap/log#forAll"; + var Logic_NS = "http://www.w3.org/2000/10/swap/log#"; - // ### `_tokenizeToEnd` tokenizes as for as possible, emitting tokens through the callback. - _tokenizeToEnd: function (callback, inputFinished) { - // Continue parsing as far as possible; the loop will return eventually. - var input = this._input; - while (true) { - // Count and skip whitespace lines. - var whiteSpaceMatch; - while (whiteSpaceMatch = this._newline.exec(input)) - input = input.substr(whiteSpaceMatch[0].length, input.length), this._line++; - // Skip whitespace on current line. - if (whiteSpaceMatch = this._whitespace.exec(input)) - input = input.substr(whiteSpaceMatch[0].length, input.length); + // pyjs seems to reference runtime library which I didn't find - // Stop for now if we're at the end. - if (this._endOfFile.test(input)) { - // If the input is finished, emit EOF. - if (inputFinished) - callback(input = null, { line: this._line, type: 'eof', value: '', prefix: '' }); - return this._input = input; - } + var pyjslib_Tuple = function pyjslib_Tuple(theList) { + return theList; + }; - // Look for specific token types based on the first character. - var line = this._line, type = '', value = '', prefix = '', - firstChar = input[0], match = null, matchLength = 0, unescaped, inconclusive = false; - switch (firstChar) { - case '^': - // Try to match a type. - if (input.length === 1) break; - else if (input[1] !== '^') return reportSyntaxError(this); - this._prevTokenType = '^'; - // Move to type IRI or prefixed name. - input = input.substr(2); - if (input[0] !== '<') { - inconclusive = true; - break; - } - // Fall through in case the type is an IRI. + var pyjslib_List = function pyjslib_List(theList) { + return theList; + }; - case '<': - // Try to find a full IRI without escape sequences. - if (match = this._unescapedIri.exec(input)) - type = 'IRI', value = match[1]; - // Try to find a full IRI with escape sequences. - else if (match = this._iri.exec(input)) { - unescaped = this._unescape(match[1]); - if (unescaped === null || illegalIriChars.test(unescaped)) - return reportSyntaxError(this); - type = 'IRI', value = unescaped; - } - break; + var pyjslib_Dict = function pyjslib_Dict(listOfPairs) { + if (listOfPairs.length > 0) throw "missing.js: oops nnonempty dict not imp"; + return []; + }; - case '_': - // Try to find a blank node. Since it can contain (but not end with) a dot, - // we always need a non-dot character before deciding it is a prefixed name. - // Therefore, try inserting a space if we're at the end of the input. - if ((match = this._blank.exec(input)) || - inputFinished && (match = this._blank.exec(input + ' '))) - type = 'prefixed', prefix = '_', value = match[1]; - break; + var pyjslib_len = function pyjslib_len(s) { + return s.length; + }; - case '"': - case "'": - // Try to find a non-empty double-quoted literal without escape sequences. - if (match = this._unescapedString.exec(input)) - type = 'literal', value = match[0]; - // Try to find any other literal wrapped in a pair of single or double quotes. - else if (match = this._singleQuotedString.exec(input)) { - unescaped = this._unescape(match[0]); - if (unescaped === null) - return reportSyntaxError(this); - type = 'literal', value = unescaped.replace(/^'|'$/g, '"'); - } - // Try to find a literal wrapped in three pairs of single or double quotes. - else if (match = this._tripleQuotedString.exec(input)) { - unescaped = match[1] || match[2]; - // Count the newlines and advance line counter. - this._line += unescaped.split(/\r\n|\r|\n/).length - 1; - unescaped = this._unescape(unescaped); - if (unescaped === null) - return reportSyntaxError(this); - type = 'literal', value = unescaped.replace(/^'|'$/g, '"'); - } - break; + var pyjslib_slice = function pyjslib_slice(str, i, j) { + if (typeof str.slice == 'undefined') throw '@@ mising.js: No .slice function for ' + str + ' of type ' + (typeof str === 'undefined' ? 'undefined' : _typeof(str)); + if (typeof j == 'undefined' || j == null) return str.slice(i); + return str.slice(i, j); // @ exactly the same spec? + }; + var StopIteration = Error('dummy error stop iteration'); - case '@': - // Try to find a language code. - if (this._prevTokenType === 'literal' && (match = this._langcode.exec(input))) - type = 'langcode', value = match[1]; - // Try to find a keyword. - else if (match = this._keyword.exec(input)) - type = match[0]; - break; + var pyjslib_Iterator = function pyjslib_Iterator(theList) { + this.last = 0; + this.li = theList; + this.next = function () { + if (this.last == this.li.length) throw StopIteration; + return this.li[this.last++]; + }; + return this; + }; - case '.': - // Try to find a dot as punctuation. - if (input.length === 1 ? inputFinished : (input[1] < '0' || input[1] > '9')) { - type = '.'; - matchLength = 1; - break; - } - // Fall through to numerical case (could be a decimal dot). + var ord = function ord(str) { + return str.charCodeAt(0); + }; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '+': - case '-': - // Try to find a number. - if (match = this._number.exec(input)) { - type = 'literal'; - value = '"' + match[0] + '"^^http://www.w3.org/2001/XMLSchema#' + - (match[1] ? 'double' : (/^[+\-]?\d+$/.test(match[0]) ? 'integer' : 'decimal')); - } - break; + var string_find = function string_find(str, s) { + return str.indexOf(s); + }; - case 'B': - case 'b': - case 'p': - case 'P': - case 'G': - case 'g': - // Try to find a SPARQL-style keyword. - if (match = this._sparqlKeyword.exec(input)) - type = match[0].toUpperCase(); - else - inconclusive = true; - break; + var assertFudge = function assertFudge(condition, desc) { + if (condition) return; + if (desc) throw "python Assertion failed: " + desc; + throw "(python) Assertion failed."; + }; - case 'f': - case 't': - // Try to match a boolean. - if (match = this._boolean.exec(input)) - type = 'literal', value = '"' + match[0] + '"^^http://www.w3.org/2001/XMLSchema#boolean'; - else - inconclusive = true; - break; + var stringFromCharCode = function stringFromCharCode(uesc) { + return String.fromCharCode(uesc); + }; - case 'a': - // Try to find an abbreviated predicate. - if (match = this._shortPredicates.exec(input)) - type = 'abbreviation', value = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; - else - inconclusive = true; - break; + String.prototype.encode = function (encoding) { + if (encoding != 'utf-8') throw "UTF8_converter: can only do utf-8"; + return Utf8.encode(this); + }; + String.prototype.decode = function (encoding) { + if (encoding != 'utf-8') throw "UTF8_converter: can only do utf-8"; + //return Utf8.decode(this); + return this; + }; - case ',': - case ';': - case '[': - case ']': - case '(': - case ')': - case '{': - case '}': - // The next token is punctuation - matchLength = 1; - type = firstChar; - break; + var uripath_join = function uripath_join(base, given) { + return Uri.join(given, base); // sad but true + }; - default: - inconclusive = true; - } + var becauseSubexpression = null; // No reason needed + var diag_tracking = 0; + var diag_chatty_flag = 0; + var diag_progress = function diag_progress(str) {} /*$rdf.log.debug(str);*/ - // Some first characters do not allow an immediate decision, so inspect more. - if (inconclusive) { - // Try to find a prefix. - if ((this._prevTokenType === '@prefix' || this._prevTokenType === 'PREFIX') && - (match = this._prefix.exec(input))) - type = 'prefix', value = match[1] || ''; - // Try to find a prefixed name. Since it can contain (but not end with) a dot, - // we always need a non-dot character before deciding it is a prefixed name. - // Therefore, try inserting a space if we're at the end of the input. - else if ((match = this._prefixed.exec(input)) || - inputFinished && (match = this._prefixed.exec(input + ' '))) - type = 'prefixed', prefix = match[1] || '', value = this._unescape(match[2]); - } + // why_BecauseOfData = function(doc, reason) { return doc }; - // A type token is special: it can only be emitted after an IRI or prefixed name is read. - if (this._prevTokenType === '^') - type = (type === 'IRI' || type === 'prefixed') ? 'type' : ''; - // What if nothing of the above was found? - if (!type) { - // We could be in streaming mode, and then we just wait for more input to arrive. - // Otherwise, a syntax error has occurred in the input. - // One exception: error on an unaccounted linebreak (= not inside a triple-quoted literal). - if (inputFinished || (!/^'''|^"""/.test(input) && /\n|\r/.test(input))) - return reportSyntaxError(this); - else - return this._input = input; - } + ;var RDF_type_URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"; + var DAML_sameAs_URI = "http://www.w3.org/2002/07/owl#sameAs"; - // Emit the parsed token. - callback(null, { line: line, type: type, value: value, prefix: prefix }); - this._prevTokenType = type; + /* + function SyntaxError(details) { + return new __SyntaxError(details); + } + */ - // Advance to next part to tokenize. - input = input.substr(matchLength || match[0].length, input.length); + function __SyntaxError(details) { + this.details = details; } - // Signals the syntax error through the callback - function reportSyntaxError(self) { callback(self._syntaxError(/^\S*/.exec(input)[0])); } - }, + /* + + $Id: n3parser.js 14561 2008-02-23 06:37:26Z kennyluck $ + + HAND EDITED FOR CONVERSION TO JAVASCRIPT + + This module implements a Nptation3 parser, and the final + part of a notation3 serializer. + + See also: + + Notation 3 + http://www.w3.org/DesignIssues/Notation3 + + Closed World Machine - and RDF Processor + http://www.w3.org/2000/10/swap/cwm + + To DO: See also "@@" in comments + + - Clean up interfaces + ______________________________________________ + + Module originally by Dan Connolly, includeing notation3 + parser and RDF generator. TimBL added RDF stream model + and N3 generation, replaced stream model with use + of common store/formula API. Yosi Scharf developped + the module, including tests and test harness. + + */ - // ### `_unescape` replaces N3 escape codes by their corresponding characters. - _unescape: function (item) { - try { - return item.replace(escapeSequence, function (sequence, unicode4, unicode8, escapedChar) { - var charCode; - if (unicode4) { - charCode = parseInt(unicode4, 16); - if (isNaN(charCode)) throw new Error(); // can never happen (regex), but helps performance - return fromCharCode(charCode); + var ADDED_HASH = "#"; + var LOG_implies_URI = "http://www.w3.org/2000/10/swap/log#implies"; + var INTEGER_DATATYPE = "http://www.w3.org/2001/XMLSchema#integer"; + var FLOAT_DATATYPE = "http://www.w3.org/2001/XMLSchema#double"; + var DECIMAL_DATATYPE = "http://www.w3.org/2001/XMLSchema#decimal"; + var DATE_DATATYPE = "http://www.w3.org/2001/XMLSchema#date"; + var DATETIME_DATATYPE = "http://www.w3.org/2001/XMLSchema#dateTime"; + var BOOLEAN_DATATYPE = "http://www.w3.org/2001/XMLSchema#boolean"; + var option_noregen = 0; + var _notQNameChars = "\t\r\n !\"#$%&'()*.,+/;<=>?@[\\]^`{|}~"; + var _notNameChars = _notQNameChars + ":"; + var _rdfns = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + var N3CommentCharacter = "#"; + var eol = new RegExp("^[ \\t]*(#[^\\n]*)?\\r?\\n", 'g'); + var eof = new RegExp("^[ \\t]*(#[^\\n]*)?$", 'g'); + var ws = new RegExp("^[ \\t]*", 'g'); + var signed_integer = new RegExp("^[-+]?[0-9]+", 'g'); + var number_syntax = new RegExp("^([-+]?[0-9]+)(\\.[0-9]+)?(e[-+]?[0-9]+)?", 'g'); + var datetime_syntax = new RegExp('^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9](T[0-9][0-9]:[0-9][0-9](:[0-9][0-9](\\.[0-9]*)?)?)?Z?'); + + var digitstring = new RegExp("^[0-9]+", 'g'); + var interesting = new RegExp("[\\\\\\r\\n\\\"]", 'g'); + var langcode = new RegExp("^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*", 'g'); + function SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why) { + return new __SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why); + } + function __SinkParser(store, openFormula, thisDoc, baseURI, genPrefix, metaURI, flags, why) { + if (typeof openFormula == 'undefined') openFormula = null; + if (typeof thisDoc == 'undefined') thisDoc = ""; + if (typeof baseURI == 'undefined') baseURI = null; + if (typeof genPrefix == 'undefined') genPrefix = ""; + if (typeof metaURI == 'undefined') metaURI = null; + if (typeof flags == 'undefined') flags = ""; + if (typeof why == 'undefined') why = null; + /* + note: namespace names should *not* end in #; + the # will get added during qname processing */ + + this._bindings = new pyjslib_Dict([]); + this._flags = flags; + if (thisDoc != "") { + assertFudge(thisDoc.indexOf(":") >= 0, "Document URI not absolute: " + thisDoc); + this._bindings[""] = thisDoc + "#"; } - else if (unicode8) { - charCode = parseInt(unicode8, 16); - if (isNaN(charCode)) throw new Error(); // can never happen (regex), but helps performance - if (charCode <= 0xFFFF) return fromCharCode(charCode); - return fromCharCode(0xD800 + ((charCode -= 0x10000) / 0x400), 0xDC00 + (charCode & 0x3FF)); + this._store = store; + if (genPrefix) { + store.setGenPrefix(genPrefix); } - else { - var replacement = escapeReplacements[escapedChar]; - if (!replacement) - throw new Error(); - return replacement; + this._thisDoc = thisDoc; + this.source = store.sym(thisDoc); + this.lines = 0; + this.statementCount = 0; + this.startOfLine = 0; + this.previousLine = 0; + this._genPrefix = genPrefix; + this.keywords = new pyjslib_List(["a", "this", "bind", "has", "is", "of", "true", "false"]); + this.keywordsSet = 0; + this._anonymousNodes = new pyjslib_Dict([]); + this._variables = new pyjslib_Dict([]); + this._parentVariables = new pyjslib_Dict([]); + this._reason = why; + this._reason2 = null; + if (diag_tracking) { + this._reason2 = why_BecauseOfData(store.sym(thisDoc), this._reason); } - }); + if (baseURI) { + this._baseURI = baseURI; + } else { + if (thisDoc) { + this._baseURI = thisDoc; + } else { + this._baseURI = null; + } + } + assertFudge(!this._baseURI || this._baseURI.indexOf(":") >= 0); + if (!this._genPrefix) { + if (this._thisDoc) { + this._genPrefix = this._thisDoc + "#_g"; + } else { + this._genPrefix = RDFSink_uniqueURI(); + } + } + if (openFormula == null) { + if (this._thisDoc) { + this._formula = store.formula(thisDoc + "#_formula"); + } else { + this._formula = store.formula(); + } + } else { + this._formula = openFormula; + } + this._context = this._formula; + this._parentContext = null; } - catch (error) { return null; } - }, + __SinkParser.prototype.here = function (i) { + return this._genPrefix + "_L" + this.lines + "C" + (i - this.startOfLine + 1); + }; + __SinkParser.prototype.formula = function () { + return this._formula; + }; + __SinkParser.prototype.loadStream = function (stream) { + return this.loadBuf(stream.read()); + }; + __SinkParser.prototype.loadBuf = function (buf) { + /* + Parses a buffer and returns its top level formula*/ - // ### `_syntaxError` creates a syntax error for the given issue - _syntaxError: function (issue) { - this._input = null; - return new Error('Syntax error: unexpected "' + issue + '" on line ' + this._line + '.'); - }, + this.startDoc(); + this.feed(buf); + return this.endDoc(); + }; + __SinkParser.prototype.feed = function (octets) { + /* + Feed an octet stream tothe parser + if BadSyntax is raised, the string + passed in the exception object is the + remainder after any statements have been parsed. + So if there is more data to feed to the + parser, it should be straightforward to recover.*/ + + var str = octets.decode("utf-8"); + var i = 0; + while (i >= 0) { + var j = this.skipSpace(str, i); + if (j < 0) { + return; + } + var i = this.directiveOrStatement(str, j); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "expected directive or statement"); + } + } + }; + __SinkParser.prototype.directiveOrStatement = function (str, h) { + var i = this.skipSpace(str, h); + if (i < 0) { + return i; + } + var j = this.directive(str, i); + if (j >= 0) { + return this.checkDot(str, j); + } + var j = this.statement(str, i); + if (j >= 0) { + return this.checkDot(str, j); + } + return j; + }; + __SinkParser.prototype.tok = function (tok, str, i) { + /* + Check for keyword. Space must have been stripped on entry and + we must not be at end of file.*/ + var whitespace = "\t\n\v\f\r "; + if (pyjslib_slice(str, i, i + 1) == "@") { + var i = i + 1; + } else { + if (ArrayIndexOf(this.keywords, tok) < 0) { + return -1; + } + } + var k = i + pyjslib_len(tok); + if (pyjslib_slice(str, i, k) == tok && _notQNameChars.indexOf(str.charAt(k)) >= 0) { + return k; + } else { + return -1; + } + }; + __SinkParser.prototype.directive = function (str, i) { + var j = this.skipSpace(str, i); + if (j < 0) { + return j; + } + var res = new pyjslib_List([]); + var j = this.tok("bind", str, i); + if (j > 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "keyword bind is obsolete: use @prefix"); + } + var j = this.tok("keywords", str, i); + if (j > 0) { + var i = this.commaSeparatedList(str, j, res, false); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "'@keywords' needs comma separated list of words"); + } + this.setKeywords(pyjslib_slice(res, null, null)); + if (diag_chatty_flag > 80) { + diag_progress("Keywords ", this.keywords); + } + return i; + } + var j = this.tok("forAll", str, i); + if (j > 0) { + var i = this.commaSeparatedList(str, j, res, true); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad variable list after @forAll"); + } + var __x = new pyjslib_Iterator(res); + try { + while (true) { + var x = __x.next(); - // ## Public methods + if (ArrayIndexOf(this._variables, x) < 0 || ArrayIndexOf(this._parentVariables, x) >= 0) { + this._variables[x] = this._context.newUniversal(x); + } + } + } catch (e) { + if (e != StopIteration) { + throw e; + } + } - // ### `tokenize` starts the transformation of an N3 document into an array of tokens. - // The input can be a string or a stream. - tokenize: function (input, callback) { - var self = this; - this._line = 1; + return i; + } + var j = this.tok("forSome", str, i); + if (j > 0) { + var i = this.commaSeparatedList(str, j, res, this.uri_ref2); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad variable list after @forSome"); + } - // If the input is a string, continuously emit tokens through the callback until the end. - if (typeof input === 'string') { - this._input = input; - immediately(function () { self._tokenizeToEnd(callback, true); }); - } - // Otherwise, the input will be streamed. - else { - this._input = ''; + var __x = new pyjslib_Iterator(res); + try { + while (true) { + var x = __x.next(); - // If no input was given, it will be streamed through `addChunk` and ended with `end` - if (!input || typeof input === 'function') { - this.addChunk = addChunk; - this.end = end; - if (!callback) - callback = input; - } - // Otherwise, the input itself must be a stream - else { - if (typeof input.setEncoding === 'function') - input.setEncoding('utf8'); - input.on('data', addChunk); - input.on('end', end); - } - } + this._context.declareExistential(x); + } + } catch (e) { + if (e != StopIteration) { + throw e; + } + } - // Adds the data chunk to the buffer and parses as far as possible - function addChunk(data) { - if (self._input !== null) { - self._input += data; - self._tokenizeToEnd(callback, false); - } - } + return i; + } + var j = this.tok("prefix", str, i); + if (j >= 0) { + var t = new pyjslib_List([]); + var i = this.qname(str, j, t); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "expected qname after @prefix"); + } + var j = this.uri_ref2(str, i, t); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected after @prefix _qname_"); + } + var ns = t[1].uri; + if (this._baseURI) { + var ns = uripath_join(this._baseURI, ns); + } else { + assertFudge(ns.indexOf(":") >= 0, "With no base URI, cannot handle relative URI for NS"); + } + assertFudge(ns.indexOf(":") >= 0); + this._bindings[t[0][0]] = ns; - // Parses until the end - function end() { - if (self._input !== null) - self._tokenizeToEnd(callback, true); - } - }, -}; + this.bind(t[0][0], hexify(ns)); + return j; + } + var j = this.tok("base", str, i); + if (j >= 0) { + var t = new pyjslib_List([]); + var i = this.uri_ref2(str, j, t); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "expected after @base "); + } + var ns = t[0].uri; + if (this._baseURI) { + var ns = uripath_join(this._baseURI, ns); + } else { + throw BadSyntax(this._thisDoc, this.lines, str, j, "With no previous base URI, cannot use relative URI in @base <" + ns + ">"); + } + assertFudge(ns.indexOf(":") >= 0); + this._baseURI = ns; + return i; + } + return -1; + }; + __SinkParser.prototype.bind = function (qn, uri) { + if (qn == "") {} else { + this._store.setPrefixForURI(qn, uri); + } + }; + __SinkParser.prototype.setKeywords = function (k) { + /* + Takes a list of strings*/ -// ## Exports + if (k == null) { + this.keywordsSet = 0; + } else { + this.keywords = k; + this.keywordsSet = 1; + } + }; + __SinkParser.prototype.startDoc = function () {}; + __SinkParser.prototype.endDoc = function () { + /* + Signal end of document and stop parsing. returns formula*/ -// Export the `N3Lexer` class as a whole. -module.exports = N3Lexer; + return this._formula; + }; + __SinkParser.prototype.makeStatement = function (quad) { + quad[0].add(quad[2], quad[1], quad[3], this.source); + this.statementCount += 1; + }; + __SinkParser.prototype.statement = function (str, i) { + var r = new pyjslib_List([]); + var i = this.object(str, i, r); + if (i < 0) { + return i; + } + var j = this.property_list(str, i, r[0]); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected propertylist"); + } + return j; + }; + __SinkParser.prototype.subject = function (str, i, res) { + return this.item(str, i, res); + }; + __SinkParser.prototype.verb = function (str, i, res) { + /* + has _prop_ + is _prop_ of + a + = + _prop_ + >- prop -> + <- prop -< + _operator_*/ -},{}],78:[function(_dereq_,module,exports){ -// **N3Parser** parses N3 documents. -var N3Lexer = _dereq_('./N3Lexer'); + var j = this.skipSpace(str, i); + if (j < 0) { + return j; + } + var r = new pyjslib_List([]); + var j = this.tok("has", str, i); + if (j >= 0) { + var i = this.prop(str, j, r); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "expected property after 'has'"); + } + res.push(new pyjslib_Tuple(["->", r[0]])); + return i; + } + var j = this.tok("is", str, i); + if (j >= 0) { + var i = this.prop(str, j, r); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "expected after 'is'"); + } + var j = this.skipSpace(str, i); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "End of file found, expected property after 'is'"); + return j; + } + var i = j; + var j = this.tok("of", str, i); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected 'of' after 'is' "); + } + res.push(new pyjslib_Tuple(["<-", r[0]])); + return j; + } + var j = this.tok("a", str, i); + if (j >= 0) { + res.push(new pyjslib_Tuple(["->", this._store.sym(RDF_type_URI)])); + return j; + } + if (pyjslib_slice(str, i, i + 2) == "<=") { + res.push(new pyjslib_Tuple(["<-", this._store.sym(Logic_NS + "implies")])); + return i + 2; + } + if (pyjslib_slice(str, i, i + 1) == "=") { + if (pyjslib_slice(str, i + 1, i + 2) == ">") { + res.push(new pyjslib_Tuple(["->", this._store.sym(Logic_NS + "implies")])); + return i + 2; + } + res.push(new pyjslib_Tuple(["->", this._store.sym(DAML_sameAs_URI)])); + return i + 1; + } + if (pyjslib_slice(str, i, i + 2) == ":=") { + res.push(new pyjslib_Tuple(["->", Logic_NS + "becomes"])); + return i + 2; + } + var j = this.prop(str, i, r); + if (j >= 0) { + res.push(new pyjslib_Tuple(["->", r[0]])); + return j; + } + if (pyjslib_slice(str, i, i + 2) == ">-" || pyjslib_slice(str, i, i + 2) == "<-") { + throw BadSyntax(this._thisDoc, this.lines, str, j, ">- ... -> syntax is obsolete."); + } + return -1; + }; + __SinkParser.prototype.prop = function (str, i, res) { + return this.item(str, i, res); + }; + __SinkParser.prototype.item = function (str, i, res) { + return this.path(str, i, res); + }; + __SinkParser.prototype.blankNode = function (uri) { + return this._context.bnode(uri, this._reason2); + }; + __SinkParser.prototype.path = function (str, i, res) { + /* + Parse the path production. + */ -var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', - RDF_NIL = RDF_PREFIX + 'nil', - RDF_FIRST = RDF_PREFIX + 'first', - RDF_REST = RDF_PREFIX + 'rest'; + var j = this.nodeOrLiteral(str, i, res); + if (j < 0) { + return j; + } + while ("!^.".indexOf(pyjslib_slice(str, j, j + 1)) >= 0) { + var ch = pyjslib_slice(str, j, j + 1); + if (ch == ".") { + var ahead = pyjslib_slice(str, j + 1, j + 2); + if (!ahead || _notNameChars.indexOf(ahead) >= 0 && ":?<[{(".indexOf(ahead) < 0) { + break; + } + } + var subj = res.pop(); + var obj = this.blankNode(this.here(j)); + var j = this.node(str, j + 1, res); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found in middle of path syntax"); + } + var pred = res.pop(); + if (ch == "^") { + this.makeStatement(new pyjslib_Tuple([this._context, pred, obj, subj])); + } else { + this.makeStatement(new pyjslib_Tuple([this._context, pred, subj, obj])); + } + res.push(obj); + } + return j; + }; + __SinkParser.prototype.anonymousNode = function (ln) { + /* + Remember or generate a term for one of these _: anonymous nodes*/ -var absoluteIRI = /^[a-z][a-z0-9+.-]*:/i, - schemeAuthority = /^(?:([a-z][a-z0-9+.-]*:))?(?:\/\/[^\/]*)?/i, - dotSegments = /(?:^|\/)\.\.?(?:$|[\/#?])/; + var term = this._anonymousNodes[ln]; + if (term) { + return term; + } + var term = this._store.bnode(this._context, this._reason2); + this._anonymousNodes[ln] = term; + return term; + }; + __SinkParser.prototype.node = function (str, i, res, subjectAlready) { + if (typeof subjectAlready == 'undefined') subjectAlready = null; + /* + Parse the production. + Space is now skipped once at the beginning + instead of in multipe calls to self.skipSpace(). + */ -// The next ID for new blank nodes -var blankNodePrefix = 0, blankNodeCount = 0; + var subj = subjectAlready; + var j = this.skipSpace(str, i); + if (j < 0) { + return j; + } + var i = j; + var ch = pyjslib_slice(str, i, i + 1); + if (ch == "[") { + var bnodeID = this.here(i); + var j = this.skipSpace(str, i + 1); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF after '['"); + } + if (pyjslib_slice(str, j, j + 1) == "=") { + var i = j + 1; + var objs = new pyjslib_List([]); + var j = this.objectList(str, i, objs); -// ## Constructor -function N3Parser(options) { - if (!(this instanceof N3Parser)) - return new N3Parser(options); - this._tripleStack = []; - this._graph = null; + if (j >= 0) { + var subj = objs[0]; + if (pyjslib_len(objs) > 1) { - // Set the document IRI. - options = options || {}; - this._setBase(options.documentIRI); + var __obj = new pyjslib_Iterator(objs); + try { + while (true) { + var obj = __obj.next(); - // Set supported features depending on the format. - var format = (typeof options.format === 'string') && options.format.match(/\w*$/)[0].toLowerCase(), - isTurtle = format === 'turtle', isTriG = format === 'trig', - isNTriples = /triple/.test(format), isNQuads = /quad/.test(format), - isLineMode = isNTriples || isNQuads; - if (!(this._supportsNamedGraphs = !isTurtle)) - this._readPredicateOrNamedGraph = this._readPredicate; - this._supportsQuads = !(isTurtle || isTriG || isNTriples); - // Disable relative IRIs in N-Triples or N-Quads mode - if (isLineMode) { - this._base = ''; - this._resolveIRI = function (token) { - this._error('Disallowed relative IRI', token); - return this._callback = noop, this._subject = null; + this.makeStatement(new pyjslib_Tuple([this._context, this._store.sym(DAML_sameAs_URI), subj, obj])); + } + } catch (e) { + if (e != StopIteration) { + throw e; + } + } + } + var j = this.skipSpace(str, j); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF when objectList expected after [ = "); + } + if (pyjslib_slice(str, j, j + 1) == ";") { + var j = j + 1; + } + } else { + throw BadSyntax(this._thisDoc, this.lines, str, i, "objectList expected after [= "); + } + } + if (subj == null) { + var subj = this.blankNode(bnodeID); + } + var i = this.property_list(str, j, subj); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "property_list expected"); + } + var j = this.skipSpace(str, i); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF when ']' expected after [ "); + } + if (pyjslib_slice(str, j, j + 1) != "]") { + throw BadSyntax(this._thisDoc, this.lines, str, j, "']' expected"); + } + res.push(subj); + return j + 1; + } + if (ch == "{") { + var ch2 = pyjslib_slice(str, i + 1, i + 2); + if (ch2 == "$") { + i += 1; + var j = i + 1; + var mylist = new pyjslib_List([]); + var first_run = true; + while (1) { + var i = this.skipSpace(str, j); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "needed '$}', found end."); + } + if (pyjslib_slice(str, i, i + 2) == "$}") { + var j = i + 2; + break; + } + if (!first_run) { + if (pyjslib_slice(str, i, i + 1) == ",") { + i += 1; + } else { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected: ','"); + } + } else { + var first_run = false; + } + var item = new pyjslib_List([]); + var j = this.item(str, i, item); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected item in set or '$}'"); + } + mylist.push(item[0]); + } + res.push(this._store.newSet(mylist, this._context)); + return j; + } else { + var j = i + 1; + var oldParentContext = this._parentContext; + this._parentContext = this._context; + var parentAnonymousNodes = this._anonymousNodes; + var grandParentVariables = this._parentVariables; + this._parentVariables = this._variables; + this._anonymousNodes = new pyjslib_Dict([]); + this._variables = this._variables.slice(); + var reason2 = this._reason2; + this._reason2 = becauseSubexpression; + if (subj == null) { + var subj = this._store.formula(); + } + this._context = subj; + while (1) { + var i = this.skipSpace(str, j); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "needed '}', found end."); + } + if (pyjslib_slice(str, i, i + 1) == "}") { + var j = i + 1; + break; + } + var j = this.directiveOrStatement(str, i); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected statement or '}'"); + } + } + this._anonymousNodes = parentAnonymousNodes; + this._variables = this._parentVariables; + this._parentVariables = grandParentVariables; + this._context = this._parentContext; + this._reason2 = reason2; + this._parentContext = oldParentContext; + res.push(subj.close()); + return j; + } + } + if (ch == "(") { + var thing_type = this._store.list; + var ch2 = pyjslib_slice(str, i + 1, i + 2); + if (ch2 == "$") { + var thing_type = this._store.newSet; + i += 1; + } + var j = i + 1; + var mylist = new pyjslib_List([]); + while (1) { + var i = this.skipSpace(str, j); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "needed ')', found end."); + } + if (pyjslib_slice(str, i, i + 1) == ")") { + var j = i + 1; + break; + } + var item = new pyjslib_List([]); + var j = this.item(str, i, item); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "expected item in list or ')'"); + } + mylist.push(item[0]); + } + res.push(thing_type(mylist, this._context)); + return j; + } + var j = this.tok("this", str, i); + if (j >= 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "Keyword 'this' was ancient N3. Now use @forSome and @forAll keywords."); + res.push(this._context); + return j; + } + var j = this.tok("true", str, i); + if (j >= 0) { + res.push(true); + return j; + } + var j = this.tok("false", str, i); + if (j >= 0) { + res.push(false); + return j; + } + if (subj == null) { + var j = this.uri_ref2(str, i, res); + if (j >= 0) { + return j; + } + } + return -1; }; - } - this._blankNodePrefix = typeof options.blankNodePrefix !== 'string' ? '' : - '_:' + options.blankNodePrefix.replace(/^_:/, ''); - this._lexer = options.lexer || new N3Lexer({ lineMode: isLineMode }); -} - -// ## Private class methods - -// ### `_resetBlankNodeIds` restarts blank node identification. -N3Parser._resetBlankNodeIds = function () { - blankNodePrefix = blankNodeCount = 0; -}; - -N3Parser.prototype = { - // ## Private methods - - // ### `_setBase` sets the base IRI to resolve relative IRIs. - _setBase: function (baseIRI) { - if (!baseIRI) - baseIRI = null; - else if (baseIRI.indexOf('#') >= 0) - throw new Error('Invalid base IRI ' + baseIRI); - // Set base IRI and its components - if (this._base = baseIRI) { - this._basePath = baseIRI.replace(/[^\/?]*(?:\?.*)?$/, ''); - baseIRI = baseIRI.match(schemeAuthority); - this._baseRoot = baseIRI[0]; - this._baseScheme = baseIRI[1]; - } - }, - - // ### `_readInTopContext` reads a token when in the top context. - _readInTopContext: function (token) { - switch (token.type) { - // If an EOF token arrives in the top context, signal that we're done. - case 'eof': - if (this._graph !== null) - return this._error('Unclosed graph', token); - delete this._prefixes._; - return this._callback(null, null, this._prefixes); - // It could be a prefix declaration. - case '@prefix': - this._sparqlStyle = false; - return this._readPrefix; - case 'PREFIX': - this._sparqlStyle = true; - return this._readPrefix; - // It could be a base declaration. - case '@base': - this._sparqlStyle = false; - return this._readBaseIRI; - case 'BASE': - this._sparqlStyle = true; - return this._readBaseIRI; - // It could be a graph. - case '{': - if (this._supportsNamedGraphs) { - this._graph = ''; - this._subject = null; - return this._readSubject; - } - case 'GRAPH': - if (this._supportsNamedGraphs) - return this._readNamedGraphLabel; - // Otherwise, the next token must be a subject. - default: - return this._readSubject(token); - } - }, + __SinkParser.prototype.property_list = function (str, i, subj) { + /* + Parse property list + Leaves the terminating punctuation in the buffer + */ - // ### `_readSubject` reads a triple's subject. - _readSubject: function (token) { - this._predicate = null; - switch (token.type) { - case 'IRI': - if (this._base === null || absoluteIRI.test(token.value)) - this._subject = token.value; - else - this._subject = this._resolveIRI(token); - break; - case 'prefixed': - var prefix = this._prefixes[token.prefix]; - if (prefix === undefined) - return this._error('Undefined prefix "' + token.prefix + ':"', token); - this._subject = prefix + token.value; - break; - case '[': - // Start a new triple with a new blank node as subject. - this._subject = '_:b' + blankNodeCount++; - this._tripleStack.push({ subject: this._subject, predicate: null, object: null, type: 'blank' }); - return this._readBlankNodeHead; - case '(': - // Start a new list - this._tripleStack.push({ subject: RDF_NIL, predicate: null, object: null, type: 'list' }); - this._subject = null; - return this._readListItem; - case '}': - return this._readPunctuation(token); - default: - return this._error('Expected subject but got ' + token.type, token); - } - // The next token must be a predicate, - // or, if the subject was actually a graph IRI, a named graph. - return this._readPredicateOrNamedGraph; - }, + while (1) { + var j = this.skipSpace(str, i); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF found when expected verb in property list"); + return j; + } + if (pyjslib_slice(str, j, j + 2) == ":-") { + var i = j + 2; + var res = new pyjslib_List([]); + var j = this.node(str, i, res, subj); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "bad {} or () or [] node after :- "); + } + var i = j; + continue; + } + var i = j; + var v = new pyjslib_List([]); + var j = this.verb(str, i, v); + if (j <= 0) { + return i; + } + var objs = new pyjslib_List([]); + var i = this.objectList(str, j, objs); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "objectList expected"); + } - // ### `_readPredicate` reads a triple's predicate. - _readPredicate: function (token) { - var type = token.type; - switch (type) { - case 'IRI': - case 'abbreviation': - if (this._base === null || absoluteIRI.test(token.value)) - this._predicate = token.value; - else - this._predicate = this._resolveIRI(token); - break; - case 'prefixed': - if (token.prefix === '_') - return this._error('Disallowed blank node as predicate', token); - var prefix = this._prefixes[token.prefix]; - if (prefix === undefined) - return this._error('Undefined prefix "' + token.prefix + ':"', token); - this._predicate = prefix + token.value; - break; - case '.': - case ']': - case '}': - // Expected predicate didn't come, must have been trailing semicolon. - if (this._predicate === null) - return this._error('Unexpected ' + type, token); - this._subject = null; - return type === ']' ? this._readBlankNodeTail(token) : this._readPunctuation(token); - case ';': - // Extra semicolons can be safely ignored - return this._readPredicate; - default: - return this._error('Expected predicate to follow "' + this._subject + '"', token); - } - // The next token must be an object. - return this._readObject; - }, + var __obj = new pyjslib_Iterator(objs); + try { + while (true) { + var obj = __obj.next(); - // ### `_readObject` reads a triple's object. - _readObject: function (token) { - switch (token.type) { - case 'IRI': - if (this._base === null || absoluteIRI.test(token.value)) - this._object = token.value; - else - this._object = this._resolveIRI(token); - break; - case 'prefixed': - var prefix = this._prefixes[token.prefix]; - if (prefix === undefined) - return this._error('Undefined prefix "' + token.prefix + ':"', token); - this._object = prefix + token.value; - break; - case 'literal': - this._object = token.value; - return this._readDataTypeOrLang; - case '[': - // Start a new triple with a new blank node as subject. - var blank = '_:b' + blankNodeCount++; - this._tripleStack.push({ subject: this._subject, predicate: this._predicate, object: blank, type: 'blank' }); - this._subject = blank; - return this._readBlankNodeHead; - case '(': - // Start a new list - this._tripleStack.push({ subject: this._subject, predicate: this._predicate, object: RDF_NIL, type: 'list' }); - this._subject = null; - return this._readListItem; - default: - return this._error('Expected object to follow "' + this._predicate + '"', token); - } - return this._getTripleEndReader(); - }, + var pairFudge = v[0]; + var dir = pairFudge[0]; + var sym = pairFudge[1]; + if (dir == "->") { + this.makeStatement(new pyjslib_Tuple([this._context, sym, subj, obj])); + } else { + this.makeStatement(new pyjslib_Tuple([this._context, sym, obj, subj])); + } + } + } catch (e) { + if (e != StopIteration) { + throw e; + } + } - // ### `_readPredicateOrNamedGraph` reads a triple's predicate, or a named graph. - _readPredicateOrNamedGraph: function (token) { - return token.type === '{' ? this._readGraph(token) : this._readPredicate(token); - }, + var j = this.skipSpace(str, i); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found in list of objects"); + return j; + } + if (pyjslib_slice(str, i, i + 1) != ";") { + return i; + } + var i = i + 1; + } + }; + __SinkParser.prototype.commaSeparatedList = function (str, j, res, ofUris) { + /* + return value: -1 bad syntax; >1 new position in str + res has things found appended + Used to use a final value of the function to be called, e.g. this.bareWord + but passing the function didn't work fo js converion pyjs + */ - // ### `_readGraph` reads a graph. - _readGraph: function (token) { - if (token.type !== '{') - return this._error('Expected graph but got ' + token.type, token); - // The "subject" we read is actually the GRAPH's label - this._graph = this._subject, this._subject = null; - return this._readSubject; - }, + var i = this.skipSpace(str, j); + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "EOF found expecting comma sep list"); + return i; + } + if (str.charAt(i) == ".") { + return j; + } + if (ofUris) { + var i = this.uri_ref2(str, i, res); + } else { + var i = this.bareWord(str, i, res); + } + if (i < 0) { + return -1; + } + while (1) { + var j = this.skipSpace(str, i); + if (j < 0) { + return j; + } + var ch = pyjslib_slice(str, j, j + 1); + if (ch != ",") { + if (ch != ".") { + return -1; + } + return j; + } + if (ofUris) { + var i = this.uri_ref2(str, j + 1, res); + } else { + var i = this.bareWord(str, j + 1, res); + } + if (i < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "bad list content"); + return i; + } + } + }; + __SinkParser.prototype.objectList = function (str, i, res) { + var i = this.object(str, i, res); + if (i < 0) { + return -1; + } + while (1) { + var j = this.skipSpace(str, i); + if (j < 0) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "EOF found after object"); + return j; + } + if (pyjslib_slice(str, j, j + 1) != ",") { + return j; + } + var i = this.object(str, j + 1, res); + if (i < 0) { + return i; + } + } + }; + __SinkParser.prototype.checkDot = function (str, i) { + var j = this.skipSpace(str, i); + if (j < 0) { + return j; + } + if (pyjslib_slice(str, j, j + 1) == ".") { + return j + 1; + } + if (pyjslib_slice(str, j, j + 1) == "}") { + return j; + } + if (pyjslib_slice(str, j, j + 1) == "]") { + return j; + } + throw BadSyntax(this._thisDoc, this.lines, str, j, "expected '.' or '}' or ']' at end of statement"); + return i; + }; + __SinkParser.prototype.uri_ref2 = function (str, i, res) { + /* + Generate uri from n3 representation. + Note that the RDF convention of directly concatenating + NS and local name is now used though I prefer inserting a '#' + to make the namesapces look more like what XML folks expect. + */ - // ### `_readBlankNodeHead` reads the head of a blank node. - _readBlankNodeHead: function (token) { - if (token.type === ']') { - this._subject = null; - return this._readBlankNodeTail(token); - } - else { - this._predicate = null; - return this._readPredicate(token); - } - }, + var qn = new pyjslib_List([]); + var j = this.qname(str, i, qn); + if (j >= 0) { + var pairFudge = qn[0]; + var pfx = pairFudge[0]; + var ln = pairFudge[1]; + if (pfx == null) { + assertFudge(0, "not used?"); + var ns = this._baseURI + ADDED_HASH; + } else { + var ns = this._bindings[pfx]; + if (!ns) { + if (pfx == "_") { + res.push(this.anonymousNode(ln)); + return j; + } + throw BadSyntax(this._thisDoc, this.lines, str, i, "Prefix " + pfx + " not bound."); + } + } + var symb = this._store.sym(ns + ln); + if (ArrayIndexOf(this._variables, symb) >= 0) { + res.push(this._variables[symb]); + } else { + res.push(symb); + } + return j; + } + var i = this.skipSpace(str, i); + if (i < 0) { + return -1; + } + if (str.charAt(i) == "?") { + var v = new pyjslib_List([]); + var j = this.variable(str, i, v); + if (j > 0) { + res.push(v[0]); + return j; + } + return -1; + } else if (str.charAt(i) == "<") { + var i = i + 1; + var st = i; + while (i < pyjslib_len(str)) { + if (str.charAt(i) == ">") { + var uref = pyjslib_slice(str, st, i); + if (this._baseURI) { + var uref = uripath_join(this._baseURI, uref); + } else { + assertFudge(uref.indexOf(":") >= 0, "With no base URI, cannot deal with relative URIs"); + } + if (pyjslib_slice(str, i - 1, i) == "#" && !(pyjslib_slice(uref, -1, null) == "#")) { + var uref = uref + "#"; + } + var symb = this._store.sym(uref); + if (ArrayIndexOf(this._variables, symb) >= 0) { + res.push(this._variables[symb]); + } else { + res.push(symb); + } + return i + 1; + } + var i = i + 1; + } + throw BadSyntax(this._thisDoc, this.lines, str, j, "unterminated URI reference"); + } else if (this.keywordsSet) { + var v = new pyjslib_List([]); + var j = this.bareWord(str, i, v); + if (j < 0) { + return -1; + } + if (ArrayIndexOf(this.keywords, v[0]) >= 0) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "Keyword \"" + v[0] + "\" not allowed here."); + } + res.push(this._store.sym(this._bindings[""] + v[0])); + return j; + } else { + return -1; + } + }; + __SinkParser.prototype.skipSpace = function (str, i) { + /* + Skip white space, newlines and comments. + return -1 if EOF, else position of first non-ws character*/ - // ### `_readBlankNodeTail` reads the end of a blank node. - _readBlankNodeTail: function (token) { - if (token.type !== ']') - return this._readBlankNodePunctuation(token); + var whitespace = ' \n\r\t\f\x0B\xA0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u200B\u2028\u2029\u3000'; + for (var j = i ? i : 0; j < str.length; j++) { + var ch = str.charAt(j); + // console.log(" skipspace j= "+j + " i= " + i + " n= " + str.length); + // console.log(" skipspace ch <" + ch + ">"); + if (whitespace.indexOf(ch) < 0) { + //not ws + // console.log(" skipspace 2 ch <" + ch + ">"); + if (str.charAt(j) === '#') { + for (;; j++) { + // console.log(" skipspace2 j= "+j + " i= " + i + " n= " + str.length); + if (j === str.length) { + return -1; // EOF + } + if (str.charAt(j) === '\n') { + this.lines = this.lines + 1; + break; + } + }; + } else { + // Not hash - something interesting + // console.log(" skipspace 3 ch <" + ch + ">"); + return j; + } + } else { + // Whitespace + // console.log(" skipspace 5 ch <" + ch + ">"); + if (str.charAt(j) === '\n') { + this.lines = this.lines + 1; + } + } + } // next j + return -1; // EOF + }; - // Store blank node triple. - if (this._subject !== null) - this._callback(null, { subject: this._subject, - predicate: this._predicate, - object: this._object, - graph: this._graph || '' }); + __SinkParser.prototype.variable = function (str, i, res) { + /* + ?abc -> variable(:abc) + */ - // Restore parent triple that contains the blank node. - var triple = this._tripleStack.pop(); - this._subject = triple.subject; - // Was the blank node the object? - if (triple.object !== null) { - // Restore predicate and object as well, and continue by reading punctuation. - this._predicate = triple.predicate; - this._object = triple.object; - return this._getTripleEndReader(); - } - // The blank node was the subject, so continue reading the predicate. - // If the blank node didn't contain any predicates, it could also be the label of a named graph. - return this._predicate !== null ? this._readPredicate : this._readPredicateOrNamedGraph; - }, + var j = this.skipSpace(str, i); + if (j < 0) { + return -1; + } + if (pyjslib_slice(str, j, j + 1) != "?") { + return -1; + } + var j = j + 1; + var i = j; + if ("0123456789-".indexOf(str.charAt(j)) >= 0) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "Varible name can't start with '" + str.charAt(j) + "s'"); + return -1; + } + while (i < pyjslib_len(str) && _notNameChars.indexOf(str.charAt(i)) < 0) { + var i = i + 1; + } + if (this._parentContext == null) { + throw BadSyntax(this._thisDoc, this.lines, str, j, "Can't use ?xxx syntax for variable in outermost level: " + pyjslib_slice(str, j - 1, i)); + } + res.push(this._store.variable(pyjslib_slice(str, j, i))); + return i; + }; + __SinkParser.prototype.bareWord = function (str, i, res) { + /* + abc -> :abc + */ - // ### `_readDataTypeOrLang` reads an _optional_ data type or language. - _readDataTypeOrLang: function (token) { - switch (token.type) { - case 'type': - var value; - if (token.prefix === '') { - if (this._base === null || absoluteIRI.test(token.value)) - value = token.value; - else - value = this._resolveIRI(token); - } - else { - var prefix = this._prefixes[token.prefix]; - if (prefix === undefined) - return this._error('Undefined prefix "' + token.prefix + ':"', token); - value = prefix + token.value; - } - this._object += '^^' + value; - return this._getTripleEndReader(); - case 'langcode': - this._object += '@' + token.value.toLowerCase(); - return this._getTripleEndReader(); - default: - return this._getTripleEndReader().call(this, token); - } - }, + var j = this.skipSpace(str, i); + if (j < 0) { + return -1; + } + var ch = str.charAt(j); + if ("0123456789-".indexOf(ch) >= 0) { + return -1; + } + if (_notNameChars.indexOf(ch) >= 0) { + return -1; + } + var i = j; + while (i < pyjslib_len(str) && _notNameChars.indexOf(str.charAt(i)) < 0) { + var i = i + 1; + } + res.push(pyjslib_slice(str, j, i)); + return i; + }; + __SinkParser.prototype.qname = function (str, i, res) { + /* + xyz:def -> ('xyz', 'def') + If not in keywords and keywordsSet: def -> ('', 'def') + :def -> ('', 'def') + */ - // ### `_readListItem` reads items from a list. - _readListItem: function (token) { - var item = null, // The actual list item. - itemHead = null, // The head of the rdf:first predicate. - prevItemHead = this._subject, // The head of the previous rdf:first predicate. - stack = this._tripleStack, // The stack of triples part of recursion (lists, blanks, etc.). - parentTriple = stack[stack.length - 1], // The triple containing the current list. - next = this._readListItem; // The next function to execute. + var i = this.skipSpace(str, i); + if (i < 0) { + return -1; + } + var c = str.charAt(i); + if ("0123456789-+".indexOf(c) >= 0) { + return -1; + } + if (_notNameChars.indexOf(c) < 0) { + var ln = c; + var i = i + 1; + while (i < pyjslib_len(str)) { + var c = str.charAt(i); + if (_notNameChars.indexOf(c) < 0) { + var ln = ln + c; + var i = i + 1; + } else { + break; + } + } + } else { + var ln = ""; + } + if (i < pyjslib_len(str) && str.charAt(i) == ":") { + var pfx = ln; + var i = i + 1; + var ln = ""; + while (i < pyjslib_len(str)) { + var c = str.charAt(i); + if (_notNameChars.indexOf(c) < 0) { + var ln = ln + c; + var i = i + 1; + } else { + break; + } + } + res.push(new pyjslib_Tuple([pfx, ln])); + return i; + } else { + if (ln && this.keywordsSet && ArrayIndexOf(this.keywords, ln) < 0) { + res.push(new pyjslib_Tuple(["", ln])); + return i; + } + return -1; + } + }; + __SinkParser.prototype.object = function (str, i, res) { + var j = this.subject(str, i, res); + if (j >= 0) { + return j; + } else { + var j = this.skipSpace(str, i); + if (j < 0) { + return -1; + } else { + var i = j; + } + if (str.charAt(i) == "\"") { + if (pyjslib_slice(str, i, i + 3) == "\"\"\"") { + var delim = "\"\"\""; + } else { + var delim = "\""; + } + var i = i + pyjslib_len(delim); + var pairFudge = this.strconst(str, i, delim); + var j = pairFudge[0]; + var s = pairFudge[1]; + res.push(this._store.literal(s)); + diag_progress("New string const ", s, j); + return j; + } else { + return -1; + } + } + }; + __SinkParser.prototype.nodeOrLiteral = function (str, i, res) { + var j = this.node(str, i, res); + if (j >= 0) { + return j; + } else { + var j = this.skipSpace(str, i); + if (j < 0) { + return -1; + } else { + var i = j; + } + var ch = str.charAt(i); + if ("-+0987654321".indexOf(ch) >= 0) { - switch (token.type) { - case 'IRI': - if (this._base === null || absoluteIRI.test(token.value)) - item = token.value; - else - item = this._resolveIRI(token); - break; - case 'prefixed': - var prefix = this._prefixes[token.prefix]; - if (prefix === undefined) - return this._error('Undefined prefix "' + token.prefix + ':"', token); - item = prefix + token.value; - break; - case 'literal': - item = token.value; - next = this._readDataTypeOrLang; - break; - case '[': - // Stack the current list triple and start a new triple with a blank node as subject. - itemHead = '_:b' + blankNodeCount++; - item = '_:b' + blankNodeCount++; - stack.push({ subject: itemHead, predicate: RDF_FIRST, object: item, type: 'blank' }); - this._subject = item; - next = this._readBlankNodeHead; - break; - case '(': - // Stack the current list triple and start a new list - itemHead = '_:b' + blankNodeCount++; - stack.push({ subject: itemHead, predicate: RDF_FIRST, object: RDF_NIL, type: 'list' }); - this._subject = null; - next = this._readListItem; - break; - case ')': - // Restore the parent triple. - stack.pop(); - // If this list is contained within a parent list, return the membership triple here. - // This will be ` rdf:first .`. - if (stack.length !== 0 && stack[stack.length - 1].type === 'list') - this._callback(null, { subject: parentTriple.subject, - predicate: parentTriple.predicate, - object: parentTriple.object, - graph: this._graph || '' }); - // Restore the parent triple's subject. - this._subject = parentTriple.subject; - // Was this list in the parent triple's subject? - if (parentTriple.predicate === null) { - // The next token is the predicate. - next = this._readPredicate; - // Skip writing the list tail if this was an empty list. - if (parentTriple.subject === RDF_NIL) - return next; - } - // The list was in the parent triple's object. - else { - // Restore the parent triple's predicate and object as well. - this._predicate = parentTriple.predicate; - this._object = parentTriple.object; - next = this._getTripleEndReader(); - // Skip writing the list tail if this was an empty list. - if (parentTriple.object === RDF_NIL) - return next; - } - // Close the list by making the item head nil. - itemHead = RDF_NIL; - break; - default: - return this._error('Expected list item instead of "' + token.type + '"', token); - } + datetime_syntax.lastIndex = 0; + var m = datetime_syntax.exec(str.slice(i)); + if (m != null) { + // j = ( i + datetime_syntax.lastIndex ) ; + var val = m[0]; + j = i + val.length; + if (val.indexOf("T") >= 0) { + res.push(this._store.literal(val, undefined, this._store.sym(DATETIME_DATATYPE))); + } else { + res.push(this._store.literal(val, undefined, this._store.sym(DATE_DATATYPE))); + } + } else { + number_syntax.lastIndex = 0; + var m = number_syntax.exec(str.slice(i)); + if (m == null) { + throw BadSyntax(this._thisDoc, this.lines, str, i, "Bad number or date syntax"); + } + j = i + number_syntax.lastIndex; + var val = pyjslib_slice(str, i, j); + if (val.indexOf("e") >= 0) { + res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(FLOAT_DATATYPE))); + } else if (pyjslib_slice(str, i, j).indexOf(".") >= 0) { + res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(DECIMAL_DATATYPE))); + } else { + res.push(this._store.literal(parseInt(val), undefined, this._store.sym(INTEGER_DATATYPE))); + } + }; + return j; // Where we have got up to + } + if (str.charAt(i) == "\"") { + if (pyjslib_slice(str, i, i + 3) == "\"\"\"") { + var delim = "\"\"\""; + } else { + var delim = "\""; + } + var i = i + pyjslib_len(delim); + var dt = null; + var pairFudge = this.strconst(str, i, delim); + var j = pairFudge[0]; + var s = pairFudge[1]; + var lang = null; + if (pyjslib_slice(str, j, j + 1) == "@") { + langcode.lastIndex = 0; - // Create a new blank node if no item head was assigned yet. - if (itemHead === null) - this._subject = itemHead = '_:b' + blankNodeCount++; + var m = langcode.exec(str.slice(j + 1)); + if (m == null) { + throw BadSyntax(this._thisDoc, startline, str, i, "Bad language code syntax on string literal, after @"); + } + var i = langcode.lastIndex + j + 1; - // Is this the first element of the list? - if (prevItemHead === null) { - // This list is either the object or the subject. - if (parentTriple.object === RDF_NIL) - parentTriple.object = itemHead; - else - parentTriple.subject = itemHead; - } - else { - // The rest of the list is in the current head. - this._callback(null, { subject: prevItemHead, - predicate: RDF_REST, - object: itemHead, - graph: this._graph || '' }); - } - // Add the item's value. - if (item !== null) - this._callback(null, { subject: itemHead, - predicate: RDF_FIRST, - object: item, - graph: this._graph || '' }); - return next; - }, + var lang = pyjslib_slice(str, j + 1, i); + var j = i; + } + if (pyjslib_slice(str, j, j + 2) == "^^") { + var res2 = new pyjslib_List([]); + var j = this.uri_ref2(str, j + 2, res2); + var dt = res2[0]; + } + res.push(this._store.literal(s, lang, dt)); + return j; + } else { + return -1; + } + } + }; + __SinkParser.prototype.strconst = function (str, i, delim) { + /* + parse an N3 string constant delimited by delim. + return index, val + */ - // ### `_readPunctuation` reads punctuation between triples or triple parts. - _readPunctuation: function (token) { - var next, subject = this._subject, graph = this._graph; - switch (token.type) { - // A closing brace ends a graph - case '}': - if (this._graph === null) - return this._error('Unexpected graph closing', token); - this._graph = null; - // A dot just ends the statement, without sharing anything with the next. - case '.': - this._subject = null; - next = this._readInTopContext; - break; - // Semicolon means the subject is shared; predicate and object are different. - case ';': - next = this._readPredicate; - break; - // Comma means both the subject and predicate are shared; the object is different. - case ',': - next = this._readObject; - break; - // An IRI means this is a quad (only allowed if not already inside a graph). - case 'IRI': - if (this._supportsQuads && this._graph === null) { - if (this._base === null || absoluteIRI.test(token.value)) - graph = token.value; - else - graph = this._resolveIRI(token); - subject = this._subject; - next = this._readQuadPunctuation; - break; - } - // An prefixed name means this is a quad (only allowed if not already inside a graph). - case 'prefixed': - if (this._supportsQuads && this._graph === null) { - var prefix = this._prefixes[token.prefix]; - if (prefix === undefined) - return this._error('Undefined prefix "' + token.prefix + ':"', token); - graph = prefix + token.value; - next = this._readQuadPunctuation; - break; - } - default: - return this._error('Expected punctuation to follow "' + this._object + '"', token); + var j = i; + var ustr = ""; + var startline = this.lines; + while (j < pyjslib_len(str)) { + var i = j + pyjslib_len(delim); + if (pyjslib_slice(str, j, i) == delim) { + return new pyjslib_Tuple([i, ustr]); + } + if (str.charAt(j) == "\"") { + var ustr = ustr + "\""; + var j = j + 1; + continue; + } + interesting.lastIndex = 0; + var m = interesting.exec(str.slice(j)); + if (!m) { + throw BadSyntax(this._thisDoc, startline, str, j, "Closing quote missing in string at ^ in " + pyjslib_slice(str, j - 20, j) + "^" + pyjslib_slice(str, j, j + 20)); + } + var i = j + interesting.lastIndex - 1; + var ustr = ustr + pyjslib_slice(str, j, i); + var ch = str.charAt(i); + if (ch == "\"") { + var j = i; + continue; + } else if (ch == "\r") { + var j = i + 1; + continue; + } else if (ch == "\n") { + if (delim == "\"") { + throw BadSyntax(this._thisDoc, startline, str, i, "newline found in string literal"); + } + this.lines = this.lines + 1; + var ustr = ustr + ch; + var j = i + 1; + this.previousLine = this.startOfLine; + this.startOfLine = j; + } else if (ch == "\\") { + var j = i + 1; + var ch = pyjslib_slice(str, j, j + 1); + if (!ch) { + throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal (2)"); + } + var k = string_find("abfrtvn\\\"", ch); + if (k >= 0) { + var uch = "\a\b\f\r\t\v\n\\\"".charAt(k); + var ustr = ustr + uch; + var j = j + 1; + } else if (ch == "u") { + var pairFudge = this.uEscape(str, j + 1, startline); + var j = pairFudge[0]; + var ch = pairFudge[1]; + var ustr = ustr + ch; + } else if (ch == "U") { + var pairFudge = this.UEscape(str, j + 1, startline); + var j = pairFudge[0]; + var ch = pairFudge[1]; + var ustr = ustr + ch; + } else { + throw BadSyntax(this._thisDoc, this.lines, str, i, "bad escape"); + } + } + } + throw BadSyntax(this._thisDoc, this.lines, str, i, "unterminated string literal"); + }; + __SinkParser.prototype.uEscape = function (str, i, startline) { + var j = i; + var count = 0; + var value = 0; + while (count < 4) { + var chFudge = pyjslib_slice(str, j, j + 1); + var ch = chFudge.toLowerCase(); + var j = j + 1; + if (ch == "") { + throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal(3)"); + } + var k = string_find("0123456789abcdef", ch); + if (k < 0) { + throw BadSyntax(this._thisDoc, startline, str, i, "bad string literal hex escape"); + } + var value = value * 16 + k; + var count = count + 1; + } + var uch = String.fromCharCode(value); + return new pyjslib_Tuple([j, uch]); + }; + __SinkParser.prototype.UEscape = function (str, i, startline) { + var j = i; + var count = 0; + var value = '\\U'; + while (count < 8) { + var chFudge = pyjslib_slice(str, j, j + 1); + var ch = chFudge.toLowerCase(); + var j = j + 1; + if (ch == "") { + throw BadSyntax(this._thisDoc, startline, str, i, "unterminated string literal(3)"); + } + var k = string_find("0123456789abcdef", ch); + if (k < 0) { + throw BadSyntax(this._thisDoc, startline, str, i, "bad string literal hex escape"); + } + var value = value + ch; + var count = count + 1; + } + var uch = stringFromCharCode("0x" + pyjslib_slice(value, 2, 10) - 0); + return new pyjslib_Tuple([j, uch]); + }; + function OLD_BadSyntax(uri, lines, str, i, why) { + return new __OLD_BadSyntax(uri, lines, str, i, why); } - // A triple has been completed now, so return it. - if (subject !== null) - this._callback(null, { subject: subject, - predicate: this._predicate, - object: this._object, - graph: graph || '' }); - return next; - }, - - // ### `_readBlankNodePunctuation` reads punctuation in a blank node - _readBlankNodePunctuation: function (token) { - var next; - switch (token.type) { - // Semicolon means the subject is shared; predicate and object are different. - case ';': - next = this._readPredicate; - break; - // Comma means both the subject and predicate are shared; the object is different. - case ',': - next = this._readObject; - break; - default: - return this._error('Expected punctuation to follow "' + this._object + '"', token); + function __OLD_BadSyntax(uri, lines, str, i, why) { + this._str = str.encode("utf-8"); + this._str = str; + this._i = i; + this._why = why; + this.lines = lines; + this._uri = uri; + } + __OLD_BadSyntax.prototype.toString = function () { + var str = this._str; + var i = this._i; + var st = 0; + if (i > 60) { + var pre = "..."; + var st = i - 60; + } else { + var pre = ""; + } + if (pyjslib_len(str) - i > 60) { + var post = "..."; + } else { + var post = ""; + } + return "Line %i of <%s>: Bad syntax (%s) at ^ in:\n\"%s%s^%s%s\"" % new pyjslib_Tuple([this.lines + 1, this._uri, this._why, pre, pyjslib_slice(str, st, i), pyjslib_slice(str, i, i + 60), post]); + }; + function BadSyntax(uri, lines, str, i, why) { + return "Line " + (lines + 1) + " of <" + uri + ">: Bad syntax: " + why + "\nat: \"" + pyjslib_slice(str, i, i + 30) + "\""; } - // A triple has been completed now, so return it. - this._callback(null, { subject: this._subject, - predicate: this._predicate, - object: this._object, - graph: this._graph || '' }); - return next; - }, - // ### `_readQuadPunctuation` reads punctuation after a quad. - _readQuadPunctuation: function (token) { - if (token.type !== '.') - return this._error('Expected dot to follow quad', token); - return this._readInTopContext; - }, + function stripCR(str) { + var res = ""; - // ### `_readPrefix` reads the prefix of a prefix declaration. - _readPrefix: function (token) { - if (token.type !== 'prefix') - return this._error('Expected prefix to follow @prefix', token); - this._prefix = token.value; - return this._readPrefixIRI; - }, + var __ch = new pyjslib_Iterator(str); + try { + while (true) { + var ch = __ch.next(); - // ### `_readPrefixIRI` reads the IRI of a prefix declaration. - _readPrefixIRI: function (token) { - if (token.type !== 'IRI') - return this._error('Expected IRI to follow prefix "' + this._prefix + ':"', token); - var prefixIRI; - if (this._base === null || absoluteIRI.test(token.value)) - prefixIRI = token.value; - else - prefixIRI = this._resolveIRI(token); - this._prefixes[this._prefix] = prefixIRI; - this._prefixCallback(this._prefix, prefixIRI); - return this._readDeclarationPunctuation; - }, + if (ch != "\r") { + var res = res + ch; + } + } + } catch (e) { + if (e != StopIteration) { + throw e; + } + } - // ### `_readBaseIRI` reads the IRI of a base declaration. - _readBaseIRI: function (token) { - if (token.type !== 'IRI') - return this._error('Expected IRI to follow base declaration', token); - try { - this._setBase(this._base === null || - absoluteIRI.test(token.value) ? token.value : this._resolveIRI(token)); + return res; } - catch (error) { this._error(error.message, token); } - return this._readDeclarationPunctuation; - }, - // ### `_readNamedGraphLabel` reads the label of a named graph. - _readNamedGraphLabel: function (token) { - switch (token.type) { - case 'IRI': - case 'prefixed': - return this._readSubject(token), this._readGraph; - case '[': - return this._readNamedGraphBlankLabel; - default: - return this._error('Invalid graph label', token); - } - }, + function dummyWrite(x) {} - // ### `_readNamedGraphLabel` reads a blank node label of a named graph. - _readNamedGraphBlankLabel: function (token) { - if (token.type !== ']') - return this._error('Invalid graph label', token); - this._subject = '_:b' + blankNodeCount++; - return this._readGraph; - }, + return SinkParser; +}(); - // ### `_readDeclarationPunctuation` reads the punctuation of a declaration. - _readDeclarationPunctuation: function (token) { - // SPARQL-style declarations don't have punctuation. - if (this._sparqlStyle) - return this._readInTopContext(token); +module.exports = N3Parser; +},{"./uri":269,"./util":270}],254:[function(_dereq_,module,exports){ +'use strict'; - if (token.type !== '.') - return this._error('Expected declaration to end with a dot', token); - return this._readInTopContext; - }, +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - // ### `_getTripleEndReader` gets the next reader function at the end of a triple. - _getTripleEndReader: function () { - var stack = this._tripleStack; - if (stack.length === 0) - return this._readPunctuation; +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - switch (stack[stack.length - 1].type) { - case 'blank': - return this._readBlankNodeTail; - case 'list': - return this._readListItem; +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var ClassOrder = _dereq_('./class-order'); +var Node = _dereq_('./node'); + +/** + * @class NamedNode + * @extends Node + */ + +var NamedNode = function (_Node) { + _inherits(NamedNode, _Node); + + /** + * @constructor + * @param iri {String} + */ + function NamedNode(iri) { + _classCallCheck(this, NamedNode); + + var _this = _possibleConstructorReturn(this, (NamedNode.__proto__ || Object.getPrototypeOf(NamedNode)).call(this)); + + _this.termType = NamedNode.termType; + if (!iri.includes(':')) { + throw new Error('NamedNode IRI "' + iri + '" must be absolute.'); } - }, + if (iri.includes(' ')) { + var message = 'Error: NamedNode IRI "' + iri + '" must not contain unencoded spaces.'; + throw new Error(message); + } + _this.value = iri; + return _this; + } + /** + * Returns an $rdf node for the containing directory, ending in slash. + */ - // ### `_error` emits an error message through the callback. - _error: function (message, token) { - this._callback(new Error(message + ' at line ' + token.line + '.')); - }, - // ### `_resolveIRI` resolves a relative IRI token against the base path, - // assuming that a base path has been set and that the IRI is indeed relative. - _resolveIRI: function (token) { - var iri = token.value; - switch (iri[0]) { - // An empty relative IRI indicates the base IRI - case undefined: return this._base; - // Resolve relative fragment IRIs against the base IRI - case '#': return this._base + iri; - // Resolve relative query string IRIs by replacing the query string - case '?': return this._base.replace(/(?:\?.*)?$/, iri); - // Resolve root-relative IRIs at the root of the base IRI - case '/': - // Resolve scheme-relative IRIs to the scheme - return (iri[1] === '/' ? this._baseScheme : this._baseRoot) + this._removeDotSegments(iri); - // Resolve all other IRIs at the base IRI's path - default: - return this._removeDotSegments(this._basePath + iri); + _createClass(NamedNode, [{ + key: 'dir', + value: function dir() { + var str = this.uri.split('#')[0]; + var p = str.slice(0, -1).lastIndexOf('/'); + var q = str.indexOf('//'); + if (q >= 0 && p < q + 2 || p < 0) return null; + return new NamedNode(str.slice(0, p + 1)); } - }, + /** + * Returns an NN for the whole web site, ending in slash. + * Contrast with the "origin" which does NOT have a trailing slash + */ - // ### `_removeDotSegments` resolves './' and '../' path segments in an IRI as per RFC3986. - _removeDotSegments: function (iri) { - // Don't modify the IRI if it does not contain any dot segments - if (!dotSegments.test(iri)) - return iri; + }, { + key: 'site', + value: function site() { + var str = this.uri.split('#')[0]; + var p = str.indexOf('//'); + if (p < 0) throw new Error('This URI does not have a web site part (origin)'); + var q = str.indexOf('/', p + 2); + if (q < 0) throw new Error('This URI does not have a web site part. (origin)'); + return new NamedNode(str.slice(0, q + 1)); + } + }, { + key: 'doc', + value: function doc() { + if (this.uri.indexOf('#') < 0) { + return this; + } else { + return new NamedNode(this.uri.split('#')[0]); + } + } + }, { + key: 'toString', + value: function toString() { + return '<' + this.uri + '>'; + } - // Start with an imaginary slash before the IRI in order to resolve trailing './' and '../' - var result = '', length = iri.length, i = -1, pathStart = -1, segmentStart = 0, next = '/'; + /** + * Legacy getter and setter alias, node.uri + */ - while (i < length) { - switch (next) { - // The path starts with the first slash after the authority - case ':': - if (pathStart < 0) { - // Skip two slashes before the authority - if (iri[++i] === '/' && iri[++i] === '/') - // Skip to slash after the authority - while ((pathStart = i + 1) < length && iri[pathStart] !== '/') - i = pathStart; - } - break; - // Don't modify a query string or fragment - case '?': - case '#': - i = length; - break; - // Handle '/.' or '/..' path segments - case '/': - if (iri[i + 1] === '.') { - next = iri[++i + 1]; - switch (next) { - // Remove a '/.' segment - case '/': - result += iri.substring(segmentStart, i - 1); - segmentStart = i + 1; - break; - // Remove a trailing '/.' segment - case undefined: - case '?': - case '#': - return result + iri.substring(segmentStart, i) + iri.substr(i + 1); - // Remove a '/..' segment - case '.': - next = iri[++i + 1]; - if (next === undefined || next === '/' || next === '?' || next === '#') { - result += iri.substring(segmentStart, i - 2); - // Try to remove the parent path from result - if ((segmentStart = result.lastIndexOf('/')) >= pathStart) - result = result.substr(0, segmentStart); - // Remove a trailing '/..' segment - if (next !== '/') - return result + '/' + iri.substr(i + 1); - segmentStart = i + 1; - } - } - } + }, { + key: 'uri', + get: function get() { + return this.value; + }, + set: function set(uri) { + this.value = uri; + } + }], [{ + key: 'fromValue', + value: function fromValue(value) { + if (typeof value === 'undefined' || value === null) { + return value; } - next = iri[++i]; + var isNode = value && value.termType; + if (isNode) { + return value; + } + return new NamedNode(value); } - return result + iri.substring(segmentStart); - }, + }]); - // ## Public methods + return NamedNode; +}(Node); - // ### `parse` parses the N3 input and emits each parsed triple through the callback. - parse: function (input, tripleCallback, prefixCallback) { - // The read callback is the next function to be executed when a token arrives. - // We start reading in the top context. - this._readCallback = this._readInTopContext; - this._prefixes = Object.create(null); - this._prefixes._ = this._blankNodePrefix || '_:b' + blankNodePrefix++ + '_'; +NamedNode.termType = 'NamedNode'; +NamedNode.prototype.classOrder = ClassOrder['NamedNode']; +NamedNode.prototype.isVar = 0; - // If the input argument is not given, shift parameters - if (typeof input === 'function') - prefixCallback = tripleCallback, tripleCallback = input, input = null; +module.exports = NamedNode; +},{"./class-order":240,"./node":256}],255:[function(_dereq_,module,exports){ +'use strict'; - // Set the triple and prefix callbacks. - this._callback = tripleCallback || noop; - this._prefixCallback = prefixCallback || noop; +var NamedNode = _dereq_('./named-node'); - // Execute the read callback when a token arrives. - var self = this; - this._lexer.tokenize(input, function (error, token) { - if (error !== null) - self._callback(error), self._callback = noop; - else if (self._readCallback !== undefined) - self._readCallback = self._readCallback(token); - }); +function Namespace(nsuri) { + return function (ln) { + return new NamedNode(nsuri + (ln || '')); + }; +} - // If no input was given, it can be added with `addChunk` and ended with `end` - if (!input) { - this.addChunk = this._lexer.addChunk; - this.end = this._lexer.end; - } - }, -}; +module.exports = Namespace; +},{"./named-node":254}],256:[function(_dereq_,module,exports){ +'use strict'; +/** + * The superclass of all RDF Statement objects, that is + * NamedNode, Literal, BlankNode, etc. + * @class Node + */ -// The empty function -function noop() {} +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); -// ## Exports +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -// Export the `N3Parser` class as a whole. -module.exports = N3Parser; +var Node = function () { + function Node() { + _classCallCheck(this, Node); + } -},{"./N3Lexer":77}],79:[function(_dereq_,module,exports){ -// **N3Store** objects store N3 triples by graph in memory. + _createClass(Node, [{ + key: 'substitute', + value: function substitute(bindings) { + console.log('@@@ node substitute' + this); + return this; + } + }, { + key: 'compareTerm', + value: function compareTerm(other) { + if (this.classOrder < other.classOrder) { + return -1; + } + if (this.classOrder > other.classOrder) { + return +1; + } + if (this.value < other.value) { + return -1; + } + if (this.value > other.value) { + return +1; + } + return 0; + } + }, { + key: 'equals', + value: function equals(other) { + if (!other) { + return false; + } + return this.termType === other.termType && this.value === other.value; + } + }, { + key: 'hashString', + value: function hashString() { + return this.toCanonical(); + } + }, { + key: 'sameTerm', + value: function sameTerm(other) { + return this.equals(other); + } + }, { + key: 'toCanonical', + value: function toCanonical() { + return this.toNT(); + } + }, { + key: 'toNT', + value: function toNT() { + return this.toString(); + } + }, { + key: 'toString', + value: function toString() { + throw new Error('Node.toString() is abstract - see the subclasses instead'); + } + }]); -var expandPrefixedName = _dereq_('./N3Util').expandPrefixedName; + return Node; +}(); -// ## Constructor -function N3Store(triples, options) { - if (!(this instanceof N3Store)) - return new N3Store(triples, options); +module.exports = Node; - // The number of triples is initially zero. - this._size = 0; - // `_graphs` contains subject, predicate, and object indexes per graph. - this._graphs = Object.create(null); - // `_entities` maps entities such as `http://xmlns.com/foaf/0.1/name` to numbers. - // This saves memory, since only the numbers have to be stored in `_graphs`. - this._entities = Object.create(null); - this._entities['><'] = 0; // Dummy entry, so the first actual key is non-zero - this._entityCount = 0; - // `_blankNodeIndex` is the index of the last created blank node that was automatically named - this._blankNodeIndex = 0; +/** + * Creates an RDF Node from a native javascript value. + * RDF Nodes are returned unchanged, undefined returned as itself. + * @method fromValue + * @static + * @param value {Node|Date|String|Number|Boolean|Undefined} + * @return {Node|Collection} + */ +Node.fromValue = function fromValue(value) { + var Collection = _dereq_('./collection'); + var Literal = _dereq_('./literal'); + var NamedNode = _dereq_('./named-node'); + if (typeof value === 'undefined' || value === null) { + return value; + } + var isNode = value && value.termType; + if (isNode) { + // a Node subclass or a Collection + return value; + } + if (Array.isArray(value)) { + return new Collection(value); + } + return Literal.fromValue(value); +}; +},{"./collection":241,"./literal":251,"./named-node":254}],257:[function(_dereq_,module,exports){ +'use strict'; - // Shift parameters if `triples` is not given - if (!options && triples && !triples[0]) - options = triples, triples = null; +module.exports = parse; - // Add triples and prefixes if passed - this._prefixes = Object.create(null); - if (options && options.prefixes) - this.addPrefixes(options.prefixes); - if (triples) - this.addTriples(triples); -} +var BlankNode = _dereq_('./blank-node'); +var jsonld = _dereq_('jsonld'); +var Literal = _dereq_('./literal'); +var N3 = _dereq_('n3'); // @@ Goal: remove this dependency +var N3Parser = _dereq_('./n3parser'); +var NamedNode = _dereq_('./named-node'); +var parseRDFaDOM = _dereq_('./rdfaparser').parseRDFaDOM; +var RDFParser = _dereq_('./rdfxmlparser'); +var sparqlUpdateParser = _dereq_('./patch-parser'); +var Util = _dereq_('./util'); + +/** + * Parse a string and put the result into the graph kb. + * Normal method is sync. + * Unfortunately jsdonld is currently written to need to be called async. + * Hence the mess below with executeCallback. + */ +function parse(str, kb, base, contentType, callback) { + contentType = contentType || 'text/turtle'; + try { + if (contentType === 'text/n3' || contentType === 'text/turtle') { + var p = N3Parser(kb, kb, base, base, null, null, '', null); + p.loadBuf(str); + executeCallback(); + } else if (contentType === 'application/rdf+xml') { + var parser = new RDFParser(kb); + parser.parse(Util.parseXML(str), base, kb.sym(base)); + executeCallback(); + } else if (contentType === 'application/xhtml+xml') { + parseRDFaDOM(Util.parseXML(str, { contentType: 'application/xhtml+xml' }), kb, base); + executeCallback(); + } else if (contentType === 'text/html') { + parseRDFaDOM(Util.parseXML(str, { contentType: 'text/html' }), kb, base); + executeCallback(); + } else if (contentType === 'application/sparql-update') { + // @@ we handle a subset + sparqlUpdateParser(str, kb, base); + executeCallback(); + } else if (contentType === 'application/ld+json' || contentType === 'application/nquads' || contentType === 'application/n-quads') { + var n3Parser = N3.Parser(); + var triples = []; + if (contentType === 'application/ld+json') { + var jsonDocument; + try { + jsonDocument = JSON.parse(str); + } catch (parseErr) { + callback(parseErr, null); + } + jsonld.toRDF(jsonDocument, { format: 'application/nquads' }, nquadCallback); + } else { + nquadCallback(null, str); + } + } else { + throw new Error("Don't know how to parse " + contentType + ' yet'); + } + } catch (e) { + executeErrorCallback(e); + } -N3Store.prototype = { - // ## Public properties + function executeCallback() { + if (callback) { + callback(null, kb); + } else { + return; + } + } - // ### `size` returns the number of triples in the store. - get size() { - // Return the triple count if if was cached. - var size = this._size; - if (size !== null) - return size; + function executeErrorCallback(e) { + if (contentType !== 'application/ld+json' || contentType !== 'application/nquads' || contentType !== 'application/n-quads') { + if (callback) { + callback(e, kb); + } else { + throw new Error('Error trying to parse <' + base + '> as ' + contentType + ':\n' + e + ':\n' + e.stack); + } + } + } + /* + function setJsonLdBase (doc, base) { + if (doc instanceof Array) { + return + } + if (!('@context' in doc)) { + doc['@context'] = {} + } + doc['@context']['@base'] = base + } + */ + function nquadCallback(err, nquads) { + if (err) { + callback(err, kb); + } + try { + n3Parser.parse(nquads, tripleCallback); + } catch (err) { + callback(err, kb); + } + } - // Calculate the number of triples by counting to the deepest level. - var graphs = this._graphs, subjects, subject; - for (var graphKey in graphs) - for (var subjectKey in (subjects = graphs[graphKey].subjects)) - for (var predicateKey in (subject = subjects[subjectKey])) - size += Object.keys(subject[predicateKey]).length; - return this._size = size; - }, + function tripleCallback(err, triple, prefixes) { + if (err) { + callback(err, kb); + } + if (triple) { + triples.push(triple); + } else { + for (var i = 0; i < triples.length; i++) { + addTriple(kb, triples[i]); + } + callback(null, kb); + } + } - // ## Private methods + function addTriple(kb, triple) { + var subject = createTerm(triple.subject); + var predicate = createTerm(triple.predicate); + var object = createTerm(triple.object); + var why = null; + if (triple.graph) { + why = createTerm(triple.graph); + } + kb.add(subject, predicate, object, why); + } - // ### `_addToIndex` adds a triple to a three-layered index. - _addToIndex: function (index0, key0, key1, key2) { - // Create layers as necessary. - var index1 = index0[key0] || (index0[key0] = {}); - var index2 = index1[key1] || (index1[key1] = {}); - // Setting the key to _any_ value signalizes the presence of the triple. - index2[key2] = null; - }, + function createTerm(termString) { + var value; + if (N3.Util.isLiteral(termString)) { + value = N3.Util.getLiteralValue(termString); + var language = N3.Util.getLiteralLanguage(termString); + var datatype = new NamedNode(N3.Util.getLiteralType(termString)); + return new Literal(value, language, datatype); + } else if (N3.Util.isIRI(termString)) { + return new NamedNode(termString); + } else if (N3.Util.isBlank(termString)) { + value = termString.substring(2, termString.length); + return new BlankNode(value); + } else { + return null; + } + } +} +},{"./blank-node":239,"./literal":251,"./n3parser":253,"./named-node":254,"./patch-parser":258,"./rdfaparser":261,"./rdfxmlparser":262,"./util":270,"jsonld":55,"n3":273}],258:[function(_dereq_,module,exports){ +'use strict'; - // ### `_removeFromIndex` removes a triple from a three-layered index. - _removeFromIndex: function (index0, key0, key1, key2) { - // Remove the triple from the index. - var index1 = index0[key0], index2 = index1[key1], key; - delete index2[key2]; +// Parse a simple SPARL-Update subset syntax for patches. +// +// This parses +// WHERE {xxx} DELETE {yyy} INSERT DATA {zzz} +// (not necessarily in that order) +// as though it were the n3 +// <#query> patch:where {xxx}; patch:delete {yyy}; patch:insert {zzz}. +module.exports = sparqlUpdateParser; - // Remove intermediary index layers if they are empty. - for (key in index2) return; - delete index1[key1]; - for (key in index1) return; - delete index0[key0]; - }, +var N3Parser = _dereq_('./n3parser'); +var Namespace = _dereq_('./namespace'); - // ### `_findInIndex` finds a set of triples in a three-layered index. - // The index base is `index0` and the keys at each level are `key0`, `key1`, and `key2`. - // Any of these keys can be `null`, which is interpreted as a wildcard. - // `name0`, `name1`, and `name2` are the names of the keys at each level, - // used when reconstructing the resulting triple - // (for instance: _subject_, _predicate_, and _object_). - // Finally, `graph` will be the graph of the created triples. - _findInIndex: function (index0, key0, key1, key2, name0, name1, name2, graph) { - var results = [], entityKeys = Object.keys(this._entities), tmp, index1, index2; +function sparqlUpdateParser(str, kb, base) { + var i, j, k; + var keywords = ['INSERT', 'DELETE', 'WHERE']; + var SQNS = Namespace('http://www.w3.org/ns/pim/patch#'); + var p = N3Parser(kb, kb, base, base, null, null, '', null); + var clauses = {}; - // If a key is specified, use only that part of index 0. - if (key0) (tmp = index0, index0 = {})[key0] = tmp[key0]; - for (var value0 in index0) { - var entity0 = entityKeys[value0]; + var badSyntax = function badSyntax(uri, lines, str, i, why) { + return 'Line ' + (lines + 1) + ' of <' + uri + '>: Bad syntax:\n ' + why + '\n at: "' + str.slice(i, i + 30) + '"'; + }; - if (index1 = index0[value0]) { - // If a key is specified, use only that part of index 1. - if (key1) (tmp = index1, index1 = {})[key1] = tmp[key1]; - for (var value1 in index1) { - var entity1 = entityKeys[value1]; + // var check = function (next, last, message) { + // if (next < 0) { + // throw badSyntax(p._thisDoc, p.lines, str, j, last, message) + // } + // return next + // } + i = 0; + var query = kb.sym(base + '#query'); // Invent a URI for the query + clauses['query'] = query; // A way of accessing it in its N3 model. - if (index2 = index1[value1]) { - // If a key is specified, use only that part of index 2, if it exists. - var values = key2 ? (key2 in index2 ? [key2] : []) : Object.keys(index2); - // Create triples for all items found in index 2. - for (var l = values.length - 1; l >= 0; l--) { - var result = { subject: '', predicate: '', object: '', graph: graph }; - result[name0] = entity0; - result[name1] = entity1; - result[name2] = entityKeys[values[l]]; - results.push(result); - } - } - } + while (true) { + // console.log("A Now at i = " + i) + j = p.skipSpace(str, i); + if (j < 0) { + return clauses; + } + // console.log("B After space at j= " + j) + if (str[j] === ';') { + i = p.skipSpace(str, j + 1); + if (i < 0) { + return clauses; // Allow end in a } + j = i; } - return results; - }, - - // ### `_countInIndex` counts matching triples in a three-layered index. - // The index base is `index0` and the keys at each level are `key0`, `key1`, and `key2`. - // Any of these keys can be `null`, which is interpreted as a wildcard. - _countInIndex: function (index0, key0, key1, key2) { - var count = 0, tmp, index1, index2; - - // If a key is specified, count only that part of index 0. - if (key0) (tmp = index0, index0 = {})[key0] = tmp[key0]; - for (var value0 in index0) { - if (index1 = index0[value0]) { - // If a key is specified, count only that part of index 1. - if (key1) (tmp = index1, index1 = {})[key1] = tmp[key1]; - for (var value1 in index1) { - if (index2 = index1[value1]) { - // If a key is specified, count the triple if it exists. - if (key2) (key2 in index2) && count++; - // Otherwise, count all triples. - else count += Object.keys(index2).length; + var found = false; + for (k = 0; k < keywords.length; k++) { + var key = keywords[k]; + if (str.slice(j, j + key.length) === key) { + i = p.skipSpace(str, j + key.length); + if (i < 0) { + throw badSyntax(p._thisDoc, p.lines, str, j + key.length, 'found EOF, needed {...} after ' + key); + } + if ((key === 'INSERT' || key === 'DELETE') && str.slice(i, i + 4) === 'DATA') { + // Some wanted 'DATA'. Whatever + j = p.skipSpace(str, i + 4); + if (j < 0) { + throw badSyntax(p._thisDoc, p.lines, str, i + 4, 'needed {...} after INSERT DATA ' + key); } + i = j; + } + var res2 = []; + j = p.node(str, i, res2); // Parse all the complexity of the clause + + if (j < 0) { + throw badSyntax(p._thisDoc, p.lines, str, i, 'bad syntax or EOF in {...} after ' + key); } + clauses[key.toLowerCase()] = res2[0]; + kb.add(query, SQNS(key.toLowerCase()), res2[0]); // , kb.sym(base) + // key is the keyword and res2 has the contents + found = true; + i = j; } } - return count; - }, - - // ## Public methods + if (!found && str.slice(j, j + 7) === '@prefix') { + i = p.directive(str, j); + if (i < 0) { + throw badSyntax(p._thisDoc, p.lines, str, i, 'bad syntax or EOF after @prefix '); + } + // console.log("P before dot i= " + i) + i = p.checkDot(str, i); + // console.log("Q after dot i= " + i) + found = true; + } + if (!found) { + // console.log("Bad syntax " + j) + throw badSyntax(p._thisDoc, p.lines, str, j, "Unknown syntax at start of statememt: '" + str.slice(j).slice(0, 20) + "'"); + } + } // while + // return clauses +} +},{"./n3parser":253,"./namespace":255}],259:[function(_dereq_,module,exports){ +'use strict'; - // ### `addTriple` adds a new N3 triple to the store. - addTriple: function (subject, predicate, object, graph) { - // Shift arguments if a triple object is given instead of components - if (!predicate) - graph = subject.graph, object = subject.object, - predicate = subject.predicate, subject = subject.subject; +var log = _dereq_('./log'); - // Find the graph that will contain the triple. - graph = graph || ''; - var graphItem = this._graphs[graph]; - // Create the graph if it doesn't exist yet. - if (!graphItem) { - graphItem = this._graphs[graph] = { subjects: {}, predicates: {}, objects: {} }; - // Freezing a graph helps subsequent `add` performance, - // and properties will never be modified anyway. - Object.freeze(graphItem); +function queryToSPARQL(query) { + var indent = 0; + function getSelect(query) { + var str = addIndent() + 'SELECT '; + for (var i = 0; i < query.vars.length; i++) { + str += query.vars[i] + ' '; } + str += '\n'; + return str; + } - // Since entities can often be long IRIs, we avoid storing them in every index. - // Instead, we have a separate index that maps entities to numbers, - // which are then used as keys in the other indexes. - var entities = this._entities; - subject = entities[subject] || (entities[subject] = ++this._entityCount); - predicate = entities[predicate] || (entities[predicate] = ++this._entityCount); - object = entities[object] || (entities[object] = ++this._entityCount); + function getPattern(pat) { + var str = ''; + var st = pat.statements; + for (var x in st) { + log.debug('Found statement: ' + st); + str += addIndent() + st[x] + '\n'; + } + return str; + } - this._addToIndex(graphItem.subjects, subject, predicate, object); - this._addToIndex(graphItem.predicates, predicate, object, subject); - this._addToIndex(graphItem.objects, object, subject, predicate); + function getConstraints(pat) { + var str = ''; + for (var v in pat.constraints) { + var foo = pat.constraints[v]; + str += addIndent() + 'FILTER ( ' + foo.describe(v) + ' ) ' + '\n'; + } + return str; + } - // The cached triple count is now invalid. - this._size = null; - }, + function getOptionals(pat) { + var str = ''; + for (var x = 0; x < pat.optional.length; x++) { + // alert(pat.optional.termType) + log.debug('Found optional query'); + str += addIndent() + 'OPTIONAL { ' + '\n'; + indent++; + str += getPattern(pat.optional[x]); + str += getConstraints(pat.optional[x]); + str += getOptionals(pat.optional[x]); + indent--; + str += addIndent() + '}' + '\n'; + } + return str; + } - // ### `addTriples` adds multiple N3 triples to the store. - addTriples: function (triples) { - for (var i = triples.length - 1; i >= 0; i--) - this.addTriple(triples[i]); - }, + function getWhere(pat) { + var str = addIndent() + 'WHERE \n' + '{ \n'; + indent++; + str += getPattern(pat); + str += getConstraints(pat); + str += getOptionals(pat); + indent--; + str += '}'; + return str; + } - // ### `addPrefix` adds support for querying with the given prefix - addPrefix: function (prefix, iri) { - this._prefixes[prefix] = iri; - }, + function addIndent() { + var str = ''; + for (var i = 0; i < indent; i++) { + str += ' '; + } + return str; + } - // ### `addPrefixes` adds support for querying with the given prefixes - addPrefixes: function (prefixes) { - for (var prefix in prefixes) - this.addPrefix(prefix, prefixes[prefix]); - }, + function getSPARQL(query) { + return getSelect(query) + getWhere(query.pat); + } - // ### `removeTriple` removes an N3 triple from the store if it exists. - removeTriple: function (subject, predicate, object, graph) { - // Shift arguments if a triple object is given instead of components. - if (!predicate) - graph = subject.graph, object = subject.object, - predicate = subject.predicate, subject = subject.subject; - graph = graph || ''; + return getSPARQL(query); +} - // Find internal identifiers for all components. - var graphItem, entities = this._entities, graphs = this._graphs; - if (!(subject = entities[subject])) return; - if (!(predicate = entities[predicate])) return; - if (!(object = entities[object])) return; - if (!(graphItem = graphs[graph])) return; +module.exports = queryToSPARQL; +},{"./log":252}],260:[function(_dereq_,module,exports){ +'use strict'; - // Verify that the triple exists. - var subjects, predicates; - if (!(subjects = graphItem.subjects[subject])) return; - if (!(predicates = subjects[predicate])) return; - if (!(object in predicates)) return; +var _indexedFormula = _dereq_('./indexed-formula'); - // Remove it from all indexes. - this._removeFromIndex(graphItem.subjects, subject, predicate, object); - this._removeFromIndex(graphItem.predicates, predicate, object, subject); - this._removeFromIndex(graphItem.objects, object, subject, predicate); - if (this._size !== null) this._size--; +var _indexedFormula2 = _interopRequireDefault(_indexedFormula); - // Remove the graph if it is empty. - for (subject in graphItem.subjects) return; - delete graphs[graph]; - }, +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - // ### `removeTriples` removes multiple N3 triples from the store. - removeTriples: function (triples) { - for (var i = triples.length - 1; i >= 0; i--) - this.removeTriple(triples[i]); - }, +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // Matching a formula against another formula +// Assync as well as Synchronously +// +// W3C open source licence 2005. +// +// This builds on term.js, match.js (and identity.js?) +// to allow a query of a formula. +// +// Here we introduce for the first time a subclass of term: variable. +// +// SVN ID: $Id: query.js 25116 2008-11-15 16:13:48Z timbl $ - // ### `find` finds a set of triples matching a pattern, expanding prefixes as necessary. - // Setting `subject`, `predicate`, or `object` to `null` means an _anything_ wildcard. - // Setting `graph` to `null` means the default graph. - find: function (subject, predicate, object, graph) { - var prefixes = this._prefixes; - return this.findByIRI( - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, +// Variable +// +// Compare with BlankNode. They are similar, but a variable +// stands for something whose value is to be returned. +// Also, users name variables and want the same name back when stuff is printed +/* jsl:option explicit*/ // Turn on JavaScriptLint variable declaration checking - // ### `findByIRI` finds a set of triples matching a pattern. - // Setting `subject`, `predicate`, or `object` to a falsy value means an _anything_ wildcard. - // Setting `graph` to a falsy value means the default graph. - findByIRI: function (subject, predicate, object, graph) { - graph = graph || ''; - var graphItem = this._graphs[graph], entities = this._entities; +var log = _dereq_('./log'); +var docpart = _dereq_('./uri').docpart; - // If the specified graph contain no triples, there are no results. - if (!graphItem) return []; +/** + * Query class, for tracking queries the user has in the UI. + */ - // Translate IRIs to internal index keys. - // Optimization: if the entity doesn't exist, no triples with it exist. - if (subject && !(subject = entities[subject])) return []; - if (predicate && !(predicate = entities[predicate])) return []; - if (object && !(object = entities[object])) return []; +var Query = function Query(name, id) { + _classCallCheck(this, Query); - // Choose the optimal index, based on what fields are present - if (subject) { - if (object) - // If subject and object are given, the object index will be the fastest. - return this._findInIndex(graphItem.objects, object, subject, predicate, - 'object', 'subject', 'predicate', graph); - else - // If only subject and possibly predicate are given, the subject index will be the fastest. - return this._findInIndex(graphItem.subjects, subject, predicate, null, - 'subject', 'predicate', 'object', graph); - } - else if (predicate) - // If only predicate and possibly object are given, the predicate index will be the fastest. - return this._findInIndex(graphItem.predicates, predicate, object, null, - 'predicate', 'object', 'subject', graph); - else if (object) - // If only object is given, the object index will be the fastest. - return this._findInIndex(graphItem.objects, object, null, null, - 'object', 'subject', 'predicate', graph); - else - // If nothing is given, iterate subjects and predicates first - return this._findInIndex(graphItem.subjects, null, null, null, - 'subject', 'predicate', 'object', graph); - }, + this.pat = new _indexedFormula2.default(); // The pattern to search for + this.vars = []; // Used by UI code but not in query.js + // this.orderBy = [] // Not used yet + this.name = name; + this.id = id; +}; - // ### `count` returns the number of triples matching a pattern, expanding prefixes as necessary. - // Setting `subject`, `predicate`, or `object` to `null` means an _anything_ wildcard. - // Setting `graph` to `null` means the default graph. - count: function (subject, predicate, object, graph) { - var prefixes = this._prefixes; - return this.countByIRI( - expandPrefixedName(subject, prefixes), - expandPrefixedName(predicate, prefixes), - expandPrefixedName(object, prefixes), - expandPrefixedName(graph, prefixes) - ); - }, +/** + * This function will match a pattern to the current kb + * + * The callback function is called whenever a match is found + * When fetcher is supplied this will be called to satisfy any resource requests + * currently not in the kb. The fetcher function needs to be defined manualy and + * should call $rdf.Util.AJAR_handleNewTerm to process the requested resource. + * + * @param myQuery, a knowledgebase containing a pattern to use as query + * @param callback, whenever the pattern in myQuery is met this is called with + * the new bindings as parameter + * @param fetcher, whenever a resource needs to be loaded this gets called IGNORED OBSOLETE + * f.fetecher is used as a Fetcher instance to do this. + * @param onDone callback when + */ - // ### `countByIRI` returns the number of triples matching a pattern. - // Setting `subject`, `predicate`, or `object` to `null` means an _anything_ wildcard. - // Setting `graph` to `null` means the default graph. - countByIRI: function (subject, predicate, object, graph) { - graph = graph || ''; - var graphItem = this._graphs[graph], entities = this._entities; - // If the specified graph contain no triples, there are no results. - if (!graphItem) return 0; +function indexedFormulaQuery(myQuery, callback, fetcher, onDone) { + // var kb = this + // /////////// Debug strings + var bindingDebug = function bindingDebug(b) { + var str = ''; + var v; + for (v in b) { + if (b.hasOwnProperty(v)) { + str += ' ' + v + ' -> ' + b[v]; + } + } + return str; + }; - // Translate IRIs to internal index keys. - // Optimization: if the entity doesn't exist, no triples with it exist. - if (subject && !(subject = entities[subject])) return 0; - if (predicate && !(predicate = entities[predicate])) return 0; - if (object && !(object = entities[object])) return 0; + var bindingsDebug = function bindingsDebug(nbs) { + var str = 'Bindings: '; + var i; + var n = nbs.length; + for (i = 0; i < n; i++) { + str += bindingDebug(nbs[i][0]) + ';\n\t'; + } + return str; + }; // bindingsDebug - // Choose the optimal index, based on what fields are present - if (subject) { - if (object) - // If subject and object are given, the object index will be the fastest. - return this._countInIndex(graphItem.objects, object, subject, predicate); - else - // If only subject and possibly predicate are given, the subject index will be the fastest. - return this._countInIndex(graphItem.subjects, subject, predicate, object); + // Unification: see also + // http://www.w3.org/2000/10/swap/term.py + // for similar things in python + // + // Unification finds all bindings such that when the binding is applied + // to one term it is equal to the other. + // Returns: a list of bindings, where a binding is an associative array + // mapping variuable to value. + + var unifyTerm = function unifyTerm(self, other, bindings, formula) { + var actual = bindings[self]; + if (actual === undefined) { + // Not mapped + if (self.isVar) { + /* if (self.isBlank) //bnodes are existential variables + { + if (self.toString() == other.toString()) return [[ [], null]] + else return [] + }*/ + var b = []; + b[self] = other; + return [[b, null]]; // Match + } + actual = self; } - else if (predicate) { - // If only predicate and possibly object are given, the predicate index will be the fastest. - return this._countInIndex(graphItem.predicates, predicate, object, subject); + if (!actual.complexType) { + if (formula.redirections[actual]) { + actual = formula.redirections[actual]; + } + if (formula.redirections[other]) { + other = formula.redirections[other]; + } + if (actual.sameTerm(other)) { + return [[[], null]]; + } + return []; } - else { - // If only object is possibly given, the object index will be the fastest. - return this._countInIndex(graphItem.objects, object, subject, predicate); + if (self instanceof Array) { + if (!(other instanceof Array)) { + return []; + } + return unifyContents(self, other, bindings); } - }, + throw new Error('query.js: oops - code not written yet'); + // return undefined; // for lint - no jslint objects to unreachables + // return actual.unifyContents(other, bindings) + }; // unifyTerm - // ### `createBlankNode` creates a new blank node, returning its name. - createBlankNode: function (suggestedName) { - var name, index; - // Generate a name based on the suggested name - if (suggestedName) { - name = suggestedName = '_:' + suggestedName, index = 1; - while (this._entities[name]) - name = suggestedName + index++; + var unifyContents = function unifyContents(self, other, bindings, formula) { + var nbs2; + if (self.length !== other.length) { + return []; // no way } - // Generate a generic blank node name - else { - do { name = '_:b' + this._blankNodeIndex++; } - while (this._entities[name]); + if (!self.length) { + return [[[], null]]; // Success } - // Add the blank node to the entities, avoiding the generation of duplicates - this._entities[name] = ++this._entityCount; - return name; - }, -}; - -// ## Exports - -// Export the `N3Store` class as a whole. -module.exports = N3Store; - -},{"./N3Util":82}],80:[function(_dereq_,module,exports){ -// **N3StreamParser** parses an N3 stream into a triple stream -var Transform = _dereq_('stream').Transform, - util = _dereq_('util'), - N3Parser = _dereq_('./N3Parser.js'); - -// ## Constructor -function N3StreamParser(options) { - if (!(this instanceof N3StreamParser)) - return new N3StreamParser(options); + var nbs = unifyTerm(self[0], other[0], bindings, formula); + if (nbs.length === 0) { + return nbs; + } + var res = []; + var i; + var n = nbs.length; + var nb; + var j; + var m; + var v; + var nb2; + var bindings2; + for (i = 0; i < n; i++) { + // for each possibility from the first term + nb = nbs[i][0]; // new bindings + bindings2 = []; + for (v in nb) { + if (nb.hasOwnProperty(v)) { + bindings2[v] = nb[v]; // copy + } + } + for (v in bindings) { + if (bindings.hasOwnProperty(v)) { + bindings2[v] = bindings[v]; // copy + } + } + nbs2 = unifyContents(self.slice(1), other.slice(1), bindings2, formula); + m = nbs2.length; + for (j = 0; j < m; j++) { + nb2 = nbs2[j][0]; // @@@@ no idea whether this is used or right + for (v in nb) { + if (nb.hasOwnProperty(v)) { + nb2[v] = nb[v]; + } + } + res.push([nb2, null]); + } + } + return res; + }; // unifyContents - // Initialize Transform base class - Transform.call(this, { decodeStrings: true }); - this._readableState.objectMode = true; + // Matching + // + // Matching finds all bindings such that when the binding is applied + // to one term it is equal to the other term. We only match formulae. - // Set up parser - var self = this, parser = new N3Parser(options); - parser.parse( - // Handle triples by pushing them down the pipeline - function (error, triple) { - triple && self.push(triple) || - error && self.emit('error', error); - }, - // Emit prefixes through the `prefix` event - this.emit.bind(this, 'prefix')); + /** if x is not in the bindings array, return the var; otherwise, return the bindings **/ + var bind = function bind(x, binding) { + var y = binding[x]; + if (y === undefined) { + return x; + } + return y; + }; - // Implement Transform methods on top of parser - this._transform = function (chunk, encoding, done) { parser.addChunk(chunk); done(); }; - this._flush = function (done) { parser.end(); done(); }; -} -util.inherits(N3StreamParser, Transform); + // When there are OPTIONAL clauses, we must return bindings without them if none of them + // succeed. However, if any of them do succeed, we should not. (This is what branchCount() + // tracked. The problem currently is (2011/7) that when several optionals exist, and they + // all match, multiple sets of bindings are returned, each with one optional filled in.) -// ## Exports -// Export the `N3StreamParser` class as a whole. -module.exports = N3StreamParser; + var union = function union(a, b) { + var c = {}; + var x; + for (x in a) { + if (a.hasOwnProperty(x)) { + c[x] = a[x]; + } + } + for (x in b) { + if (b.hasOwnProperty(x)) { + c[x] = b[x]; + } + } + return c; + }; -},{"./N3Parser.js":78,"stream":101,"util":112}],81:[function(_dereq_,module,exports){ -// **N3StreamWriter** serializes a triple stream into an N3 stream -var Transform = _dereq_('stream').Transform, - util = _dereq_('util'), - N3Writer = _dereq_('./N3Writer.js'); + var OptionalBranchJunction = function OptionalBranchJunction(originalCallback, trunkBindings) { + this.trunkBindings = trunkBindings; + this.originalCallback = originalCallback; + this.branches = []; + // this.results = []; // result[i] is an array of bindings for branch i + // this.done = {}; // done[i] means all/any results are in for branch i + // this.count = {} + return this; + }; -// ## Constructor -function N3StreamWriter(options) { - if (!(this instanceof N3StreamWriter)) - return new N3StreamWriter(options); + OptionalBranchJunction.prototype.checkAllDone = function () { + var i; + for (i = 0; i < this.branches.length; i++) { + if (!this.branches[i].done) { + return; + } + } + log.debug('OPTIONAL BIDNINGS ALL DONE:'); + this.doCallBacks(this.branches.length - 1, this.trunkBindings); + }; + // Recrursively generate the cross product of the bindings + OptionalBranchJunction.prototype.doCallBacks = function (b, bindings) { + var j; + if (b < 0) { + return this.originalCallback(bindings); + } + for (j = 0; j < this.branches[b].results.length; j++) { + this.doCallBacks(b - 1, union(bindings, this.branches[b].results[j])); + } + }; - // Initialize Transform base class - Transform.call(this, { encoding: 'utf8' }); - this._writableState.objectMode = true; + // A mandatory branch is the normal one, where callbacks + // are made immediately and no junction is needed. + // Might be useful for onFinsihed callback for query API. + var MandatoryBranch = function MandatoryBranch(callback, onDone) { + this.count = 0; + this.success = false; + this.done = false; + // this.results = [] + this.callback = callback; + this.onDone = onDone; + // this.junction = junction + // junction.branches.push(this) + return this; + }; - // Set up writer with a dummy stream object - var self = this; - var writer = new N3Writer({ - write: function (chunk, encoding, callback) { self.push(chunk); callback && callback(); }, - end: function (callback) { self.push(null); callback && callback(); }, - }, options); + MandatoryBranch.prototype.reportMatch = function (bindings) { + // log.error("@@@@ query.js 1"); // @@ + this.callback(bindings); + this.success = true; + }; - // Implement Transform methods on top of writer - this._transform = function (triple, encoding, done) { writer.addTriple(triple, done); }; - this._flush = function (done) { writer.end(done); }; -} -util.inherits(N3StreamWriter, Transform); + MandatoryBranch.prototype.reportDone = function () { + this.done = true; + log.info('Mandatory query branch finished.***'); + if (this.onDone !== undefined) { + this.onDone(); + } + }; -// ## Exports -// Export the `N3StreamWriter` class as a whole. -module.exports = N3StreamWriter; + // An optional branch hoards its results. + var OptionalBranch = function OptionalBranch(junction) { + this.count = 0; + this.done = false; + this.results = []; + this.junction = junction; + junction.branches.push(this); + return this; + }; -},{"./N3Writer.js":83,"stream":101,"util":112}],82:[function(_dereq_,module,exports){ -// **N3Util** provides N3 utility functions + OptionalBranch.prototype.reportMatch = function (bindings) { + this.results.push(bindings); + }; -var Xsd = 'http://www.w3.org/2001/XMLSchema#'; -var XsdString = Xsd + 'string'; -var XsdInteger = Xsd + 'integer'; -var XsdDecimal = Xsd + 'decimal'; -var XsdBoolean = Xsd + 'boolean'; -var RdfLangString = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString'; + OptionalBranch.prototype.reportDone = function () { + log.debug('Optional branch finished - results.length = ' + this.results.length); + if (this.results.length === 0) { + // This is what optional means: if no hits, + this.results.push({}); // mimic success, but with no bindings + log.debug("Optional branch FAILED - that's OK."); + } + this.done = true; + this.junction.checkAllDone(); + }; -var N3Util = { - // Tests whether the given entity (triple object) represents an IRI in the N3 library - isIRI: function (entity) { - if (!entity) - return entity; - var firstChar = entity[0]; - return firstChar !== '"' && firstChar !== '_'; - }, + /** prepare -- sets the index of the item to the possible matches + * @param f - formula + * @param item - an Statement, possibly w/ vars in it + * @param bindings - + * @returns true if the query fails -- there are no items that match **/ + var prepare = function prepare(f, item, bindings) { + var t, terms, termIndex, i, ind; + item.nvars = 0; + item.index = null; + // if (!f.statements) log.warn("@@@ prepare: f is "+f) + // log.debug("Prepare: f has "+ f.statements.length) + // log.debug("Prepare: Kb size "+f.statements.length+" Preparing "+item) - // Tests whether the given entity (triple object) represents a literal in the N3 library - isLiteral: function (entity) { - return entity && entity[0] === '"'; - }, + terms = [item.subject, item.predicate, item.object]; + ind = [f.subjectIndex, f.predicateIndex, f.objectIndex]; + for (i = 0; i < 3; i++) { + // alert("Prepare "+terms[i]+" "+(terms[i] in bindings)) + if (terms[i].isVar && !(bindings[terms[i]] !== undefined)) { + item.nvars++; + } else { + t = bind(terms[i], bindings); // returns the RDF binding if bound, otherwise itself + // if (terms[i]!=bind(terms[i],bindings) alert("Term: "+terms[i]+"Binding: "+bind(terms[i], bindings)) + if (f.redirections[t.hashString()]) { + t = f.redirections[t.hashString()]; // redirect + } + termIndex = ind[i][t.hashString()]; - // Tests whether the given entity (triple object) represents a blank node in the N3 library - isBlank: function (entity) { - return entity && entity.substr(0, 2) === '_:'; - }, + if (!termIndex) { + item.index = []; + return false; // Query line cannot match + } + if (item.index === null || item.index.length > termIndex.length) { + item.index = termIndex; + } + } + } - // Gets the string value of a literal in the N3 library - getLiteralValue: function (literal) { - var match = /^"([^]*)"/.exec(literal); - if (!match) - throw new Error(literal + ' is not a literal'); - return match[1]; - }, + if (item.index === null) { + // All 3 are variables? + item.index = f.statements; + } + return true; + }; // prepare - // Gets the type of a literal in the N3 library - getLiteralType: function (literal) { - var match = /^"[^]*"(?:\^\^([^"]+)|(@)[^@"]+)?$/.exec(literal); - if (!match) - throw new Error(literal + ' is not a literal'); - return match[1] || (match[2] ? RdfLangString : XsdString); - }, + /** sorting function -- negative if self is easier **/ + // We always prefer to start with a URI to be able to browse a graph + // this is why we put off items with more variables till later. + function easiestQuery(self, other) { + if (self.nvars !== other.nvars) { + return self.nvars - other.nvars; + } + return self.index.length - other.index.length; + } - // Gets the language of a literal in the N3 library - getLiteralLanguage: function (literal) { - var match = /^"[^]*"(?:@([^@"]+)|\^\^[^"]+)?$/.exec(literal); - if (!match) - throw new Error(literal + ' is not a literal'); - return match[1] ? match[1].toLowerCase() : ''; - }, + var match_index = 0; // index + /** matches a pattern formula against the knowledge base, e.g. to find matches for table-view + * + * @param f - knowledge base formula + * @param g - pattern formula (may have vars) + * @param bindingsSoFar - bindings accumulated in matching to date + * @param level - spaces to indent stuff also lets you know what level of recursion you're at + * @param fetcher - function (term, requestedBy) - myFetcher / AJAR_handleNewTerm / the sort + * @param localCallback - function(bindings, pattern, branch) called on sucess + * @returns nothing + * + * Will fetch linked data from the web iff the knowledge base an associated source fetcher (f.fetcher) + ***/ + var match = function match(f, g, bindingsSoFar, level, fetcher, localCallback, branch) { + log.debug('Match begins, Branch count now: ' + branch.count + ' for ' + branch.pattern_debug); + var sf = f.fetcher ? f.fetcher : null; + // log.debug("match: f has "+f.statements.length+", g has "+g.statements.length) + var pattern = g.statements; + if (pattern.length === 0) { + // when it's satisfied all the pattern triples + log.debug('FOUND MATCH WITH BINDINGS:' + bindingDebug(bindingsSoFar)); + if (g.optional.length === 0) { + branch.reportMatch(bindingsSoFar); + } else { + log.debug('OPTIONAL: ' + g.optional); + var junction = new OptionalBranchJunction(callback, bindingsSoFar); // @@ won't work with nested optionals? nest callbacks + var br = []; + var b; + for (b = 0; b < g.optional.length; b++) { + br[b] = new OptionalBranch(junction); // Allocate branches to prevent premature ending + br[b].pattern_debug = g.optional[b]; // for diagnotics only + } + for (b = 0; b < g.optional.length; b++) { + br[b].count = br[b].count + 1; // Count how many matches we have yet to complete + match(f, g.optional[b], bindingsSoFar, '', fetcher, callback, br[b]); + } + } + branch.count--; + log.debug('Match ends -- success , Branch count now: ' + branch.count + ' for ' + branch.pattern_debug); + return; // Success + } - // Tests whether the given entity (triple object) represents a prefixed name - isPrefixedName: function (entity) { - return entity && /^[^:\/"']*:[^:\/"']+$/.test(entity); - }, + var item; + var i; + var n = pattern.length; + // log.debug(level + "Match "+n+" left, bs so far:"+bindingDebug(bindingsSoFar)) - // Expands the prefixed name to a full IRI (also when it occurs as a literal's type) - expandPrefixedName: function (prefixedName, prefixes) { - var match = /(?:^|"\^\^)([^:\/#"'\^_]*):[^\/]*$/.exec(prefixedName), prefix, base, index; - if (match) - prefix = match[1], base = prefixes[prefix], index = match.index; - if (base === undefined) - return prefixedName; + // Follow links from variables in query + if (sf) { + // Fetcher is used to fetch URIs, function first term is a URI term, second is the requester + var id = 'match' + match_index++; + var fetchResource = function fetchResource(requestedTerm, id) { + var docuri = requestedTerm.uri.split('#')[0]; + sf.nowOrWhenFetched(docuri, undefined, function (err, body, xhr) { + if (err) { + console.log('Error following link to <' + requestedTerm.uri + '> in query: ' + body); + } + match(f, g, bindingsSoFar, level, fetcher, // match not match2 to look up any others necessary. + localCallback, branch); + }); + /* + if( sf ) { + sf.addCallback('done', function(uri) { + if ((kb.canon(kb.sym(uri)).uri !== path) && (uri !== kb.canon(kb.sym(path)))) { + return true + } + return false + }) + } + fetcher(requestedTerm, id) + */ + }; + for (i = 0; i < n; i++) { + item = pattern[i]; // for each of the triples in the query + if (bindingsSoFar[item.subject] !== undefined && bindingsSoFar[item.subject].uri && sf && sf.getState(docpart(bindingsSoFar[item.subject].uri)) === 'unrequested') { + // fetch the subject info and return to id + fetchResource(bindingsSoFar[item.subject], id); + return; // only look up one per line this time, but we will come back again though match + } + if (bindingsSoFar[item.object] !== undefined && bindingsSoFar[item.object].uri && sf && sf.getState(docpart(bindingsSoFar[item.object].uri)) === 'unrequested') { + fetchResource(bindingsSoFar[item.object], id); + return; + } + } + } // if sf + match2(f, g, bindingsSoFar, level, fetcher, localCallback, branch); + return; + }; // match - // The match index is non-zero when expanding a literal's type. - return index === 0 ? base + prefixedName.substr(prefix.length + 1) - : prefixedName.substr(0, index + 3) + - base + prefixedName.substr(index + prefix.length + 4); - }, + var constraintsSatisfied = function constraintsSatisfied(bindings, constraints) { + var res = true; + var x; + var test; + for (x in bindings) { + if (bindings.hasOwnProperty(x)) { + if (constraints[x]) { + test = constraints[x].test; + if (test && !test(bindings[x])) { + res = false; + } + } + } + } + return res; + }; - // Creates an IRI in N3.js representation - createIRI: function (iri) { - return iri && iri[0] === '"' ? N3Util.getLiteralValue(iri) : iri; - }, + /** match2 -- stuff after the fetch **/ + var match2 = function match2(f, g, bindingsSoFar, level, fetcher, callback, branch) { + // post fetch + var pattern = g.statements; + var n = pattern.length; + var i; + var k; + var nk; + var v; + var bindings2; + var newBindings1; + var item; + for (i = 0; i < n; i++) { + // For each statement left in the query, run prepare + item = pattern[i]; + log.info('match2: item=' + item + ', bindingsSoFar=' + bindingDebug(bindingsSoFar)); + prepare(f, item, bindingsSoFar); + } + pattern.sort(easiestQuery); + item = pattern[0]; + // log.debug("Sorted pattern:\n"+pattern) + var rest = f.formula(); + rest.optional = g.optional; + rest.constraints = g.constraints; + rest.statements = pattern.slice(1); // No indexes: we will not query g. + log.debug(level + 'match2 searching ' + item.index.length + ' for ' + item + '; bindings so far=' + bindingDebug(bindingsSoFar)); + // var results = [] + var c; + var nc = item.index.length; + var nbs1; + var st; + var onward = 0; + // var x + for (c = 0; c < nc; c++) { + // For each candidate statement + st = item.index[c]; // for each statement in the item's index, spawn a new match with that binding + nbs1 = unifyContents([item.subject, item.predicate, item.object], [st.subject, st.predicate, st.object], bindingsSoFar, f); + log.info(level + ' From first: ' + nbs1.length + ': ' + bindingsDebug(nbs1)); + nk = nbs1.length; + // branch.count += nk + // log.debug("Branch count bumped "+nk+" to: "+branch.count) + for (k = 0; k < nk; k++) { + // For each way that statement binds + bindings2 = []; + newBindings1 = nbs1[k][0]; + if (!constraintsSatisfied(newBindings1, g.constraints)) { + // branch.count-- + log.debug('Branch count CS: ' + branch.count); + } else { + for (v in newBindings1) { + if (newBindings1.hasOwnProperty(v)) { + bindings2[v] = newBindings1[v]; // copy + } + } + for (v in bindingsSoFar) { + if (bindingsSoFar.hasOwnProperty(v)) { + bindings2[v] = bindingsSoFar[v]; // copy + } + } - // Creates a literal in N3.js representation - createLiteral: function (value, modifier) { - if (!modifier) { - switch (typeof value) { - case 'boolean': - modifier = XsdBoolean; - break; - case 'number': - if (isFinite(value)) { - modifier = value % 1 === 0 ? XsdInteger : XsdDecimal; - break; + branch.count++; // Count how many matches we have yet to complete + onward++; + match(f, rest, bindings2, level + ' ', fetcher, callback, branch); // call match } - default: - return '"' + value + '"'; } } - return '"' + value + - (/^[a-z]+(-[a-z0-9]+)*$/i.test(modifier) ? '"@' + modifier.toLowerCase() - : '"^^' + modifier); - }, -}; - -// Add the N3Util functions to the given object or its prototype -function addN3Util(parent, toPrototype) { - for (var name in N3Util) - if (!toPrototype) - parent[name] = N3Util[name]; - else - parent.prototype[name] = applyToThis(N3Util[name]); + branch.count--; + if (onward === 0) { + log.debug('Match2 fails completely on ' + item); + } + log.debug('Match2 ends, Branch count: ' + branch.count + ' for ' + branch.pattern_debug); + if (branch.count === 0) { + log.debug('Branch finished.'); + branch.reportDone(); + } + }; // match2 + // ////////////////////////// Body of query() /////////////////////// + /* + if(!fetcher) { + fetcher=function (x, requestedBy) { + if (x === null) { + return + } + $rdf.Util.AJAR_handleNewTerm(kb, x, requestedBy) + } + } + */ + // prepare, oncallback: match1 + // match1: fetcher, oncallback: match2 + // match2, oncallback: populatetable + // log.debug("Query F length"+this.statements.length+" G="+myQuery) + var f = this; + log.debug('Query on ' + this.statements.length); + // kb.remoteQuery(myQuery,'http://jena.hpl.hp.com:3040/backstage',callback) + // return + var trunck = new MandatoryBranch(callback, onDone); + trunck.count++; // count one branch to complete at the moment + setTimeout(function () { + match(f, myQuery.pat, myQuery.pat.initBindings, '', fetcher, callback, trunck /* branch */); + }, 0); - return parent; -} + return; // returns nothing; callback does the work +} // query -// Returns a function that applies `f` to the `this` object -function applyToThis(f) { - return function (a) { return f(this, a); }; -} +module.exports.Query = Query; +module.exports.indexedFormulaQuery = indexedFormulaQuery; +},{"./indexed-formula":249,"./log":252,"./uri":269}],261:[function(_dereq_,module,exports){ +'use strict'; -// Expose N3Util, attaching all functions to it -module.exports = addN3Util(addN3Util); +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); -},{}],83:[function(_dereq_,module,exports){ -// **N3Writer** writes N3 documents. +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -// Matches a literal as represented in memory by the N3 library -var N3LiteralMatcher = /^"([^]*)"(?:\^\^(.+)|@([\-a-z]+))?$/i; +// RDFa Parser for rdflib.js -// rdf:type predicate (for 'a' abbreviation) -var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', - RDF_TYPE = RDF_PREFIX + 'type'; +// Originally by: Alex Milowski +// From https://github.com/alexmilowski/green-turtle +// Converted: timbl 2015-08-25 not yet working +// Added wrapper: csarven 2016-05-09 working -// Characters in literals that require escaping -var escape = /["\\\t\n\r\b\f\u0000-\u0019\ud800-\udbff]/, - escapeAll = /["\\\t\n\r\b\f\u0000-\u0019]|[\ud800-\udbff][\udc00-\udfff]/g, - escapeReplacements = { '\\': '\\\\', '"': '\\"', '\t': '\\t', - '\n': '\\n', '\r': '\\r', '\b': '\\b', '\f': '\\f' }; +// RDFaProcessor.prototype = new Object() // Was URIResolver -// ## Constructor -function N3Writer(outputStream, options) { - if (!(this instanceof N3Writer)) - return new N3Writer(outputStream, options); +// RDFaProcessor.prototype.constructor=RDFaProcessor - // Shift arguments if the first argument is not a stream - if (outputStream && typeof outputStream.write !== 'function') - options = outputStream, outputStream = null; - options = options || {}; +// options.base = base URI not really an option, shopuld always be set. +// - // If no output stream given, send the output as string through the end callback - if (!outputStream) { - var output = ''; - this._outputStream = { - write: function (chunk, encoding, done) { output += chunk; done && done(); }, - end: function (done) { done && done(null, output); }, - }; - this._endStream = true; - } - else { - this._outputStream = outputStream; - this._endStream = options.end === undefined ? true : !!options.end; - } +var BlankNode = _dereq_('./blank-node'); +var Literal = _dereq_('./literal'); +var rdf = _dereq_('./data-factory'); +var NamedNode = _dereq_('./named-node'); +var Uri = _dereq_('./uri'); +var Util = _dereq_('./util'); - // Initialize writer, depending on the format - this._subject = null; - if (!(/triple|quad/i).test(options.format)) { - this._graph = ''; - this._prefixIRIs = Object.create(null); - options.prefixes && this.addPrefixes(options.prefixes); - } - else { - this._writeTriple = this._writeTripleLine; - } +if (typeof Node === 'undefined') { + // @@@@@@ Global. Interface to xmldom. + var Node = { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }; } -N3Writer.prototype = { - // ## Private methods +var RDFaProcessor = function () { + function RDFaProcessor(kb, options) { + _classCallCheck(this, RDFaProcessor); - // ### `_write` writes the argument to the output stream - _write: function (string, callback) { - this._outputStream.write(string, 'utf8', callback); - }, + this.options = options || {}; + this.kb = kb; + this.target = options.target || { + graph: { + subjects: {}, + prefixes: {}, + terms: {} + } + }; + // XXX: Added to track bnodes + this.blankNodes = []; + // XXX: Added for normalisation + this.htmlOptions = { + 'selfClosing': 'br img input area base basefont col colgroup source wbr isindex link meta param hr' + }; + this.theOne = '_:' + new Date().getTime(); + this.language = null; + this.vocabulary = null; + this.blankCounter = 0; + this.langAttributes = [{ namespaceURI: 'http://www.w3.org/XML/1998/namespace', localName: 'lang' }]; + this.inXHTMLMode = false; + this.absURIRE = /[\w\_\-]+:\S+/; + this.finishedHandlers = []; + this.init(); + } - // ### `_writeTriple` writes the triple to the output stream - _writeTriple: function (subject, predicate, object, graph, done) { - try { - // Write the graph's label if it has changed - if (this._graph !== graph) { - // Close the previous graph and start the new one - this._write((this._subject === null ? '' : (this._graph ? '\n}\n' : '.\n')) + - (graph ? this._encodeIriOrBlankNode(graph) + ' {\n' : '')); - this._subject = null; - // Don't treat identical blank nodes as repeating graphs - this._graph = graph[0] !== '[' ? graph : ']'; + _createClass(RDFaProcessor, [{ + key: 'addTriple', + value: function addTriple(origin, subject, predicate, object) { + var su, ob, pr, or; + if (typeof subject === 'undefined') { + su = rdf.namedNode(this.options.base); + } else { + su = this.toRDFNodeObject(subject); } - // Don't repeat the subject if it's the same - if (this._subject === subject) { - // Don't repeat the predicate if it's the same - if (this._predicate === predicate) - this._write(', ' + this._encodeObject(object), done); - // Same subject, different predicate - else - this._write(';\n ' + - this._encodePredicate(this._predicate = predicate) + ' ' + - this._encodeObject(object), done); + pr = this.toRDFNodeObject(predicate); + ob = this.toRDFNodeObject(object); + or = rdf.namedNode(this.options.base); + // console.log('Adding { ' + su + ' ' + pr + ' ' + ob + ' ' + or + ' }') + this.kb.add(su, pr, ob, or); + } + }, { + key: 'ancestorPath', + value: function ancestorPath(node) { + var path = ''; + while (node && node.nodeType !== Node.DOCUMENT_NODE) { + path = '/' + node.localName + path; + node = node.parentNode; } - // Different subject; write the whole triple - else - this._write((this._subject === null ? '' : '.\n') + - this._encodeSubject(this._subject = subject) + ' ' + - this._encodePredicate(this._predicate = predicate) + ' ' + - this._encodeObject(object), done); + return path; } - catch (error) { done && done(error); } - }, - - // ### `_writeTripleLine` writes the triple or quad to the output stream as a single line - _writeTripleLine: function (subject, predicate, object, graph, done) { - // Don't use prefixes - delete this._prefixMatch; - // Write the triple - try { - this._write(this._encodeIriOrBlankNode(subject) + ' ' + - this._encodeIriOrBlankNode(predicate) + ' ' + - this._encodeObject(object) + - (graph ? ' ' + this._encodeIriOrBlankNode(graph) + '.\n' : '.\n'), done); + }, { + key: 'copyMappings', + value: function copyMappings(mappings) { + var newMappings = {}; + for (var k in mappings) { + newMappings[k] = mappings[k]; + } + return newMappings; } - catch (error) { done && done(error); } - }, - - // ### `_encodeIriOrBlankNode` represents an IRI or blank node - _encodeIriOrBlankNode: function (entity) { - // A blank node or list is represented as-is - var firstChar = entity[0]; - if (firstChar === '[' || firstChar === '(' || firstChar === '_' && entity[1] === ':') - return entity; - // Escape special characters - if (escape.test(entity)) - entity = entity.replace(escapeAll, characterReplacer); - // Try to represent the IRI as prefixed name - var prefixMatch = this._prefixRegex.exec(entity); - return !prefixMatch ? '<' + entity + '>' : - (!prefixMatch[1] ? entity : this._prefixIRIs[prefixMatch[1]] + prefixMatch[2]); - }, - - // ### `_encodeLiteral` represents a literal - _encodeLiteral: function (value, type, language) { - // Escape special characters - if (escape.test(value)) - value = value.replace(escapeAll, characterReplacer); - // Write the literal, possibly with type or language - if (language) - return '"' + value + '"@' + language; - else if (type) - return '"' + value + '"^^' + this._encodeIriOrBlankNode(type); - else - return '"' + value + '"'; - }, - - // ### `_encodeSubject` represents a subject - _encodeSubject: function (subject) { - if (subject[0] === '"') - throw new Error('A literal as subject is not allowed: ' + subject); - // Don't treat identical blank nodes as repeating subjects - if (subject[0] === '[') - this._subject = ']'; - return this._encodeIriOrBlankNode(subject); - }, - - // ### `_encodePredicate` represents a predicate - _encodePredicate: function (predicate) { - if (predicate[0] === '"') - throw new Error('A literal as predicate is not allowed: ' + predicate); - return predicate === RDF_TYPE ? 'a' : this._encodeIriOrBlankNode(predicate); - }, - - // ### `_encodeObject` represents an object - _encodeObject: function (object) { - // Represent an IRI or blank node - if (object[0] !== '"') - return this._encodeIriOrBlankNode(object); - // Represent a literal - var match = N3LiteralMatcher.exec(object); - if (!match) throw new Error('Invalid literal: ' + object); - return this._encodeLiteral(match[1], match[2], match[3]); - }, - - // ### `_blockedWrite` replaces `_write` after the writer has been closed - _blockedWrite: function () { - throw new Error('Cannot write because the writer has been closed.'); - }, - - // ### `addTriple` adds the triple to the output stream - addTriple: function (subject, predicate, object, graph, done) { - // The triple was given as a triple object, so shift parameters - if (object === undefined) - this._writeTriple(subject.subject, subject.predicate, subject.object, - subject.graph || '', predicate); - // The optional `graph` parameter was not provided - else if (typeof graph !== 'string') - this._writeTriple(subject, predicate, object, '', graph); - // The `graph` parameter was provided - else - this._writeTriple(subject, predicate, object, graph, done); - }, - - // ### `addTriples` adds the triples to the output stream - addTriples: function (triples) { - for (var i = 0; i < triples.length; i++) - this.addTriple(triples[i]); - }, - - // ### `addPrefix` adds the prefix to the output stream - addPrefix: function (prefix, iri, done) { - var prefixes = {}; - prefixes[prefix] = iri; - this.addPrefixes(prefixes, done); - }, + }, { + key: 'copyProperties', + value: function copyProperties() {} + }, { + key: 'deriveDateTimeType', + value: function deriveDateTimeType(value) { + for (var i = 0; i < RDFaProcessor.dateTimeTypes.length; i++) { + // console.log("Checking "+value+" against "+RDFaProcessor.dateTimeTypes[i].type) + var matched = RDFaProcessor.dateTimeTypes[i].pattern.exec(value); + if (matched && matched[0].length === value.length) { + // console.log("Matched!") + return RDFaProcessor.dateTimeTypes[i].type; + } + } + return null; + } + }, { + key: 'init', + value: function init() {} + }, { + key: 'newBlankNode', + value: function newBlankNode() { + this.blankCounter++; + return '_:' + this.blankCounter; + } + }, { + key: 'newSubjectOrigin', + value: function newSubjectOrigin(origin, subject) {} + }, { + key: 'parseCURIE', + value: function parseCURIE(value, prefixes, base) { + var colon = value.indexOf(':'); + var uri; + if (colon >= 0) { + var prefix = value.substring(0, colon); + if (prefix === '') { + // default prefix + uri = prefixes['']; + return uri ? uri + value.substring(colon + 1) : null; + } else if (prefix === '_') { + // blank node + return '_:' + value.substring(colon + 1); + } else if (RDFaProcessor.NCNAME.test(prefix)) { + uri = prefixes[prefix]; + if (uri) { + return uri + value.substring(colon + 1); + } + } + } + return null; + } + }, { + key: 'parseCURIEOrURI', + value: function parseCURIEOrURI(value, prefixes, base) { + var curie = this.parseCURIE(value, prefixes, base); + if (curie) { + return curie; + } + return this.resolveAndNormalize(base, value); + } + }, { + key: 'parsePredicate', + value: function parsePredicate(value, defaultVocabulary, terms, prefixes, base, ignoreTerms) { + if (value === '') { + return null; + } + var predicate = this.parseTermOrCURIEOrAbsURI(value, defaultVocabulary, ignoreTerms ? null : terms, prefixes, base); + if (predicate && predicate.indexOf('_:') === 0) { + return null; + } + return predicate; + } + }, { + key: 'parsePrefixMappings', + value: function parsePrefixMappings(str, target) { + var values = this.tokenize(str); + var prefix = null; + // var uri = null + for (var i = 0; i < values.length; i++) { + if (values[i][values[i].length - 1] === ':') { + prefix = values[i].substring(0, values[i].length - 1); + } else if (prefix) { + target[prefix] = this.options.base ? Uri.join(values[i], this.options.base) : values[i]; + prefix = null; + } + } + } + }, { + key: 'parseSafeCURIEOrCURIEOrURI', + value: function parseSafeCURIEOrCURIEOrURI(value, prefixes, base) { + value = this.trim(value); + if (value.charAt(0) === '[' && value.charAt(value.length - 1) === ']') { + value = value.substring(1, value.length - 1); + value = value.trim(value); + if (value.length === 0) { + return null; + } + if (value === '_:') { + // the one node + return this.theOne; + } + return this.parseCURIE(value, prefixes, base); + } else { + return this.parseCURIEOrURI(value, prefixes, base); + } + } + }, { + key: 'parseTermOrCURIEOrAbsURI', + value: function parseTermOrCURIEOrAbsURI(value, defaultVocabulary, terms, prefixes, base) { + // alert("Parsing "+value+" with default vocab "+defaultVocabulary) + value = this.trim(value); + var curie = this.parseCURIE(value, prefixes, base); + if (curie) { + return curie; + } else if (terms) { + if (defaultVocabulary && !this.absURIRE.exec(value)) { + return defaultVocabulary + value; + } + var term = terms[value]; + if (term) { + return term; + } + var lcvalue = value.toLowerCase(); + term = terms[lcvalue]; + if (term) { + return term; + } + } + if (this.absURIRE.exec(value)) { + return this.resolveAndNormalize(base, value); + } + return null; + } + }, { + key: 'parseTermOrCURIEOrURI', + value: function parseTermOrCURIEOrURI(value, defaultVocabulary, terms, prefixes, base) { + // alert("Parsing "+value+" with default vocab "+defaultVocabulary) + value = this.trim(value); + var curie = this.parseCURIE(value, prefixes, base); + if (curie) { + return curie; + } else { + var term = terms[value]; + if (term) { + return term; + } + var lcvalue = value.toLowerCase(); + term = terms[lcvalue]; + if (term) { + return term; + } + if (defaultVocabulary && !this.absURIRE.exec(value)) { + return defaultVocabulary + value; + } + } + return this.resolveAndNormalize(base, value); + } + }, { + key: 'parseURI', + value: function parseURI(uri) { + return uri; // We just use strings as URIs, not objects now. + } + }, { + key: 'process', + value: function process(node, options) { + /* + if (!window.console) { + window.console = { log: function() {} } + }*/ + var base; + if (node.nodeType === Node.DOCUMENT_NODE) { + base = node.baseURI; + node = node.documentElement; + node.baseURI = base; + this.setContext(node); + } else if (node.parentNode.nodeType === Node.DOCUMENT_NODE) { + this.setContext(node); + } + var queue = []; + // Fix for Firefox that includes the hash in the base URI + var removeHash = function removeHash(baseURI) { + // Fix for undefined baseURI property + if (!baseURI && options && options.baseURI) { + return options.baseURI; + } - // ### `addPrefixes` adds the prefixes to the output stream - addPrefixes: function (prefixes, done) { - // Add all useful prefixes - var prefixIRIs = this._prefixIRIs, hasPrefixes = false; - for (var prefix in prefixes) { - // Verify whether the prefix can be used and does not exist yet - var iri = prefixes[prefix]; - if (/[#\/]$/.test(iri) && prefixIRIs[iri] !== (prefix += ':')) { - hasPrefixes = true; - prefixIRIs[iri] = prefix; - // Finish a possible pending triple - if (this._subject !== null) { - this._write(this._graph ? '\n}\n' : '.\n'); - this._subject = null, this._graph = ''; + var hash = baseURI.indexOf('#'); + if (hash >= 0) { + baseURI = baseURI.substring(0, hash); + } + if (options && options.baseURIMap) { + baseURI = options.baseURIMap(baseURI); + } + return baseURI; + }; + queue.push({ current: node, + context: this.push(null, removeHash(node.baseURI)) + }); + while (queue.length > 0) { + var item = queue.shift(); + if (item.parent) { + // Sequence Step 14: list triple generation + if (item.context.parent && item.context.parent.listMapping === item.listMapping) { + // Skip a child context with exactly the same mapping + continue; + } + // console.log("Generating lists for "+item.subject+", tag "+item.parent.localName) + for (var _predicate in item.listMapping) { + var list = item.listMapping[_predicate]; + if (list.length === 0) { + this.addTriple(item.parent, item.subject, _predicate, { type: RDFaProcessor.objectURI, value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' }); + continue; + } + var bnodes = []; + for (var _i = 0; _i < list.length; _i++) { + bnodes.push(this.newBlankNode()); + // this.newSubject(item.parent,bnodes[i]) + } + for (var _i2 = 0; _i2 < bnodes.length; _i2++) { + this.addTriple(item.parent, bnodes[_i2], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', list[_i2]); + this.addTriple(item.parent, bnodes[_i2], 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', { type: RDFaProcessor.objectURI, value: _i2 + 1 < bnodes.length ? bnodes[_i2 + 1] : 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil' }); + } + this.addTriple(item.parent, item.subject, _predicate, { type: RDFaProcessor.objectURI, value: bnodes[0] }); + } + continue; + } + var current = item.current; + var context = item.context; + // console.log("Tag: "+current.localName+", listMapping="+JSON.stringify(context.listMapping)) + // Sequence Step 1 + var skip = false; + var newSubject = null; + var currentObjectResource = null; + var typedResource = null; + var prefixes = context.prefixes; + var prefixesCopied = false; + var incomplete = []; + var listMapping = context.listMapping; + var listMappingDifferent = !context.parent; + var language = context.language; + var vocabulary = context.vocabulary; + // TODO: the "base" element may be used for HTML+RDFa 1.1 + base = this.parseURI(removeHash(current.baseURI)); + current.item = null; + // Sequence Step 2: set the default vocabulary + var vocabAtt = current.getAttributeNode('vocab'); + if (vocabAtt) { + var value = this.trim(vocabAtt.value); + if (value.length > 0) { + vocabulary = value; + var baseSubject = base.spec; + // this.newSubject(current,baseSubject) + this.addTriple(current, baseSubject, 'http://www.w3.org/ns/rdfa#usesVocabulary', { type: RDFaProcessor.objectURI, value: vocabulary }); + } else { + vocabulary = this.vocabulary; + } + } + // Sequence Step 3: IRI mappings + // handle xmlns attributes + for (var i = 0; i < current.attributes.length; i++) { + var att = current.attributes[i]; + // if (att.namespaceURI=="http://www.w3.org/2000/xmlns/") { + if (att.nodeName.charAt(0) === 'x' && att.nodeName.indexOf('xmlns:') === 0) { + if (!prefixesCopied) { + prefixes = this.copyMappings(prefixes); + prefixesCopied = true; + } + var prefix = att.nodeName.substring(6); + // TODO: resolve relative? + var ref = RDFaProcessor.trim(att.value); + prefixes[prefix] = this.options.base ? Uri.join(ref, this.options.base) : ref; + } + } + // Handle prefix mappings (@prefix) + var prefixAtt = current.getAttributeNode('prefix'); + if (prefixAtt) { + if (!prefixesCopied) { + prefixes = this.copyMappings(prefixes); + prefixesCopied = true; + } + this.parsePrefixMappings(prefixAtt.value, prefixes); + } + // Sequence Step 4: language + var xmlLangAtt = null; + for (var _i3 = 0; !xmlLangAtt && _i3 < this.langAttributes.length; _i3++) { + xmlLangAtt = current.getAttributeNodeNS(this.langAttributes[_i3].namespaceURI, this.langAttributes[_i3].localName); + } + if (xmlLangAtt) { + var _value = RDFaProcessor.trim(xmlLangAtt.value); + if (_value.length > 0) { + language = _value; + } else { + language = null; + } + } + var relAtt = current.getAttributeNode('rel'); + var revAtt = current.getAttributeNode('rev'); + var typeofAtt = current.getAttributeNode('typeof'); + var propertyAtt = current.getAttributeNode('property'); + var datatypeAtt = current.getAttributeNode('datatype'); + var datetimeAtt = this.inHTMLMode ? current.getAttributeNode('datetime') : null; + var contentAtt = current.getAttributeNode('content'); + var aboutAtt = current.getAttributeNode('about'); + var srcAtt = current.getAttributeNode('src'); + var resourceAtt = current.getAttributeNode('resource'); + var hrefAtt = current.getAttributeNode('href'); + var inlistAtt = current.getAttributeNode('inlist'); + var relAttPredicates = []; + var predicate, values; + if (relAtt) { + values = this.tokenize(relAtt.value); + for (var _i4 = 0; _i4 < values.length; _i4++) { + predicate = this.parsePredicate(values[_i4], vocabulary, context.terms, prefixes, base, this.inHTMLMode && propertyAtt !== null); + if (predicate) { + relAttPredicates.push(predicate); + } + } + } + var revAttPredicates = []; + if (revAtt) { + values = this.tokenize(revAtt.value); + for (var _i5 = 0; _i5 < values.length; _i5++) { + predicate = this.parsePredicate(values[_i5], vocabulary, context.terms, prefixes, base, this.inHTMLMode && propertyAtt); + if (predicate) { + revAttPredicates.push(predicate); + } + } + } + // Section 3.1, bullet 7 + if (this.inHTMLMode && (relAtt || revAtt) && propertyAtt) { + if (relAttPredicates.length === 0) { + relAtt = null; + } + if (revAttPredicates.length === 0) { + revAtt = null; + } + } + if (relAtt || revAtt) { + // Sequence Step 6: establish new subject and value + if (aboutAtt) { + newSubject = this.parseSafeCURIEOrCURIEOrURI(aboutAtt.value, prefixes, base); + } + if (typeofAtt) { + typedResource = newSubject; + } + if (!newSubject) { + if (current.parentNode.nodeType === Node.DOCUMENT_NODE) { + newSubject = removeHash(current.baseURI); + } else if (context.parentObject) { + // TODO: Verify: If the xml:base has been set and the parentObject is the baseURI of the parent, then the subject needs to be the new base URI + newSubject = removeHash(current.parentNode.baseURI) === context.parentObject ? removeHash(current.baseURI) : context.parentObject; + } + } + if (resourceAtt) { + currentObjectResource = this.parseSafeCURIEOrCURIEOrURI(resourceAtt.value, prefixes, base); + } + if (!currentObjectResource) { + if (hrefAtt) { + currentObjectResource = this.resolveAndNormalize(base, encodeURI(hrefAtt.value)); + } else if (srcAtt) { + currentObjectResource = this.resolveAndNormalize(base, encodeURI(srcAtt.value)); + } else if (typeofAtt && !aboutAtt && !(this.inXHTMLMode && (current.localName === 'head' || current.localName === 'body'))) { + currentObjectResource = this.newBlankNode(); + } + } + if (typeofAtt && !aboutAtt && this.inXHTMLMode && (current.localName === 'head' || current.localName === 'body')) { + typedResource = newSubject; + } else if (typeofAtt && !aboutAtt) { + typedResource = currentObjectResource; + } + } else if (propertyAtt && !contentAtt && !datatypeAtt) { + // Sequence Step 5.1: establish a new subject + if (aboutAtt) { + newSubject = this.parseSafeCURIEOrCURIEOrURI(aboutAtt.value, prefixes, base); + if (typeofAtt) { + typedResource = newSubject; + } + } + if (!newSubject && current.parentNode.nodeType === Node.DOCUMENT_NODE) { + newSubject = removeHash(current.baseURI); + if (typeofAtt) { + typedResource = newSubject; + } + } else if (!newSubject && context.parentObject) { + // TODO: Verify: If the xml:base has been set and the parentObject is the baseURI of the parent, then the subject needs to be the new base URI + newSubject = removeHash(current.parentNode.baseURI) === context.parentObject ? removeHash(current.baseURI) : context.parentObject; + } + if (typeofAtt && !typedResource) { + if (resourceAtt) { + typedResource = this.parseSafeCURIEOrCURIEOrURI(resourceAtt.value, prefixes, base); + } + if (!typedResource && hrefAtt) { + typedResource = this.resolveAndNormalize(base, encodeURI(hrefAtt.value)); + } + if (!typedResource && srcAtt) { + typedResource = this.resolveAndNormalize(base, encodeURI(srcAtt.value)); + } + if (!typedResource && (this.inXHTMLMode || this.inHTMLMode) && (current.localName === 'head' || current.localName === 'body')) { + typedResource = newSubject; + } + if (!typedResource) { + typedResource = this.newBlankNode(); + } + currentObjectResource = typedResource; + } + // console.log(current.localName+", newSubject="+newSubject+", typedResource="+typedResource+", currentObjectResource="+currentObjectResource) + } else { + // Sequence Step 5.2: establish a new subject + if (aboutAtt) { + newSubject = this.parseSafeCURIEOrCURIEOrURI(aboutAtt.value, prefixes, base); + } + if (!newSubject && resourceAtt) { + newSubject = this.parseSafeCURIEOrCURIEOrURI(resourceAtt.value, prefixes, base); + } + if (!newSubject && hrefAtt) { + newSubject = this.resolveAndNormalize(base, encodeURI(hrefAtt.value)); + } + if (!newSubject && srcAtt) { + newSubject = this.resolveAndNormalize(base, encodeURI(srcAtt.value)); + } + if (!newSubject) { + if (current.parentNode.nodeType === Node.DOCUMENT_NODE) { + newSubject = removeHash(current.baseURI); + } else if ((this.inXHTMLMode || this.inHTMLMode) && (current.localName === 'head' || current.localName === 'body')) { + newSubject = removeHash(current.parentNode.baseURI) === context.parentObject ? removeHash(current.baseURI) : context.parentObject; + } else if (typeofAtt) { + newSubject = this.newBlankNode(); + } else if (context.parentObject) { + // TODO: Verify: If the xml:base has been set and the parentObject is the baseURI of the parent, then the subject needs to be the new base URI + newSubject = removeHash(current.parentNode.baseURI) === context.parentObject ? removeHash(current.baseURI) : context.parentObject; + if (!propertyAtt) { + skip = true; + } + } + } + if (typeofAtt) { + typedResource = newSubject; + } + } + // console.log(current.tagName+": newSubject="+newSubject+", currentObjectResource="+currentObjectResource+", typedResource="+typedResource+", skip="+skip) + // var rdfaData = null + if (newSubject) { + // this.newSubject(current,newSubject) + if (aboutAtt || resourceAtt || typedResource) { + var id = newSubject; + if (typeofAtt && !aboutAtt && !resourceAtt && currentObjectResource) { + id = currentObjectResource; + } + // console.log("Setting data attribute for "+current.localName+" for subject "+id) + this.newSubjectOrigin(current, id); + } + } + // Sequence Step 7: generate type triple + if (typedResource) { + values = this.tokenize(typeofAtt.value); + for (var _i6 = 0; _i6 < values.length; _i6++) { + var object = this.parseTermOrCURIEOrAbsURI(values[_i6], vocabulary, context.terms, prefixes, base); + if (object) { + this.addTriple(current, typedResource, RDFaProcessor.typeURI, { type: RDFaProcessor.objectURI, value: object }); + } + } + } + // Sequence Step 8: new list mappings if there is a new subject + // console.log("Step 8: newSubject="+newSubject+", context.parentObject="+context.parentObject) + if (newSubject && newSubject !== context.parentObject) { + // console.log("Generating new list mapping for "+newSubject) + listMapping = {}; + listMappingDifferent = true; + } + // Sequence Step 9: generate object triple + if (currentObjectResource) { + if (relAtt && inlistAtt) { + for (var _i7 = 0; _i7 < relAttPredicates.length; _i7++) { + var _list = listMapping[relAttPredicates[_i7]]; + if (!_list) { + _list = []; + listMapping[relAttPredicates[_i7]] = _list; + } + _list.push({ type: RDFaProcessor.objectURI, value: currentObjectResource }); + } + } else if (relAtt) { + for (var _i8 = 0; _i8 < relAttPredicates.length; _i8++) { + this.addTriple(current, newSubject, relAttPredicates[_i8], { type: RDFaProcessor.objectURI, value: currentObjectResource }); + } + } + if (revAtt) { + for (var _i9 = 0; _i9 < revAttPredicates.length; _i9++) { + this.addTriple(current, currentObjectResource, revAttPredicates[_i9], { type: RDFaProcessor.objectURI, value: newSubject }); + } + } + } else { + // Sequence Step 10: incomplete triples + if (newSubject && !currentObjectResource && (relAtt || revAtt)) { + currentObjectResource = this.newBlankNode(); + // alert(current.tagName+": generated blank node, newSubject="+newSubject+" currentObjectResource="+currentObjectResource) + } + if (relAtt && inlistAtt) { + for (var _i10 = 0; _i10 < relAttPredicates.length; _i10++) { + var _list2 = listMapping[relAttPredicates[_i10]]; + if (!_list2) { + _list2 = []; + listMapping[predicate] = _list2; + } + // console.log("Adding incomplete list for "+predicate) + incomplete.push({ predicate: relAttPredicates[_i10], list: _list2 }); + } + } else if (relAtt) { + for (var _i11 = 0; _i11 < relAttPredicates.length; _i11++) { + incomplete.push({ predicate: relAttPredicates[_i11], forward: true }); + } + } + if (revAtt) { + for (var _i12 = 0; _i12 < revAttPredicates.length; _i12++) { + incomplete.push({ predicate: revAttPredicates[_i12], forward: false }); + } + } + } + // Step 11: Current property values + if (propertyAtt) { + var datatype = null; + var content = null; + if (datatypeAtt) { + datatype = datatypeAtt.value === '' ? RDFaProcessor.PlainLiteralURI : this.parseTermOrCURIEOrAbsURI(datatypeAtt.value, vocabulary, context.terms, prefixes, base); + if (datetimeAtt && !contentAtt) { + content = datetimeAtt.value; + } else { + content = datatype === RDFaProcessor.XMLLiteralURI || datatype === RDFaProcessor.HTMLLiteralURI ? null : contentAtt ? contentAtt.value : current.textContent; + } + } else if (contentAtt) { + datatype = RDFaProcessor.PlainLiteralURI; + content = contentAtt.value; + } else if (datetimeAtt) { + content = datetimeAtt.value; + datatype = RDFaProcessor.deriveDateTimeType(content); + if (!datatype) { + datatype = RDFaProcessor.PlainLiteralURI; + } + } else if (!relAtt && !revAtt) { + if (resourceAtt) { + content = this.parseSafeCURIEOrCURIEOrURI(resourceAtt.value, prefixes, base); + } + if (!content && hrefAtt) { + content = this.resolveAndNormalize(base, encodeURI(hrefAtt.value)); + } else if (!content && srcAtt) { + content = this.resolveAndNormalize(base, encodeURI(srcAtt.value)); + } + if (content) { + datatype = RDFaProcessor.objectURI; + } + } + if (!datatype) { + if (typeofAtt && !aboutAtt) { + datatype = RDFaProcessor.objectURI; + content = typedResource; + } else { + content = current.textContent; + if (this.inHTMLMode && current.localName === 'time') { + datatype = RDFaProcessor.deriveDateTimeType(content); + } + if (!datatype) { + datatype = RDFaProcessor.PlainLiteralURI; + } + } + } + values = this.tokenize(propertyAtt.value); + for (var _i13 = 0; _i13 < values.length; _i13++) { + var _predicate2 = this.parsePredicate(values[_i13], vocabulary, context.terms, prefixes, base); + if (_predicate2) { + if (inlistAtt) { + var _list3 = listMapping[_predicate2]; + if (!_list3) { + _list3 = []; + listMapping[_predicate2] = _list3; + } + _list3.push(datatype === RDFaProcessor.XMLLiteralURI || datatype === RDFaProcessor.HTMLLiteralURI ? { type: datatype, value: current.childNodes } : { type: datatype ? datatype : RDFaProcessor.PlainLiteralURI, value: content, language: language }); + } else { + if (datatype === RDFaProcessor.XMLLiteralURI || datatype === RDFaProcessor.HTMLLiteralURI) { + this.addTriple(current, newSubject, _predicate2, { type: datatype, value: current.childNodes }); + } else { + this.addTriple(current, newSubject, _predicate2, { type: datatype ? datatype : RDFaProcessor.PlainLiteralURI, value: content, language: language }); + // console.log(newSubject+" "+predicate+"="+content) + } + } + } + } } - // Write prefix - this._write('@prefix ' + prefix + ' <' + iri + '>.\n'); - } - } - // Recreate the prefix matcher - if (hasPrefixes) { - var IRIlist = '', prefixList = ''; - for (var prefixIRI in prefixIRIs) { - IRIlist += IRIlist ? '|' + prefixIRI : prefixIRI; - prefixList += (prefixList ? '|' : '') + prefixIRIs[prefixIRI]; - } - IRIlist = IRIlist.replace(/[\]\/\(\)\*\+\?\.\\\$]/g, '\\$&'); - this._prefixRegex = new RegExp('^(?:' + prefixList + ')[^\/]*$|' + - '^(' + IRIlist + ')([a-zA-Z][\\-_a-zA-Z0-9]*)$'); - } - // End a prefix block with a newline - this._write(hasPrefixes ? '\n' : '', done); - }, - - // ### `blank` creates a blank node with the given content - blank: function (predicate, object) { - var children = predicate, child, length; - // Empty blank node - if (predicate === undefined) - children = []; - // Blank node passed as blank("predicate", "object") - else if (typeof predicate === 'string') - children = [{ predicate: predicate, object: object }]; - // Blank node passed as blank({ predicate: predicate, object: object }) - else if (!('length' in predicate)) - children = [predicate]; - - switch (length = children.length) { - // Generate an empty blank node - case 0: - return '[]'; - // Generate a non-nested one-triple blank node - case 1: - child = children[0]; - if (child.object[0] !== '[') - return '[ ' + this._encodePredicate(child.predicate) + ' ' + - this._encodeObject(child.object) + ' ]'; - // Generate a multi-triple or nested blank node - default: - var contents = '['; - // Write all triples in order - for (var i = 0; i < length; i++) { - child = children[i]; - // Write only the object is the predicate is the same as the previous - if (child.predicate === predicate) - contents += ', ' + this._encodeObject(child.object); - // Otherwise, write the predicate and the object - else { - contents += (i ? ';\n ' : '\n ') + - this._encodePredicate(child.predicate) + ' ' + - this._encodeObject(child.object); - predicate = child.predicate; + // Sequence Step 12: complete incomplete triples with new subject + if (newSubject && !skip) { + for (var _i14 = 0; _i14 < context.incomplete.length; _i14++) { + if (context.incomplete[_i14].list) { + // console.log("Adding subject "+newSubject+" to list for "+context.incomplete[i].predicate) + // TODO: it is unclear what to do here + context.incomplete[_i14].list.push({ type: RDFaProcessor.objectURI, value: newSubject }); + } else if (context.incomplete[_i14].forward) { + // console.log(current.tagName+": completing forward triple "+context.incomplete[i].predicate+" with object="+newSubject) + this.addTriple(current, context.subject, context.incomplete[_i14].predicate, { type: RDFaProcessor.objectURI, value: newSubject }); + } else { + // console.log(current.tagName+": completing reverse triple with object="+context.subject) + this.addTriple(current, newSubject, context.incomplete[_i14].predicate, { type: RDFaProcessor.objectURI, value: context.subject }); + } + } } - } - return contents + '\n]'; - } - }, - - // ### `list` creates a list node with the given content - list: function (elements) { - var length = elements && elements.length || 0, contents = new Array(length); - for (var i = 0; i < length; i++) - contents[i] = this._encodeObject(elements[i]); - return '(' + contents.join(' ') + ')'; - }, - - // ### `_prefixRegex` matches a prefixed name or IRI that begins with one of the added prefixes - _prefixRegex: /$0^/, - - // ### `end` signals the end of the output stream - end: function (done) { - // Finish a possible pending triple - if (this._subject !== null) { - this._write(this._graph ? '\n}\n' : '.\n'); - this._subject = null; - } - // Disallow further writing - this._write = this._blockedWrite; - - // Try to end the underlying stream, ensuring done is called exactly one time - var singleDone = done && function (error, result) { singleDone = null, done(error, result); }; - if (this._endStream) { - try { return this._outputStream.end(singleDone); } - catch (error) { /* error closing stream */ } - } - singleDone && singleDone(); - }, -}; - -// Replaces a character by its escaped version -function characterReplacer(character) { - // Replace a single character by its escaped version - var result = escapeReplacements[character]; - if (result === undefined) { - // Replace a single character with its 4-bit unicode escape sequence - if (character.length === 1) { - result = character.charCodeAt(0).toString(16); - result = '\\u0000'.substr(0, 6 - result.length) + result; - } - // Replace a surrogate pair with its 8-bit unicode escape sequence - else { - result = ((character.charCodeAt(0) - 0xD800) * 0x400 + - character.charCodeAt(1) + 0x2400).toString(16); - result = '\\U00000000'.substr(0, 10 - result.length) + result; - } - } - return result; -} - -// ## Exports - -// Export the `N3Writer` class as a whole. -module.exports = N3Writer; - -},{}],84:[function(_dereq_,module,exports){ -module.exports = _dereq_('./lib/_stream_duplex.js'); - -},{"./lib/_stream_duplex.js":85}],85:[function(_dereq_,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// a duplex stream is just a stream that is both readable and writable. -// Since JS doesn't have multiple prototypal inheritance, this class -// prototypally inherits from Readable, and then parasitically from -// Writable. - -'use strict'; - -/**/ - -var processNextTick = _dereq_('process-nextick-args'); -/**/ - -/**/ -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) { - keys.push(key); - }return keys; -}; -/**/ - -module.exports = Duplex; - -/**/ -var util = _dereq_('core-util-is'); -util.inherits = _dereq_('inherits'); -/**/ - -var Readable = _dereq_('./_stream_readable'); -var Writable = _dereq_('./_stream_writable'); - -util.inherits(Duplex, Readable); - -var keys = objectKeys(Writable.prototype); -for (var v = 0; v < keys.length; v++) { - var method = keys[v]; - if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; -} - -function Duplex(options) { - if (!(this instanceof Duplex)) return new Duplex(options); - - Readable.call(this, options); - Writable.call(this, options); - - if (options && options.readable === false) this.readable = false; - - if (options && options.writable === false) this.writable = false; - - this.allowHalfOpen = true; - if (options && options.allowHalfOpen === false) this.allowHalfOpen = false; - - this.once('end', onend); -} - -// the no-half-open enforcer -function onend() { - // if we allow half-open state, or if the writable side ended, - // then we're ok. - if (this.allowHalfOpen || this._writableState.ended) return; - - // no more data can be written. - // But allow more writes to happen in this tick. - processNextTick(onEndNT, this); -} - -function onEndNT(self) { - self.end(); -} - -Object.defineProperty(Duplex.prototype, 'destroyed', { - get: function () { - if (this._readableState === undefined || this._writableState === undefined) { - return false; - } - return this._readableState.destroyed && this._writableState.destroyed; - }, - set: function (value) { - // we ignore the value if the stream - // has not been initialized yet - if (this._readableState === undefined || this._writableState === undefined) { - return; - } - - // backward compatibility, the user is explicitly - // managing destroyed - this._readableState.destroyed = value; - this._writableState.destroyed = value; - } -}); - -Duplex.prototype._destroy = function (err, cb) { - this.push(null); - this.end(); - - processNextTick(cb, err); -}; - -function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } -} -},{"./_stream_readable":87,"./_stream_writable":89,"core-util-is":8,"inherits":15,"process-nextick-args":36}],86:[function(_dereq_,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// a passthrough stream. -// basically just the most minimal sort of Transform stream. -// Every written chunk gets output as-is. - -'use strict'; - -module.exports = PassThrough; - -var Transform = _dereq_('./_stream_transform'); - -/**/ -var util = _dereq_('core-util-is'); -util.inherits = _dereq_('inherits'); -/**/ - -util.inherits(PassThrough, Transform); - -function PassThrough(options) { - if (!(this instanceof PassThrough)) return new PassThrough(options); - - Transform.call(this, options); -} - -PassThrough.prototype._transform = function (chunk, encoding, cb) { - cb(null, chunk); -}; -},{"./_stream_transform":88,"core-util-is":8,"inherits":15}],87:[function(_dereq_,module,exports){ -(function (process,global){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; - -/**/ - -var processNextTick = _dereq_('process-nextick-args'); -/**/ - -module.exports = Readable; - -/**/ -var isArray = _dereq_('isarray'); -/**/ - -/**/ -var Duplex; -/**/ - -Readable.ReadableState = ReadableState; - -/**/ -var EE = _dereq_('events').EventEmitter; - -var EElistenerCount = function (emitter, type) { - return emitter.listeners(type).length; -}; -/**/ - -/**/ -var Stream = _dereq_('./internal/streams/stream'); -/**/ - -// TODO(bmeurer): Change this back to const once hole checks are -// properly optimized away early in Ignition+TurboFan. -/**/ -var Buffer = _dereq_('safe-buffer').Buffer; -var OurUint8Array = global.Uint8Array || function () {}; -function _uint8ArrayToBuffer(chunk) { - return Buffer.from(chunk); -} -function _isUint8Array(obj) { - return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; -} -/**/ - -/**/ -var util = _dereq_('core-util-is'); -util.inherits = _dereq_('inherits'); -/**/ - -/**/ -var debugUtil = _dereq_('util'); -var debug = void 0; -if (debugUtil && debugUtil.debuglog) { - debug = debugUtil.debuglog('stream'); -} else { - debug = function () {}; -} -/**/ - -var BufferList = _dereq_('./internal/streams/BufferList'); -var destroyImpl = _dereq_('./internal/streams/destroy'); -var StringDecoder; - -util.inherits(Readable, Stream); - -var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; - -function prependListener(emitter, event, fn) { - // Sadly this is not cacheable as some libraries bundle their own - // event emitter implementation with them. - if (typeof emitter.prependListener === 'function') { - return emitter.prependListener(event, fn); - } else { - // This is a hack to make sure that our error handler is attached before any - // userland ones. NEVER DO THIS. This is here only because this code needs - // to continue to work with older versions of Node.js that do not include - // the prependListener() method. The goal is to eventually remove this hack. - if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; - } -} - -function ReadableState(options, stream) { - Duplex = Duplex || _dereq_('./_stream_duplex'); - - options = options || {}; - - // object stream flag. Used to make read(n) ignore n and to - // make all the buffer merging and length checks go away - this.objectMode = !!options.objectMode; - - if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.readableObjectMode; - - // the point at which it stops calling _read() to fill the buffer - // Note: 0 is a valid value, means "don't call _read preemptively ever" - var hwm = options.highWaterMark; - var defaultHwm = this.objectMode ? 16 : 16 * 1024; - this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; - - // cast to ints. - this.highWaterMark = Math.floor(this.highWaterMark); - - // A linked list is used to store data chunks instead of an array because the - // linked list can remove elements from the beginning faster than - // array.shift() - this.buffer = new BufferList(); - this.length = 0; - this.pipes = null; - this.pipesCount = 0; - this.flowing = null; - this.ended = false; - this.endEmitted = false; - this.reading = false; - - // a flag to be able to tell if the event 'readable'/'data' is emitted - // immediately, or on a later tick. We set this to true at first, because - // any actions that shouldn't happen until "later" should generally also - // not happen before the first read call. - this.sync = true; - - // whenever we return null, then we set a flag to say - // that we're awaiting a 'readable' event emission. - this.needReadable = false; - this.emittedReadable = false; - this.readableListening = false; - this.resumeScheduled = false; - - // has it been destroyed - this.destroyed = false; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; - - // the number of writers that are awaiting a drain event in .pipe()s - this.awaitDrain = 0; - - // if true, a maybeReadMore has been scheduled - this.readingMore = false; - - this.decoder = null; - this.encoding = null; - if (options.encoding) { - if (!StringDecoder) StringDecoder = _dereq_('string_decoder/').StringDecoder; - this.decoder = new StringDecoder(options.encoding); - this.encoding = options.encoding; - } -} - -function Readable(options) { - Duplex = Duplex || _dereq_('./_stream_duplex'); - - if (!(this instanceof Readable)) return new Readable(options); - - this._readableState = new ReadableState(options, this); - - // legacy - this.readable = true; - - if (options) { - if (typeof options.read === 'function') this._read = options.read; - - if (typeof options.destroy === 'function') this._destroy = options.destroy; - } - - Stream.call(this); -} - -Object.defineProperty(Readable.prototype, 'destroyed', { - get: function () { - if (this._readableState === undefined) { - return false; + var childContext = null; + var listSubject = newSubject; + if (skip) { + // TODO: should subject be null? + childContext = this.push(context, context.subject); + // TODO: should the entObject be passed along? If not, then intermediary children will keep properties from being associated with incomplete triples. + // TODO: Verify: if the current baseURI has changed and the parentObject is the parent's base URI, then the baseURI should change + childContext.parentObject = removeHash(current.parentNode.baseURI) === context.parentObject ? removeHash(current.baseURI) : context.parentObject; + childContext.incomplete = context.incomplete; + childContext.language = language; + childContext.prefixes = prefixes; + childContext.vocabulary = vocabulary; + } else { + childContext = this.push(context, newSubject); + childContext.parentObject = currentObjectResource ? currentObjectResource : newSubject ? newSubject : context.subject; + childContext.prefixes = prefixes; + childContext.incomplete = incomplete; + if (currentObjectResource) { + // console.log("Generating new list mapping for "+currentObjectResource) + listSubject = currentObjectResource; + listMapping = {}; + listMappingDifferent = true; + } + childContext.listMapping = listMapping; + childContext.language = language; + childContext.vocabulary = vocabulary; + } + if (listMappingDifferent) { + // console.log("Pushing list parent "+current.localName) + queue.unshift({ parent: current, context: context, subject: listSubject, listMapping: listMapping }); + } + for (var child = current.lastChild; child; child = child.previousSibling) { + if (child.nodeType === Node.ELEMENT_NODE) { + // console.log("Pushing child "+child.localName) + child.baseURI = current.baseURI; + queue.unshift({ current: child, context: childContext }); + } + } + } + if (this.inHTMLMode) { + this.copyProperties(); + } + for (var _i15 = 0; _i15 < this.finishedHandlers.length; _i15++) { + this.finishedHandlers[_i15](node); + } } - return this._readableState.destroyed; - }, - set: function (value) { - // we ignore the value if the stream - // has not been initialized yet - if (!this._readableState) { - return; + }, { + key: 'push', + value: function push(parent, subject) { + return { + parent: parent, + subject: subject ? subject : parent ? parent.subject : null, + parentObject: null, + incomplete: [], + listMapping: parent ? parent.listMapping : {}, + language: parent ? parent.language : this.language, + prefixes: parent ? parent.prefixes : this.target.graph.prefixes, + terms: parent ? parent.terms : this.target.graph.terms, + vocabulary: parent ? parent.vocabulary : this.vocabulary + }; } - - // backward compatibility, the user is explicitly - // managing destroyed - this._readableState.destroyed = value; - } -}); - -Readable.prototype.destroy = destroyImpl.destroy; -Readable.prototype._undestroy = destroyImpl.undestroy; -Readable.prototype._destroy = function (err, cb) { - this.push(null); - cb(err); -}; - -// Manually shove something into the read() buffer. -// This returns true if the highWaterMark has not been hit yet, -// similar to how Writable.write() returns true if you should -// write() some more. -Readable.prototype.push = function (chunk, encoding) { - var state = this._readableState; - var skipChunkCheck; - - if (!state.objectMode) { - if (typeof chunk === 'string') { - encoding = encoding || state.defaultEncoding; - if (encoding !== state.encoding) { - chunk = Buffer.from(chunk, encoding); - encoding = ''; - } - skipChunkCheck = true; + }, { + key: 'resolveAndNormalize', + value: function resolveAndNormalize(base, uri) { + // console.log("Joining " + uri + " to " + base + " making " + Uri.join(uri, base)) + return Uri.join(uri, base); // @@ normalize? } - } else { - skipChunkCheck = true; - } - - return readableAddChunk(this, chunk, encoding, false, skipChunkCheck); -}; - -// Unshift should *always* be something directly out of read() -Readable.prototype.unshift = function (chunk) { - return readableAddChunk(this, chunk, null, true, false); -}; - -function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { - var state = stream._readableState; - if (chunk === null) { - state.reading = false; - onEofChunk(stream, state); - } else { - var er; - if (!skipChunkCheck) er = chunkInvalid(state, chunk); - if (er) { - stream.emit('error', er); - } else if (state.objectMode || chunk && chunk.length > 0) { - if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) { - chunk = _uint8ArrayToBuffer(chunk); - } - - if (addToFront) { - if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true); - } else if (state.ended) { - stream.emit('error', new Error('stream.push() after EOF')); - } else { - state.reading = false; - if (state.decoder && !encoding) { - chunk = state.decoder.write(chunk); - if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state); + }, { + key: 'setContext', + value: function setContext(node) { + // We only recognized XHTML+RDFa 1.1 if the version is set propertyly + if (node.localName === 'html' && node.getAttribute('version') === 'XHTML+RDFa 1.1') { + this.setXHTMLContext(); + } else if (node.localName === 'html' || node.namespaceURI === 'http://www.w3.org/1999/xhtml') { + if (typeof document !== 'undefined' && document.doctype) { + if (document.doctype.publicId === '-//W3C//DTD XHTML+RDFa 1.0//EN' && document.doctype.systemId === 'http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd') { + console.log('WARNING: RDF 1.0 is not supported. Defaulting to HTML5 mode.'); + this.setHTMLContext(); + } else if (document.doctype.publicId === '-//W3C//DTD XHTML+RDFa 1.1//EN' && document.doctype.systemId === 'http://www.w3.org/MarkUp/DTD/xhtml-rdfa-2.dtd') { + this.setXHTMLContext(); + } else { + this.setHTMLContext(); + } } else { - addChunk(stream, state, chunk, false); + this.setHTMLContext(); } + } else { + this.setXMLContext(); } - } else if (!addToFront) { - state.reading = false; } - } - - return needMoreData(state); -} - -function addChunk(stream, state, chunk, addToFront) { - if (state.flowing && state.length === 0 && !state.sync) { - stream.emit('data', chunk); - stream.read(0); - } else { - // update the buffer info. - state.length += state.objectMode ? 1 : chunk.length; - if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk); - - if (state.needReadable) emitReadable(stream); - } - maybeReadMore(stream, state); -} - -function chunkInvalid(state, chunk) { - var er; - if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); - } - return er; -} - -// if it's past the high water mark, we can push in some more. -// Also, if we have no data yet, we can stand some -// more bytes. This is to work around cases where hwm=0, -// such as the repl. Also, if the push() triggered a -// readable event, and the user called read(largeNumber) such that -// needReadable was set, then we ought to push more, so that another -// 'readable' event will be triggered. -function needMoreData(state) { - return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0); -} - -Readable.prototype.isPaused = function () { - return this._readableState.flowing === false; -}; - -// backwards compatibility. -Readable.prototype.setEncoding = function (enc) { - if (!StringDecoder) StringDecoder = _dereq_('string_decoder/').StringDecoder; - this._readableState.decoder = new StringDecoder(enc); - this._readableState.encoding = enc; - return this; -}; - -// Don't raise the hwm > 8MB -var MAX_HWM = 0x800000; -function computeNewHighWaterMark(n) { - if (n >= MAX_HWM) { - n = MAX_HWM; - } else { - // Get the next highest power of 2 to prevent increasing hwm excessively in - // tiny amounts - n--; - n |= n >>> 1; - n |= n >>> 2; - n |= n >>> 4; - n |= n >>> 8; - n |= n >>> 16; - n++; - } - return n; -} - -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function howMuchToRead(n, state) { - if (n <= 0 || state.length === 0 && state.ended) return 0; - if (state.objectMode) return 1; - if (n !== n) { - // Only flow one buffer at a time - if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length; - } - // If we're asking for more than the current hwm, then raise the hwm. - if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n); - if (n <= state.length) return n; - // Don't have enough - if (!state.ended) { - state.needReadable = true; - return 0; - } - return state.length; -} - -// you can override either this method, or the async _read(n) below. -Readable.prototype.read = function (n) { - debug('read', n); - n = parseInt(n, 10); - var state = this._readableState; - var nOrig = n; - - if (n !== 0) state.emittedReadable = false; - - // if we're doing read(0) to trigger a readable event, but we - // already have a bunch of data in the buffer, then just trigger - // the 'readable' event and move on. - if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) { - debug('read: emitReadable', state.length, state.ended); - if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this); - return null; - } - - n = howMuchToRead(n, state); - - // if we've ended, and we're now clear, then finish it up. - if (n === 0 && state.ended) { - if (state.length === 0) endReadable(this); - return null; - } - - // All the actual chunk generation logic needs to be - // *below* the call to _read. The reason is that in certain - // synthetic stream cases, such as passthrough streams, _read - // may be a completely synchronous operation which may change - // the state of the read buffer, providing enough data when - // before there was *not* enough. - // - // So, the steps are: - // 1. Figure out what the state of things will be after we do - // a read from the buffer. - // - // 2. If that resulting state will trigger a _read, then call _read. - // Note that this may be asynchronous, or synchronous. Yes, it is - // deeply ugly to write APIs this way, but that still doesn't mean - // that the Readable class should behave improperly, as streams are - // designed to be sync/async agnostic. - // Take note if the _read call is sync or async (ie, if the read call - // has returned yet), so that we know whether or not it's safe to emit - // 'readable' etc. - // - // 3. Actually pull the requested chunks out of the buffer and return. - - // if we need a readable event, then we need to do some reading. - var doRead = state.needReadable; - debug('need readable', doRead); - - // if we currently have less than the highWaterMark, then also read some - if (state.length === 0 || state.length - n < state.highWaterMark) { - doRead = true; - debug('length less than watermark', doRead); - } - - // however, if we've ended, then there's no point, and if we're already - // reading, then it's unnecessary. - if (state.ended || state.reading) { - doRead = false; - debug('reading or ended', doRead); - } else if (doRead) { - debug('do read'); - state.reading = true; - state.sync = true; - // if the length is currently zero, then we *need* a readable event. - if (state.length === 0) state.needReadable = true; - // call internal read method - this._read(state.highWaterMark); - state.sync = false; - // If _read pushed data synchronously, then `reading` will be false, - // and we need to re-evaluate how much data we can return to the user. - if (!state.reading) n = howMuchToRead(nOrig, state); - } - - var ret; - if (n > 0) ret = fromList(n, state);else ret = null; - - if (ret === null) { - state.needReadable = true; - n = 0; - } else { - state.length -= n; - } - - if (state.length === 0) { - // If we have nothing in the buffer, then we want to know - // as soon as we *do* get something into the buffer. - if (!state.ended) state.needReadable = true; - - // If we tried to read() past the EOF, then emit end on the next tick. - if (nOrig !== n && state.ended) endReadable(this); - } - - if (ret !== null) this.emit('data', ret); - - return ret; -}; - -function onEofChunk(stream, state) { - if (state.ended) return; - if (state.decoder) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) { - state.buffer.push(chunk); - state.length += state.objectMode ? 1 : chunk.length; + }, { + key: 'setHTMLContext', + value: function setHTMLContext() { + this.setInitialContext(); + this.langAttributes = [{ + namespaceURI: 'http://www.w3.org/XML/1998/namespace', + localName: 'lang' + }, { namespaceURI: null, localName: 'lang' }]; + this.inXHTMLMode = false; + this.inHTMLMode = true; } - } - state.ended = true; - - // emit 'readable' now to make sure it gets picked up. - emitReadable(stream); -} - -// Don't emit readable right away in sync mode, because this can trigger -// another read() call => stack overflow. This way, it might trigger -// a nextTick recursion warning, but that's not so bad. -function emitReadable(stream) { - var state = stream._readableState; - state.needReadable = false; - if (!state.emittedReadable) { - debug('emitReadable', state.flowing); - state.emittedReadable = true; - if (state.sync) processNextTick(emitReadable_, stream);else emitReadable_(stream); - } -} - -function emitReadable_(stream) { - debug('emit readable'); - stream.emit('readable'); - flow(stream); -} - -// at this point, the user has presumably seen the 'readable' event, -// and called read() to consume some data. that may have triggered -// in turn another _read(n) call, in which case reading = true if -// it's in progress. -// However, if we're not ended, or reading, and the length < hwm, -// then go ahead and try to read some more preemptively. -function maybeReadMore(stream, state) { - if (!state.readingMore) { - state.readingMore = true; - processNextTick(maybeReadMore_, stream, state); - } -} - -function maybeReadMore_(stream, state) { - var len = state.length; - while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) { - debug('maybeReadMore read 0'); - stream.read(0); - if (len === state.length) - // didn't get any data, stop spinning. - break;else len = state.length; - } - state.readingMore = false; -} - -// abstract method. to be overridden in specific implementation classes. -// call cb(er, data) where data is <= n in length. -// for virtual (non-string, non-buffer) streams, "length" is somewhat -// arbitrary, and perhaps not very meaningful. -Readable.prototype._read = function (n) { - this.emit('error', new Error('_read() is not implemented')); -}; - -Readable.prototype.pipe = function (dest, pipeOpts) { - var src = this; - var state = this._readableState; - - switch (state.pipesCount) { - case 0: - state.pipes = dest; - break; - case 1: - state.pipes = [state.pipes, dest]; - break; - default: - state.pipes.push(dest); - break; - } - state.pipesCount += 1; - debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); - - var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; - - var endFn = doEnd ? onend : unpipe; - if (state.endEmitted) processNextTick(endFn);else src.once('end', endFn); - - dest.on('unpipe', onunpipe); - function onunpipe(readable, unpipeInfo) { - debug('onunpipe'); - if (readable === src) { - if (unpipeInfo && unpipeInfo.hasUnpiped === false) { - unpipeInfo.hasUnpiped = true; - cleanup(); - } + }, { + key: 'setInitialContext', + value: function setInitialContext() { + this.vocabulary = null; + // By default, the prefixes are terms are loaded to the RDFa 1.1. standard within the graph constructor + this.langAttributes = [{ + namespaceURI: 'http://www.w3.org/XML/1998/namespace', + localName: 'lang' + }]; + } + }, { + key: 'setXHTMLContext', + value: function setXHTMLContext() { + this.setInitialContext(); + this.inXHTMLMode = true; + this.inHTMLMode = false; + this.langAttributes = [{ + namespaceURI: 'http://www.w3.org/XML/1998/namespace', + localName: 'lang' }, { namespaceURI: null, localName: 'lang' }]; + // From http://www.w3.org/2011/rdfa-context/xhtml-rdfa-1.1 + this.target.graph.terms['alternate'] = 'http://www.w3.org/1999/xhtml/vocab#alternate'; + this.target.graph.terms['appendix'] = 'http://www.w3.org/1999/xhtml/vocab#appendix'; + this.target.graph.terms['bookmark'] = 'http://www.w3.org/1999/xhtml/vocab#bookmark'; + this.target.graph.terms['cite'] = 'http://www.w3.org/1999/xhtml/vocab#cite'; + this.target.graph.terms['chapter'] = 'http://www.w3.org/1999/xhtml/vocab#chapter'; + this.target.graph.terms['contents'] = 'http://www.w3.org/1999/xhtml/vocab#contents'; + this.target.graph.terms['copyright'] = 'http://www.w3.org/1999/xhtml/vocab#copyright'; + this.target.graph.terms['first'] = 'http://www.w3.org/1999/xhtml/vocab#first'; + this.target.graph.terms['glossary'] = 'http://www.w3.org/1999/xhtml/vocab#glossary'; + this.target.graph.terms['help'] = 'http://www.w3.org/1999/xhtml/vocab#help'; + this.target.graph.terms['icon'] = 'http://www.w3.org/1999/xhtml/vocab#icon'; + this.target.graph.terms['index'] = 'http://www.w3.org/1999/xhtml/vocab#index'; + this.target.graph.terms['last'] = 'http://www.w3.org/1999/xhtml/vocab#last'; + this.target.graph.terms['license'] = 'http://www.w3.org/1999/xhtml/vocab#license'; + this.target.graph.terms['meta'] = 'http://www.w3.org/1999/xhtml/vocab#meta'; + this.target.graph.terms['next'] = 'http://www.w3.org/1999/xhtml/vocab#next'; + this.target.graph.terms['prev'] = 'http://www.w3.org/1999/xhtml/vocab#prev'; + this.target.graph.terms['previous'] = 'http://www.w3.org/1999/xhtml/vocab#previous'; + this.target.graph.terms['section'] = 'http://www.w3.org/1999/xhtml/vocab#section'; + this.target.graph.terms['stylesheet'] = 'http://www.w3.org/1999/xhtml/vocab#stylesheet'; + this.target.graph.terms['subsection'] = 'http://www.w3.org/1999/xhtml/vocab#subsection'; + this.target.graph.terms['start'] = 'http://www.w3.org/1999/xhtml/vocab#start'; + this.target.graph.terms['top'] = 'http://www.w3.org/1999/xhtml/vocab#top'; + this.target.graph.terms['up'] = 'http://www.w3.org/1999/xhtml/vocab#up'; + this.target.graph.terms['p3pv1'] = 'http://www.w3.org/1999/xhtml/vocab#p3pv1'; + // other + this.target.graph.terms['related'] = 'http://www.w3.org/1999/xhtml/vocab#related'; + this.target.graph.terms['role'] = 'http://www.w3.org/1999/xhtml/vocab#role'; + this.target.graph.terms['transformation'] = 'http://www.w3.org/1999/xhtml/vocab#transformation'; + } + }, { + key: 'setXMLContext', + value: function setXMLContext() { + this.setInitialContext(); + this.inXHTMLMode = false; + this.inHTMLMode = false; + } + }, { + key: 'tokenize', + value: function tokenize(str) { + return this.trim(str).split(/\s+/); } - } - - function onend() { - debug('onend'); - dest.end(); - } - - // when the dest drains, it reduces the awaitDrain counter - // on the source. This would be more elegant with a .once() - // handler in flow(), but adding and removing repeatedly is - // too slow. - var ondrain = pipeOnDrain(src); - dest.on('drain', ondrain); - - var cleanedUp = false; - function cleanup() { - debug('cleanup'); - // cleanup event handlers once the pipe is broken - dest.removeListener('close', onclose); - dest.removeListener('finish', onfinish); - dest.removeListener('drain', ondrain); - dest.removeListener('error', onerror); - dest.removeListener('unpipe', onunpipe); - src.removeListener('end', onend); - src.removeListener('end', unpipe); - src.removeListener('data', ondata); - - cleanedUp = true; - - // if the reader is waiting for a drain event from this - // specific writer, then it would cause it to never start - // flowing again. - // So, if this is awaiting a drain, then we just call it now. - // If we don't know, then assume that we are waiting for one. - if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain(); - } - - // If the user pushes more data while we're writing to dest then we'll end up - // in ondata again. However, we only want to increase awaitDrain once because - // dest will only emit one 'drain' event for the multiple writes. - // => Introduce a guard on increasing awaitDrain. - var increasedAwaitDrain = false; - src.on('data', ondata); - function ondata(chunk) { - debug('ondata'); - increasedAwaitDrain = false; - var ret = dest.write(chunk); - if (false === ret && !increasedAwaitDrain) { - // If the user unpiped during `dest.write()`, it is possible - // to get stuck in a permanently paused state if that write - // also returned false. - // => Check whether `dest` is still a piping destination. - if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) { - debug('false write response, pause', src._readableState.awaitDrain); - src._readableState.awaitDrain++; - increasedAwaitDrain = true; + }, { + key: 'toRDFNodeObject', + value: function toRDFNodeObject(x) { + if (typeof x === 'undefined') return undefined; + if (typeof x === 'string') { + if (x.substring(0, 2) === '_:') { + if (typeof this.blankNodes[x.substring(2)] === 'undefined') { + this.blankNodes[x.substring(2)] = new BlankNode(x.substring(2)); + } + return this.blankNodes[x.substring(2)]; + } + return rdf.namedNode(x); + } + switch (x.type) { + case RDFaProcessor.objectURI: + if (x.value.substring(0, 2) === '_:') { + if (typeof this.blankNodes[x.value.substring(2)] === 'undefined') { + this.blankNodes[x.value.substring(2)] = new BlankNode(x.value.substring(2)); + } + return this.blankNodes[x.value.substring(2)]; + } + return rdf.namedNode(x.value); + case RDFaProcessor.PlainLiteralURI: + return new Literal(x.value, x.language || ''); + case RDFaProcessor.XMLLiteralURI: + case RDFaProcessor.HTMLLiteralURI: + var string = ''; + Object.keys(x.value).forEach(function (i) { + string += Util.domToString(x.value[i], this.htmlOptions); + }); + return new Literal(string, '', new NamedNode(x.type)); + default: + return new Literal(x.value, '', new NamedNode(x.type)); } - src.pause(); } - } - - // if the dest has an error, then stop piping into it. - // however, don't suppress the throwing behavior for this. - function onerror(er) { - debug('onerror', er); - unpipe(); - dest.removeListener('error', onerror); - if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er); - } - - // Make sure our error handler is attached before userland ones. - prependListener(dest, 'error', onerror); - - // Both close and finish should trigger unpipe, but only once. - function onclose() { - dest.removeListener('finish', onfinish); - unpipe(); - } - dest.once('close', onclose); - function onfinish() { - debug('onfinish'); - dest.removeListener('close', onclose); - unpipe(); - } - dest.once('finish', onfinish); - - function unpipe() { - debug('unpipe'); - src.unpipe(dest); - } - - // tell the dest that it's being piped to - dest.emit('pipe', src); - - // start the flow if it hasn't been started already. - if (!state.flowing) { - debug('pipe resume'); - src.resume(); - } - - return dest; -}; - -function pipeOnDrain(src) { - return function () { - var state = src._readableState; - debug('pipeOnDrain', state.awaitDrain); - if (state.awaitDrain) state.awaitDrain--; - if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) { - state.flowing = true; - flow(src); + }, { + key: 'trim', + value: function trim(str) { + return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); } - }; -} - -Readable.prototype.unpipe = function (dest) { - var state = this._readableState; - var unpipeInfo = { hasUnpiped: false }; - - // if we're not piping anywhere, then do nothing. - if (state.pipesCount === 0) return this; - - // just one destination. most common case. - if (state.pipesCount === 1) { - // passed in one, but it's not the right one. - if (dest && dest !== state.pipes) return this; - - if (!dest) dest = state.pipes; - - // got a match. - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - if (dest) dest.emit('unpipe', this, unpipeInfo); - return this; - } - - // slow case. multiple pipe destinations. - - if (!dest) { - // remove all. - var dests = state.pipes; - var len = state.pipesCount; - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - - for (var i = 0; i < len; i++) { - dests[i].emit('unpipe', this, unpipeInfo); - }return this; - } - - // try to find the right one. - var index = indexOf(state.pipes, dest); - if (index === -1) return this; - - state.pipes.splice(index, 1); - state.pipesCount -= 1; - if (state.pipesCount === 1) state.pipes = state.pipes[0]; - - dest.emit('unpipe', this, unpipeInfo); - - return this; -}; - -// set up data events if they are asked for -// Ensure readable listeners eventually get something -Readable.prototype.on = function (ev, fn) { - var res = Stream.prototype.on.call(this, ev, fn); - - if (ev === 'data') { - // Start flowing on next tick if stream isn't explicitly paused - if (this._readableState.flowing !== false) this.resume(); - } else if (ev === 'readable') { - var state = this._readableState; - if (!state.endEmitted && !state.readableListening) { - state.readableListening = state.needReadable = true; - state.emittedReadable = false; - if (!state.reading) { - processNextTick(nReadingNextTick, this); - } else if (state.length) { - emitReadable(this); - } + }], [{ + key: 'parseRDFaDOM', + value: function parseRDFaDOM(dom, kb, base) { + var p = new RDFaProcessor(kb, { 'base': base }); + dom.baseURI = base; + p.process(dom); } - } - - return res; -}; -Readable.prototype.addListener = Readable.prototype.on; + }]); -function nReadingNextTick(self) { - debug('readable nexttick read 0'); - self.read(0); -} + return RDFaProcessor; +}(); -// pause() and resume() are remnants of the legacy readable stream API -// If the user uses them, then switch into old mode. -Readable.prototype.resume = function () { - var state = this._readableState; - if (!state.flowing) { - debug('resume'); - state.flowing = true; - resume(this, state); - } - return this; -}; +RDFaProcessor.XMLLiteralURI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'; +RDFaProcessor.HTMLLiteralURI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#HTML'; +RDFaProcessor.PlainLiteralURI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#PlainLiteral'; +RDFaProcessor.objectURI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#object'; +RDFaProcessor.typeURI = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'; +RDFaProcessor.nameChar = '[-A-Z_a-z\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u10000-\uEFFFF.0-9\xB7\u0300-\u036F\u203F-\u2040]'; +RDFaProcessor.nameStartChar = '[A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\u0100-\u0131\u0134-\u013E\u0141-\u0148\u014A-\u017E\u0180-\u01C3\u01CD-\u01F0\u01F4-\u01F5\u01FA-\u0217\u0250-\u02A8\u02BB-\u02C1\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03D6\u03DA\u03DC\u03DE\u03E0\u03E2-\u03F3\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E-\u0481\u0490-\u04C4\u04C7-\u04C8\u04CB-\u04CC\u04D0-\u04EB\u04EE-\u04F5\u04F8-\u04F9\u0531-\u0556\u0559\u0561-\u0586\u05D0-\u05EA\u05F0-\u05F2\u0621-\u063A\u0641-\u064A\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D3\u06D5\u06E5-\u06E6\u0905-\u0939\u093D\u0958-\u0961\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8B\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AE0\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B36-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60-\u0D61\u0E01-\u0E2E\u0E30\u0E32-\u0E33\u0E40-\u0E45\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EAE\u0EB0\u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0F40-\u0F47\u0F49-\u0F69\u10A0-\u10C5\u10D0-\u10F6\u1100\u1102-\u1103\u1105-\u1107\u1109\u110B-\u110C\u110E-\u1112\u113C\u113E\u1140\u114C\u114E\u1150\u1154-\u1155\u1159\u115F-\u1161\u1163\u1165\u1167\u1169\u116D-\u116E\u1172-\u1173\u1175\u119E\u11A8\u11AB\u11AE-\u11AF\u11B7-\u11B8\u11BA\u11BC-\u11C2\u11EB\u11F0\u11F9\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A-\u212B\u212E\u2180-\u2182\u3041-\u3094\u30A1-\u30FA\u3105-\u312C\uAC00-\uD7A3\u4E00-\u9FA5\u3007\u3021-\u3029_]'; +RDFaProcessor.NCNAME = new RegExp('^' + RDFaProcessor.nameStartChar + RDFaProcessor.nameChar + '*$'); -function resume(stream, state) { - if (!state.resumeScheduled) { - state.resumeScheduled = true; - processNextTick(resume_, stream, state); - } +/* +RDFaProcessor.prototype.resolveAndNormalize = function(base,href) { + var u = base.resolve(href) + var parsed = this.parseURI(u) + parsed.normalize() + return parsed.spec } +*/ -function resume_(stream, state) { - if (!state.reading) { - debug('resume read 0'); - stream.read(0); - } - - state.resumeScheduled = false; - state.awaitDrain = 0; - stream.emit('resume'); - flow(stream); - if (state.flowing && !state.reading) stream.read(0); -} +RDFaProcessor.dateTimeTypes = [{ pattern: /-?P(?:[0-9]+Y)?(?:[0-9]+M)?(?:[0-9]+D)?(?:T(?:[0-9]+H)?(?:[0-9]+M)?(?:[0-9]+(?:\.[0-9]+)?S)?)?/, + type: 'http://www.w3.org/2001/XMLSchema#duration' }, { pattern: /-?(?:[1-9][0-9][0-9][0-9]|0[1-9][0-9][0-9]|00[1-9][0-9]|000[1-9])-[0-9][0-9]-[0-9][0-9]T(?:[0-1][0-9]|2[0-4]):[0-5][0-9]:[0-5][0-9](?:\.[0-9]+)?(?:Z|[+\-][0-9][0-9]:[0-9][0-9])?/, + type: 'http://www.w3.org/2001/XMLSchema#dateTime' }, { pattern: /-?(?:[1-9][0-9][0-9][0-9]|0[1-9][0-9][0-9]|00[1-9][0-9]|000[1-9])-[0-9][0-9]-[0-9][0-9](?:Z|[+\-][0-9][0-9]:[0-9][0-9])?/, + type: 'http://www.w3.org/2001/XMLSchema#date' }, { pattern: /(?:[0-1][0-9]|2[0-4]):[0-5][0-9]:[0-5][0-9](?:\.[0-9]+)?(?:Z|[+\-][0-9][0-9]:[0-9][0-9])?/, + type: 'http://www.w3.org/2001/XMLSchema#time' }, { pattern: /-?(?:[1-9][0-9][0-9][0-9]|0[1-9][0-9][0-9]|00[1-9][0-9]|000[1-9])-[0-9][0-9]/, + type: 'http://www.w3.org/2001/XMLSchema#gYearMonth' }, { pattern: /-?[1-9][0-9][0-9][0-9]|0[1-9][0-9][0-9]|00[1-9][0-9]|000[1-9]/, + type: 'http://www.w3.org/2001/XMLSchema#gYear' }]; -Readable.prototype.pause = function () { - debug('call pause flowing=%j', this._readableState.flowing); - if (false !== this._readableState.flowing) { - debug('pause'); - this._readableState.flowing = false; - this.emit('pause'); - } - return this; -}; +module.exports = RDFaProcessor; +},{"./blank-node":239,"./data-factory":243,"./literal":251,"./named-node":254,"./uri":269,"./util":270}],262:[function(_dereq_,module,exports){ +'use strict'; -function flow(stream) { - var state = stream._readableState; - debug('flow', state.flowing); - while (state.flowing && stream.read() !== null) {} -} +/** + * @fileoverview + * RDF/XML PARSER + * + * Version 0.1 + * Parser believed to be in full positive RDF/XML parsing compliance + * with the possible exception of handling deprecated RDF attributes + * appropriately. Parser is believed to comply fully with other W3C + * and industry standards where appropriate (DOM, ECMAScript, &c.) + * + * Author: David Sheets + * + * W3C® SOFTWARE NOTICE AND LICENSE + * http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231 + * This work (and included software, documentation such as READMEs, or + * other related items) is being provided by the copyright holders under + * the following license. By obtaining, using and/or copying this work, + * you (the licensee) agree that you have read, understood, and will + * comply with the following terms and conditions. + * + * Permission to copy, modify, and distribute this software and its + * documentation, with or without modification, for any purpose and + * without fee or royalty is hereby granted, provided that you include + * the following on ALL copies of the software and documentation or + * portions thereof, including modifications: + * + * 1. The full text of this NOTICE in a location viewable to users of + * the redistributed or derivative work. + * 2. Any pre-existing intellectual property disclaimers, notices, or terms and + * conditions. If none exist, the W3C Software Short Notice should be + * included (hypertext is preferred, text is permitted) within the body + * of any redistributed or derivative code. + * 3. Notice of any changes or modifications to the files, including the + * date changes were made. (We recommend you provide URIs to the location + * from which the code is derived.) + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT + * HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS + * FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR + * DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, + * TRADEMARKS OR OTHER RIGHTS. + * + * COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL + * OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR + * DOCUMENTATION. + * + * The name and trademarks of copyright holders may NOT be used in + * advertising or publicity pertaining to the software without specific, + * written prior permission. Title to copyright in this software and any + * associated documentation will at all times remain with copyright + * holders. + */ +/** + * @class Class defining an RDFParser resource object tied to an RDFStore + * + * @author David Sheets + * @version 0.1 + * + * @constructor + * @param {RDFStore} store An RDFStore object + */ +var uriUtil = _dereq_('./uri'); -// wrap an old-style stream as the async data source. -// This is *not* part of the readable stream interface. -// It is an ugly unfortunate mess of history. -Readable.prototype.wrap = function (stream) { - var state = this._readableState; - var paused = false; +var RDFParser = function RDFParser(store) { + var RDFParser = {}; - var self = this; - stream.on('end', function () { - debug('wrapped end'); - if (state.decoder && !state.ended) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) self.push(chunk); - } + /** Standard namespaces that we know how to handle @final + * @member RDFParser + */ + RDFParser.ns = { 'RDF': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'RDFS': 'http://www.w3.org/2000/01/rdf-schema#' }; - self.push(null); - }); + /** DOM Level 2 node type magic numbers @final + * @member RDFParser + */ + RDFParser.nodeType = { 'ELEMENT': 1, 'ATTRIBUTE': 2, 'TEXT': 3, + 'CDATA_SECTION': 4, 'ENTITY_REFERENCE': 5, + 'ENTITY': 6, 'PROCESSING_INSTRUCTION': 7, + 'COMMENT': 8, 'DOCUMENT': 9, 'DOCUMENT_TYPE': 10, + 'DOCUMENT_FRAGMENT': 11, 'NOTATION': 12 }; - stream.on('data', function (chunk) { - debug('wrapped data'); - if (state.decoder) chunk = state.decoder.write(chunk); + /** + * Frame class for namespace and base URI lookups + * Base lookups will always resolve because the parser knows + * the default base. + * + * @private + */ - // don't skip over falsy values in objectMode - if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return; + this.frameFactory = function (parser, parent, element) { + return { 'NODE': 1, 'ARC': 2, 'parent': parent, 'parser': parser, 'store': parser.store, 'element': element, + 'lastChild': 0, 'base': null, 'lang': null, 'node': null, 'nodeType': null, 'listIndex': 1, 'rdfid': null, 'datatype': null, 'collection': false, /** Terminate the frame and notify the store that we're done */ + 'terminateFrame': function terminateFrame() { + if (this.collection) { + this.node.close(); + } + }, /** Add a symbol of a certain type to the this frame */'addSymbol': function addSymbol(type, uri) { + uri = uriUtil.join(uri, this.base); + this.node = this.store.sym(uri); - var ret = self.push(chunk); - if (!ret) { - paused = true; - stream.pause(); - } - }); + this.nodeType = type; + }, /** Load any constructed triples into the store */'loadTriple': function loadTriple() { + if (this.parent.parent.collection) { + this.parent.parent.node.append(this.node); + } else { + this.store.add(this.parent.parent.node, this.parent.node, this.node, this.parser.why); + } + if (this.parent.rdfid != null) { + // reify + var triple = this.store.sym(uriUtil.join('#' + this.parent.rdfid, this.base)); + this.store.add(triple, this.store.sym(RDFParser.ns.RDF + 'type'), this.store.sym(RDFParser.ns.RDF + 'Statement'), this.parser.why); + this.store.add(triple, this.store.sym(RDFParser.ns.RDF + 'subject'), this.parent.parent.node, this.parser.why); + this.store.add(triple, this.store.sym(RDFParser.ns.RDF + 'predicate'), this.parent.node, this.parser.why); - // proxy all the other methods. - // important when wrapping filters and duplexes. - for (var i in stream) { - if (this[i] === undefined && typeof stream[i] === 'function') { - this[i] = function (method) { - return function () { - return stream[method].apply(stream, arguments); - }; - }(i); - } - } + this.store.add(triple, this.store.sym(RDFParser.ns.RDF + 'object'), this.node, this.parser.why); + } + }, /** Check if it's OK to load a triple */'isTripleToLoad': function isTripleToLoad() { + return this.parent != null && this.parent.parent != null && this.nodeType === this.NODE && this.parent.nodeType === this.ARC && this.parent.parent.nodeType === this.NODE; + }, /** Add a symbolic node to this frame */'addNode': function addNode(uri) { + this.addSymbol(this.NODE, uri); + if (this.isTripleToLoad()) { + this.loadTriple(); + } + }, /** Add a collection node to this frame */'addCollection': function addCollection() { + this.nodeType = this.NODE; + this.node = this.store.collection(); + this.collection = true; + if (this.isTripleToLoad()) { + this.loadTriple(); + } + }, /** Add a collection arc to this frame */'addCollectionArc': function addCollectionArc() { + this.nodeType = this.ARC; + }, /** Add a bnode to this frame */'addBNode': function addBNode(id) { + if (id != null) { + if (this.parser.bnodes[id] != null) { + this.node = this.parser.bnodes[id]; + } else { + this.node = this.parser.bnodes[id] = this.store.bnode(); + } + } else { + this.node = this.store.bnode(); + } + this.nodeType = this.NODE; + if (this.isTripleToLoad()) { + this.loadTriple(); + } + }, /** Add an arc or property to this frame */'addArc': function addArc(uri) { + if (uri === RDFParser.ns.RDF + 'li') { + uri = RDFParser.ns.RDF + '_' + this.parent.listIndex; + this.parent.listIndex++; + } - // proxy certain important events. - for (var n = 0; n < kProxyEvents.length; n++) { - stream.on(kProxyEvents[n], self.emit.bind(self, kProxyEvents[n])); - } + this.addSymbol(this.ARC, uri); + }, /** Add a literal to this frame */'addLiteral': function addLiteral(value) { + if (this.parent.datatype) { + this.node = this.store.literal(value, '', this.store.sym(this.parent.datatype)); + } else { + this.node = this.store.literal(value, this.lang); + } + this.nodeType = this.NODE; + if (this.isTripleToLoad()) { + this.loadTriple(); + } + } + }; + }; - // when we try to consume some more bytes, simply unpause the - // underlying stream. - self._read = function (n) { - debug('wrapped _read', n); - if (paused) { - paused = false; - stream.resume(); + // from the OpenLayers source .. needed to get around IE problems. + this.getAttributeNodeNS = function (node, uri, name) { + var attributeNode = null; + if (node.getAttributeNodeNS) { + attributeNode = node.getAttributeNodeNS(uri, name); + } else { + var attributes = node.attributes; + var potentialNode, fullName; + for (var i = 0; i < attributes.length; ++i) { + potentialNode = attributes[i]; + if (potentialNode.namespaceURI === uri) { + fullName = potentialNode.prefix ? potentialNode.prefix + ':' + name : name; + if (fullName === potentialNode.nodeName) { + attributeNode = potentialNode; + break; + } + } + } } + return attributeNode; }; - return self; -}; - -// exposed for testing purposes only. -Readable._fromList = fromList; - -// Pluck off n bytes from an array of buffers. -// Length is the combined lengths of all the buffers in the list. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function fromList(n, state) { - // nothing buffered - if (state.length === 0) return null; - - var ret; - if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) { - // read it all, truncate the list - if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length); - state.buffer.clear(); - } else { - // read part of list - ret = fromListPartial(n, state.buffer, state.decoder); - } + /** Our triple store reference @private */ - return ret; -} + this.store = store; /** Our identified blank nodes @private */ + this.bnodes = {}; /** A context for context-aware stores @private */ + this.why = null; /** Reification flag */ + this.reify = false; -// Extracts only enough buffered data to satisfy the amount requested. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function fromListPartial(n, list, hasStrings) { - var ret; - if (n < list.head.data.length) { - // slice is the same for buffers and strings - ret = list.head.data.slice(0, n); - list.head.data = list.head.data.slice(n); - } else if (n === list.head.data.length) { - // first chunk is a perfect match - ret = list.shift(); - } else { - // result spans more than one buffer - ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list); - } - return ret; -} + /** + * Build our initial scope frame and parse the DOM into triples + * @param {DOMTree} document The DOM to parse + * @param {String} base The base URL to use + * @param {Object} why The context to which this resource belongs + */ -// Copies a specified amount of characters from the list of buffered data -// chunks. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function copyFromBufferString(n, list) { - var p = list.head; - var c = 1; - var ret = p.data; - n -= ret.length; - while (p = p.next) { - var str = p.data; - var nb = n > str.length ? str.length : n; - if (nb === str.length) ret += str;else ret += str.slice(0, n); - n -= nb; - if (n === 0) { - if (nb === str.length) { - ++c; - if (p.next) list.head = p.next;else list.head = list.tail = null; - } else { - list.head = p; - p.data = str.slice(nb); + this.parse = function (document, base, why) { + var children = document.childNodes; // clean up for the next run + this.cleanParser(); // figure out the root element + var root; + if (document.nodeType === RDFParser.nodeType.DOCUMENT) { + for (var c = 0; c < children.length; c++) { + if (children[c].nodeType === RDFParser.nodeType.ELEMENT) { + root = children[c]; + break; + } } - break; + } else if (document.nodeType === RDFParser.nodeType.ELEMENT) { + root = document; + } else { + throw new Error("RDFParser: can't find root in " + base + '. Halting. '); + // return false } - ++c; - } - list.length -= c; - return ret; -} + this.why = why; // our topmost frame + var f = this.frameFactory(this); + this.base = base; + f.base = base; + f.lang = null; // was '' but can't have langs like that 2015 (!) + this.parseDOM(this.buildFrame(f, root)); + return true; + }; -// Copies a specified amount of bytes from the list of buffered data chunks. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function copyFromBuffer(n, list) { - var ret = Buffer.allocUnsafe(n); - var p = list.head; - var c = 1; - p.data.copy(ret); - n -= p.data.length; - while (p = p.next) { - var buf = p.data; - var nb = n > buf.length ? buf.length : n; - buf.copy(ret, ret.length - n, 0, nb); - n -= nb; - if (n === 0) { - if (nb === buf.length) { - ++c; - if (p.next) list.head = p.next;else list.head = list.tail = null; - } else { - list.head = p; - p.data = buf.slice(nb); + this.parseDOM = function (frame) { + // a DOM utility function used in parsing + var rdfid; + var elementURI = function (el) { + var result = ''; + if (el.namespaceURI == null) { + throw new Error('RDF/XML syntax error: No namespace for ' + el.localName + ' in ' + this.base); } - break; - } - ++c; - } - list.length -= c; - return ret; -} - -function endReadable(stream) { - var state = stream._readableState; - - // If we get here before consuming all the bytes, then that is a - // bug in node. Should never happen. - if (state.length > 0) throw new Error('"endReadable()" called on non-empty stream'); + if (el.namespaceURI) { + result = result + el.namespaceURI; + } + if (el.localName) { + result = result + el.localName; + } else if (el.nodeName) { + if (el.nodeName.indexOf(':') >= 0) result = result + el.nodeName.split(':')[1];else result = result + el.nodeName; + } + return result; + }.bind(this); + var dig = true; // if we'll dig down in the tree on the next iter + while (frame.parent) { + var dom = frame.element; + var attrs = dom.attributes; + if (dom.nodeType === RDFParser.nodeType.TEXT || dom.nodeType === RDFParser.nodeType.CDATA_SECTION) { + // we have a literal + if (frame.parent.nodeType === frame.NODE) { + // must have had attributes, store as rdf:value + frame.addArc(RDFParser.ns.RDF + 'value'); + frame = this.buildFrame(frame); + } + frame.addLiteral(dom.nodeValue); + } else if (elementURI(dom) !== RDFParser.ns.RDF + 'RDF') { + // not root + if (frame.parent && frame.parent.collection) { + // we're a collection element + frame.addCollectionArc(); + frame = this.buildFrame(frame, frame.element); + frame.parent.element = null; + } + if (!frame.parent || !frame.parent.nodeType || frame.parent.nodeType === frame.ARC) { + // we need a node + var about = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'about'); + rdfid = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'ID'); + if (about && rdfid) { + throw new Error('RDFParser: ' + dom.nodeName + ' has both rdf:id and rdf:about.' + ' Halting. Only one of these' + ' properties may be specified on a' + ' node.'); + } + if (!about && rdfid) { + frame.addNode('#' + rdfid.nodeValue); + dom.removeAttributeNode(rdfid); + } else if (about == null && rdfid == null) { + var bnid = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'nodeID'); + if (bnid) { + frame.addBNode(bnid.nodeValue); + dom.removeAttributeNode(bnid); + } else { + frame.addBNode(); + } + } else { + frame.addNode(about.nodeValue); + dom.removeAttributeNode(about); + } + // Typed nodes + var rdftype = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'type'); + if (RDFParser.ns.RDF + 'Description' !== elementURI(dom)) { + rdftype = { 'nodeValue': elementURI(dom) }; + } + if (rdftype != null) { + this.store.add(frame.node, this.store.sym(RDFParser.ns.RDF + 'type'), this.store.sym(uriUtil.join(rdftype.nodeValue, frame.base)), this.why); + if (rdftype.nodeName) { + dom.removeAttributeNode(rdftype); + } + } + // Property Attributes + for (var x = attrs.length - 1; x >= 0; x--) { + this.store.add(frame.node, this.store.sym(elementURI(attrs[x])), this.store.literal(attrs[x].nodeValue, frame.lang), this.why); + } + } else { + // we should add an arc (or implicit bnode+arc) + frame.addArc(elementURI(dom)); // save the arc's rdf:ID if it has one + if (this.reify) { + rdfid = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'ID'); + if (rdfid) { + frame.rdfid = rdfid.nodeValue; + dom.removeAttributeNode(rdfid); + } + } + var parsetype = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'parseType'); + var datatype = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'datatype'); + if (datatype) { + frame.datatype = datatype.nodeValue; + dom.removeAttributeNode(datatype); + } + if (parsetype) { + var nv = parsetype.nodeValue; + if (nv === 'Literal') { + frame.datatype = RDFParser.ns.RDF + 'XMLLiteral'; // (this.buildFrame(frame)).addLiteral(dom) + // should work but doesn't + frame = this.buildFrame(frame); + frame.addLiteral(dom); + dig = false; + } else if (nv === 'Resource') { + frame = this.buildFrame(frame, frame.element); + frame.parent.element = null; + frame.addBNode(); + } else if (nv === 'Collection') { + frame = this.buildFrame(frame, frame.element); + frame.parent.element = null; + frame.addCollection(); + } + dom.removeAttributeNode(parsetype); + } + if (attrs.length !== 0) { + var resource = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'resource'); + var bnid2 = this.getAttributeNodeNS(dom, RDFParser.ns.RDF, 'nodeID'); + frame = this.buildFrame(frame); + if (resource) { + frame.addNode(resource.nodeValue); + dom.removeAttributeNode(resource); + } else { + if (bnid2) { + frame.addBNode(bnid2.nodeValue); + dom.removeAttributeNode(bnid2); + } else { + frame.addBNode(); + } + } + for (var x1 = attrs.length - 1; x1 >= 0; x1--) { + var f = this.buildFrame(frame); + f.addArc(elementURI(attrs[x1])); + if (elementURI(attrs[x1]) === RDFParser.ns.RDF + 'type') { + this.buildFrame(f).addNode(attrs[x1].nodeValue); + } else { + this.buildFrame(f).addLiteral(attrs[x1].nodeValue); + } + } + } else if (dom.childNodes.length === 0) { + this.buildFrame(frame).addLiteral(''); + } + } + } // rdf:RDF + // dig dug + dom = frame.element; + while (frame.parent) { + var pframe = frame; + while (dom == null) { + frame = frame.parent; + dom = frame.element; + } + var candidate = dom.childNodes && dom.childNodes[frame.lastChild]; + if (!candidate || !dig) { + frame.terminateFrame(); + if (!(frame = frame.parent)) { + break; + } // done + dom = frame.element; + dig = true; + } else if (candidate.nodeType !== RDFParser.nodeType.ELEMENT && candidate.nodeType !== RDFParser.nodeType.TEXT && candidate.nodeType !== RDFParser.nodeType.CDATA_SECTION || (candidate.nodeType === RDFParser.nodeType.TEXT || candidate.nodeType === RDFParser.nodeType.CDATA_SECTION) && dom.childNodes.length !== 1) { + frame.lastChild++; + } else { + // not a leaf + frame.lastChild++; + frame = this.buildFrame(pframe, dom.childNodes[frame.lastChild - 1]); + break; + } + } + } // while + }; - if (!state.endEmitted) { - state.ended = true; - processNextTick(endReadableNT, state, stream); - } -} + /** + * Cleans out state from a previous parse run + * @private + */ + this.cleanParser = function () { + this.bnodes = {}; + this.why = null; + }; -function endReadableNT(state, stream) { - // Check that we didn't get one last unshift. - if (!state.endEmitted && state.length === 0) { - state.endEmitted = true; - stream.readable = false; - stream.emit('end'); - } -} + /** + * Builds scope frame + * @private + */ + this.buildFrame = function (parent, element) { + var frame = this.frameFactory(this, parent, element); + if (parent) { + frame.base = parent.base; + frame.lang = parent.lang; + } + if (!element || element.nodeType === RDFParser.nodeType.TEXT || element.nodeType === RDFParser.nodeType.CDATA_SECTION) { + return frame; + } + var attrs = element.attributes; + var base = element.getAttributeNode('xml:base'); + if (base != null) { + frame.base = base.nodeValue; + element.removeAttribute('xml:base'); + } + var lang = element.getAttributeNode('xml:lang'); + if (lang != null) { + frame.lang = lang.nodeValue; + element.removeAttribute('xml:lang'); + } + // remove all extraneous xml and xmlns attributes + for (var x = attrs.length - 1; x >= 0; x--) { + if (attrs[x].nodeName.substr(0, 3) === 'xml') { + if (attrs[x].name.slice(0, 6) === 'xmlns:') { + var uri = attrs[x].nodeValue; // alert('base for namespac attr:'+this.base) + if (this.base) uri = uriUtil.join(uri, this.base); + this.store.setPrefixForURI(attrs[x].name.slice(6), uri); + } + // alert('rdfparser: xml atribute: '+attrs[x].name) //@@ + element.removeAttributeNode(attrs[x]); + } + } + return frame; + }; +}; -function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } -} +module.exports = RDFParser; +},{"./uri":269}],263:[function(_dereq_,module,exports){ +'use strict'; -function indexOf(xs, x) { - for (var i = 0, l = xs.length; i < l; i++) { - if (xs[i] === x) return i; - } - return -1; -} -}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +module.exports = serialize; -},{"./_stream_duplex":85,"./internal/streams/BufferList":90,"./internal/streams/destroy":91,"./internal/streams/stream":92,"_process":37,"core-util-is":8,"events":10,"inherits":15,"isarray":93,"process-nextick-args":36,"safe-buffer":99,"string_decoder/":94,"util":3}],88:[function(_dereq_,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. +var convert = _dereq_('./convert'); +var Serializer = _dereq_('./serializer'); -// a transform stream is a readable/writable stream where you do -// something with the data. Sometimes it's called a "filter", -// but that's not a great name for it, since that implies a thing where -// some bits pass through, and others are simply ignored. (That would -// be a valid example of a transform, of course.) -// -// While the output is causally related to the input, it's not a -// necessarily symmetric or synchronous transformation. For example, -// a zlib stream might take multiple plain-text writes(), and then -// emit a single compressed chunk some time in the future. -// -// Here's how this works: -// -// The Transform stream has all the aspects of the readable and writable -// stream classes. When you write(chunk), that calls _write(chunk,cb) -// internally, and returns false if there's a lot of pending writes -// buffered up. When you call read(), that calls _read(n) until -// there's enough pending readable data buffered up. -// -// In a transform stream, the written data is placed in a buffer. When -// _read(n) is called, it transforms the queued up data, calling the -// buffered _write cb's as it consumes chunks. If consuming a single -// written chunk would result in multiple output chunks, then the first -// outputted bit calls the readcb, and subsequent chunks just go into -// the read buffer, and will cause it to emit 'readable' if necessary. -// -// This way, back-pressure is actually determined by the reading side, -// since _read has to be called to start processing a new chunk. However, -// a pathological inflate type of transform can cause excessive buffering -// here. For example, imagine a stream where every byte of input is -// interpreted as an integer from 0-255, and then results in that many -// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in -// 1kb of data being output. In this case, you could write a very small -// amount of input, and end up with a very large amount of output. In -// such a pathological inflating mechanism, there'd be no way to tell -// the system to stop doing the transform. A single 4MB write could -// cause the system to run out of memory. -// -// However, even in such a pathological case, only a single written chunk -// would be consumed, and then the rest would wait (un-transformed) until -// the results of the previous transformed chunk were consumed. +/** + * Serialize to the appropriate format + * @@ Currently NQuads and JSON/LD are deal with extrelemently inefficiently + * through mutiple conversions. + */ +function serialize(target, kb, base, contentType, callback, options) { + base = base || target.uri; + options = options || {}; + contentType = contentType || 'text/turtle'; // text/n3 if complex? + var documentString = null; + try { + var sz = Serializer(kb); + if (options.flags) sz.setFlags(options.flags); + var newSts = kb.statementsMatching(undefined, undefined, undefined, target); + var n3String; + sz.suggestNamespaces(kb.namespaces); + sz.setBase(base); + switch (contentType) { + case 'application/rdf+xml': + documentString = sz.statementsToXML(newSts); + return executeCallback(null, documentString); + case 'text/n3': + case 'application/n3': + // Legacy + documentString = sz.statementsToN3(newSts); + return executeCallback(null, documentString); + case 'text/turtle': + case 'application/x-turtle': + // Legacy + sz.setFlags('si'); // Suppress = for sameAs and => for implies + documentString = sz.statementsToN3(newSts); + return executeCallback(null, documentString); + case 'application/n-triples': + sz.setFlags('deinprstux'); // Suppress nice parts of N3 to make ntriples + documentString = sz.statementsToNTriples(newSts); + return executeCallback(null, documentString); + case 'application/ld+json': + sz.setFlags('deinprstux'); // Use adapters to connect to incmpatible parser + n3String = sz.statementsToNTriples(newSts); + // n3String = sz.statementsToN3(newSts) + convert.convertToJson(n3String, callback); + break; + case 'application/n-quads': + case 'application/nquads': + // @@@ just outpout the quads? Does not work for collections + sz.setFlags('deinprstux q'); // Suppress nice parts of N3 to make ntriples + documentString = sz.statementsToNTriples(newSts); // q in flag means actually quads + return executeCallback(null, documentString); + // n3String = sz.statementsToN3(newSts) + // documentString = convert.convertToNQuads(n3String, callback) + break; + default: + throw new Error('Serialize: Content-type ' + contentType + ' not supported for data write.'); + } + } catch (err) { + if (callback) { + return callback(err); + } + throw err; // Don't hide problems from caller in sync mode + } + function executeCallback(err, result) { + if (callback) { + callback(err, result); + return; + } else { + return result; + } + } +} +},{"./convert":242,"./serializer":264}],264:[function(_dereq_,module,exports){ 'use strict'; -module.exports = Transform; +/* Serialization of RDF Graphs +** +** Tim Berners-Lee 2006 +** This is was http://dig.csail.mit.edu/2005/ajar/ajaw/js/rdf/serialize.js +** This is or was https://github.com/linkeddata/rdflib.js/blob/master/src/serializer.js +** Licence: MIT +*/ +var NamedNode = _dereq_('./named-node'); +var BlankNode = _dereq_('./blank-node'); +var Uri = _dereq_('./uri'); +var Util = _dereq_('./util'); +var XSD = _dereq_('./xsd'); -var Duplex = _dereq_('./_stream_duplex'); +var Serializer = function () { + var __Serializer = function __Serializer(store) { + this.flags = ''; + this.base = null; -/**/ -var util = _dereq_('core-util-is'); -util.inherits = _dereq_('inherits'); -/**/ + this.prefixes = []; // suggested prefixes + this.namespaces = []; // complementary indexes -util.inherits(Transform, Duplex); + this.suggestPrefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'); // XML code assumes this! + this.suggestPrefix('xml', 'reserved:reservedForFutureUse'); // XML reserves xml: in the spec. -function TransformState(stream) { - this.afterTransform = function (er, data) { - return afterTransform(stream, er, data); + this.namespacesUsed = []; // Count actually used and so needed in @prefixes + this.keywords = ['a']; // The only one we generate at the moment + this.prefixchars = 'abcdefghijklmnopqustuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + this.incoming = null; // Array not calculated yet + this.formulas = []; // remebering original formulae from hashes + this.store = store; }; - this.needTransform = false; - this.transforming = false; - this.writecb = null; - this.writechunk = null; - this.writeencoding = null; -} - -function afterTransform(stream, er, data) { - var ts = stream._transformState; - ts.transforming = false; - - var cb = ts.writecb; - - if (!cb) { - return stream.emit('error', new Error('write callback called multiple times')); - } + __Serializer.prototype.setBase = function (base) { + this.base = base;return this; + }; - ts.writechunk = null; - ts.writecb = null; + __Serializer.prototype.setFlags = function (flags) { + this.flags = flags || '';return this; + }; - if (data !== null && data !== undefined) stream.push(data); + __Serializer.prototype.toStr = function (x) { + var s = x.toNT(); + if (x.termType === 'Graph') { + this.formulas[s] = x; // remember as reverse does not work + } + return s; + }; - cb(er); + __Serializer.prototype.fromStr = function (s) { + if (s[0] === '{') { + var x = this.formulas[s]; + if (!x) console.log('No formula object for ' + s); + return x; + } + return this.store.fromNT(s); + }; + /* Accumulate Namespaces + ** + ** These are only hints. If two overlap, only one gets used + ** There is therefore no guarantee in general. + */ + __Serializer.prototype.suggestPrefix = function (prefix, uri) { + if (prefix.slice(0, 7) === 'default') return; // Try to weed these out + if (prefix.slice(0, 2) === 'ns') return; // From others inferior algos + if (!prefix || !uri) return; // empty strings not suitable + if (prefix in this.namespaces || uri in this.prefixes) return; // already used + this.prefixes[uri] = prefix; + this.namespaces[prefix] = uri; + }; - var rs = stream._readableState; - rs.reading = false; - if (rs.needReadable || rs.length < rs.highWaterMark) { - stream._read(rs.highWaterMark); - } -} + // Takes a namespace -> prefix map + __Serializer.prototype.suggestNamespaces = function (namespaces) { + for (var px in namespaces) { + this.suggestPrefix(px, namespaces[px]); + } + return this; + }; -function Transform(options) { - if (!(this instanceof Transform)) return new Transform(options); + __Serializer.prototype.checkIntegrity = function () { + var p, ns; + for (p in this.namespaces) { + if (this.prefixes[this.namespaces[p]] !== p) { + throw new Error('Serializer integity error 1: ' + p + ', ' + this.namespaces[p] + ', ' + this.prefixes[this.namespaces[p]] + '!'); + } + } + for (ns in this.prefixes) { + if (this.namespaces[this.prefixes[ns]] !== ns) { + throw new Error('Serializer integity error 2: ' + ns + ', ' + this.prefixs[ns] + ', ' + this.namespaces[this.prefixes[ns]] + '!'); + } + } + }; - Duplex.call(this, options); + // Make up an unused prefix for a random namespace + __Serializer.prototype.makeUpPrefix = function (uri) { + var p = uri; + function canUseMethod(pp) { + if (!__Serializer.prototype.validPrefix.test(pp)) return false; // bad format + if (pp === 'ns') return false; // boring + if (pp in this.namespaces) return false; // already used + this.prefixes[uri] = pp; + this.namespaces[pp] = uri; + return pp; + } + var canUse = canUseMethod.bind(this); - this._transformState = new TransformState(this); + if ('#/'.indexOf(p[p.length - 1]) >= 0) p = p.slice(0, -1); + var slash = p.lastIndexOf('/'); + if (slash >= 0) p = p.slice(slash + 1); + var i = 0; + while (i < p.length) { + if (this.prefixchars.indexOf(p[i])) { + i++; + } else { + break; + } + } + p = p.slice(0, i); - var stream = this; + if (p.length < 6 && canUse(p)) return p; // exact is best + if (canUse(p.slice(0, 3))) return p.slice(0, 3); + if (canUse(p.slice(0, 2))) return p.slice(0, 2); + if (canUse(p.slice(0, 4))) return p.slice(0, 4); + if (canUse(p.slice(0, 1))) return p.slice(0, 1); + if (canUse(p.slice(0, 5))) return p.slice(0, 5); + if (!__Serializer.prototype.validPrefix.test(p)) { + p = 'n'; // Otherwise the loop below may never termimnate + } + for (var j = 0;; j++) { + if (canUse(p.slice(0, 3) + j)) return p.slice(0, 3) + j; + } + }; - // start out asking for a readable event once data is transformed. - this._readableState.needReadable = true; + __Serializer.prototype.rootSubjects = function (sts) { + var incoming = {}; + var subjects = {}; + var allBnodes = {}; - // we have implemented the _read method, and done the other things - // that Readable wants before the first _read call, so unset the - // sync guard flag. - this._readableState.sync = false; + /* This scan is to find out which nodes will have to be the roots of trees + ** in the serialized form. This will be any symbols, and any bnodes + ** which hve more or less than one incoming arc, and any bnodes which have + ** one incoming arc but it is an uninterrupted loop of such nodes back to itself. + ** This should be kept linear time with repect to the number of statements. + ** Note it does not use any indexing of the store. + */ + for (var i = 0; i < sts.length; i++) { + var st = sts[i]; + var checkMentions = function checkMentions(x) { + if (!incoming.hasOwnProperty(x)) incoming[x] = []; + incoming[x].push(st.subject); // List of things which will cause this to be printed + }; + var st2 = [st.subject, st.predicate, st.object]; + st2.map(function (y) { + if (y.termType === 'BlankNode') { + allBnodes[y.toNT()] = true; + } else if (y.termType === 'Collection') { + y.elements.forEach(function (z) { + checkMentions(z); // bnodes in collections important + }); + } + }); + checkMentions(sts[i].object); + var ss = subjects[this.toStr(st.subject)]; // Statements with this as subject + if (!ss) ss = []; + ss.push(st); + subjects[this.toStr(st.subject)] = ss; // Make hash. @@ too slow for formula? + } - if (options) { - if (typeof options.transform === 'function') this._transform = options.transform; + var roots = []; + for (var xNT in subjects) { + if (!subjects.hasOwnProperty(xNT)) continue; + var y = this.fromStr(xNT); + if (y.termType !== 'BlankNode' || !incoming[y] || incoming[y].length !== 1) { + roots.push(y); + continue; + } + } + this.incoming = incoming; // Keep for serializing @@ Bug for nested formulas - if (typeof options.flush === 'function') this._flush = options.flush; - } + // Now do the scan using existing roots + var rootsHash = {}; + for (var k = 0; k < roots.length; k++) { + rootsHash[roots[k].toNT()] = true; + } + return { 'roots': roots, 'subjects': subjects, + 'rootsHash': rootsHash, 'incoming': incoming }; + }; - // When the writable side finishes, then flush out anything remaining. - this.once('prefinish', function () { - if (typeof this._flush === 'function') this._flush(function (er, data) { - done(stream, er, data); - });else done(stream); - }); -} + // ////////////////////////////////////////////////////// -Transform.prototype.push = function (chunk, encoding) { - this._transformState.needTransform = false; - return Duplex.prototype.push.call(this, chunk, encoding); -}; + __Serializer.prototype.toN3 = function (f) { + return this.statementsToN3(f.statements); + }; -// This is the part where you do stuff! -// override this function in implementation classes. -// 'chunk' is an input chunk. -// -// Call `push(newChunk)` to pass along transformed output -// to the readable side. You may call 'push' zero or more times. -// -// Call `cb(err)` when you are done with this chunk. If you pass -// an error, then that'll put the hurt on the whole operation. If you -// never call cb(), then you'll never get another chunk. -Transform.prototype._transform = function (chunk, encoding, cb) { - throw new Error('_transform() is not implemented'); -}; + __Serializer.prototype._notQNameChars = '\t\r\n !"#$%&\'()*.,+/;<=>?@[\\]^`{|}~'; + __Serializer.prototype._notNameChars = __Serializer.prototype._notQNameChars + ':'; -Transform.prototype._write = function (chunk, encoding, cb) { - var ts = this._transformState; - ts.writecb = cb; - ts.writechunk = chunk; - ts.writeencoding = encoding; - if (!ts.transforming) { - var rs = this._readableState; - if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark); - } -}; + __Serializer.prototype.explicitURI = function (uri) { + if (this.flags.indexOf('r') < 0 && this.base) { + uri = Uri.refTo(this.base, uri); + } else if (this.flags.indexOf('u') >= 0) { + // Unicode encoding NTriples style + uri = backslashUify(uri); + } else { + uri = hexify(uri); + } + return '<' + uri + '>'; + }; -// Doesn't matter what the args are here. -// _transform does all the work. -// That we got here means that the readable side wants more data. -Transform.prototype._read = function (n) { - var ts = this._transformState; + __Serializer.prototype.statementsToNTriples = function (sts) { + var sorted = sts.slice(); + sorted.sort(); + var str = ''; + var rdfns = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; + var self = this; + var kb = this.store; + var termToNT = function termToNT(x) { + if (x.termType !== 'Collection') { + return self.atomicTermToN3(x); + } + var list = x.elements; + var rest = kb.sym(rdfns + 'nill'); + for (var i = list.length - 1; i >= 0; i--) { + var bnode = new BlankNode(); + str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'first')) + ' ' + termToNT(list[i]) + '.\n'; + str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'rest')) + ' ' + termToNT(rest) + '.\n'; + rest = bnode; + } + return self.atomicTermToN3(rest); + }; + for (var i = 0; i < sorted.length; i++) { + var st = sorted[i]; + var s = ''; + s += termToNT(st.subject) + ' '; + s += termToNT(st.predicate) + ' '; + s += termToNT(st.object) + ' '; + if (this.flags.indexOf('q') >= 0) { + // Do quads not nrtiples + s += termToNT(st.why) + ' '; + } + s += '.\n'; + str += s; + } + return str; + }; - if (ts.writechunk !== null && ts.writecb && !ts.transforming) { - ts.transforming = true; - this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); - } else { - // mark that we need a transform, so that any data that comes in - // will get processed, now that we've asked for it. - ts.needTransform = true; - } -}; + __Serializer.prototype.statementsToN3 = function (sts) { + var indent = 4; + var width = 80; + var kb = this.store; + // A URI Map alows us to put the type statemnts at the top. + var uriMap = { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type': 'aaa:00' }; + var SPO = function SPO(x, y) { + // Do limited canonicalization of bnodes + return Util.heavyCompareSPO(x, y, kb, uriMap); + }; + sts.sort(SPO); -Transform.prototype._destroy = function (err, cb) { - var _this = this; + if (this.base && !this.defaultNamespace) { + this.defaultNamespace = this.base + '#'; + } - Duplex.prototype._destroy.call(this, err, function (err2) { - cb(err2); - _this.emit('close'); - }); -}; + var predMap = {}; + if (this.flags.indexOf('s') < 0) { + predMap['http://www.w3.org/2002/07/owl#sameAs'] = '='; + } + if (this.flags.indexOf('t') < 0) { + predMap['http://www.w3.org/1999/02/22-rdf-syntax-ns#type'] = 'a'; + } + if (this.flags.indexOf('i') < 0) { + predMap['http://www.w3.org/2000/10/swap/log#implies'] = '=>'; + } + // //////////////////////// Arrange the bits of text -function done(stream, er, data) { - if (er) return stream.emit('error', er); + var spaces = function spaces(n) { + var s = ''; + for (var i = 0; i < n; i++) { + s += ' '; + }return s; + }; - if (data !== null && data !== undefined) stream.push(data); + var treeToLine = function treeToLine(tree) { + var str = ''; + for (var i = 0; i < tree.length; i++) { + var branch = tree[i]; + var s2 = typeof branch === 'string' ? branch : treeToLine(branch); + // Note the space before the dot in case statement ends 123. which is in fact allowed but be conservative. + if (i !== 0) { + var ch = str.slice(-1) || ' '; + if (s2 === ',' || s2 === ';') { + // no gap + } else if (s2 === '.' && !'0123456789.'.includes(ch)) {// no gap except after number + // no gap + } else { + str += ' '; // separate from previous token + } + } + str += s2; + } + return str; + }; - // if there's nothing in the write buffer, then that means - // that nothing more will ever be provided - var ws = stream._writableState; - var ts = stream._transformState; + // Convert a nested tree of lists and strings to a string + var treeToString = function treeToString(tree, level) { + var str = ''; + var lastLength = 100000; + if (level === undefined) level = -1; + for (var i = 0; i < tree.length; i++) { + var branch = tree[i]; + if (typeof branch !== 'string') { + var substr = treeToString(branch, level + 1); + if (substr.length < 10 * (width - indent * level) && substr.indexOf('"""') < 0) { + // Don't mess up multiline strings + var line = treeToLine(branch); + if (line.length < width - indent * level) { + branch = line; // Note! treat as string below + substr = ''; + } + } + if (substr) lastLength = 10000; + str += substr; + } + if (typeof branch === 'string') { + if (branch.length === 1 && str.slice(-1) === '\n') { + if (',.;'.indexOf(branch) >= 0) { + str = str.slice(0, -1) + branch + '\n'; // slip punct'n on end + lastLength += 1; + continue; + } + } + if (lastLength < indent * level + 4 || // if new line not necessary + lastLength + branch.length + 1 < width && ';.'.indexOf(str[str.length - 2]) < 0) { + // or the string fits on last line + str = str.slice(0, -1) + ' ' + branch + '\n'; // then continue on this line + lastLength += branch.length + 1; + } else { + var _line = spaces(indent * level) + branch; + str += _line + '\n'; + lastLength = _line.length; + if (level < 0) { + str += '\n'; // extra blank line + lastLength = 100000; // don't touch + } + } + } + } + return str; + }; - if (ws.length) throw new Error('Calling transform done when ws.length != 0'); + // //////////////////////////////////////////// Structure for N3 + // Convert a set of statements into a nested tree of lists and strings + function statementListToTreeMethod(statements) { + var stats = this.rootSubjects(statements); + var roots = stats.roots; + var results = []; + for (var i = 0; i < roots.length; i++) { + var root = roots[i]; + results.push(subjectTree(root, stats)); + } + return results; + } + var statementListToTree = statementListToTreeMethod.bind(this); - if (ts.transforming) throw new Error('Calling transform done when still transforming'); + // The tree for a subject + function subjectTree(subject, stats) { + if (subject.termType === 'BlankNode' && !stats.incoming[subject]) { + return objectTree(subject, stats, true).concat(['.']); // Anonymous bnode subject + } + return [termToN3(subject, stats)].concat([propertyTree(subject, stats)]).concat(['.']); + } + // The property tree for a single subject or anonymous node + function propertyTreeMethod(subject, stats) { + var results = []; + var lastPred = null; + var sts = stats.subjects[this.toStr(subject)] || []; // relevant statements + if (typeof sts === 'undefined') { + throw new Error('Cant find statements for ' + subject); + } - return stream.push(null); -} -},{"./_stream_duplex":85,"core-util-is":8,"inherits":15}],89:[function(_dereq_,module,exports){ -(function (process,global){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. + var objects = []; + for (var i = 0; i < sts.length; i++) { + var st = sts[i]; + if (st.predicate.uri === lastPred) { + objects.push(','); + } else { + if (lastPred) { + results = results.concat([objects]).concat([';']); + objects = []; + } + results.push(predMap[st.predicate.uri] ? predMap[st.predicate.uri] : termToN3(st.predicate, stats)); + } + lastPred = st.predicate.uri; + objects.push(objectTree(st.object, stats)); + } + results = results.concat([objects]); + return results; + } + var propertyTree = propertyTreeMethod.bind(this); -// A bit simpler than readable streams. -// Implement an async ._write(chunk, encoding, cb), and it'll handle all -// the drain event emission and buffering. + function objectTreeMethod(obj, stats, force) { + if (obj.termType === 'BlankNode' && (force || stats.rootsHash[obj.toNT()] === undefined)) { + // if not a root + if (stats.subjects[this.toStr(obj)]) { + return ['[', propertyTree(obj, stats), ']']; + } else { + return '[]'; + } + } + return termToN3(obj, stats); + } + var objectTree = objectTreeMethod.bind(this); -'use strict'; + function termToN3Method(expr, stats) { + // + var i, res; + switch (expr.termType) { + case 'Graph': + res = ['{']; + res = res.concat(statementListToTree(expr.statements)); + return res.concat(['}']); -/**/ + case 'Collection': + res = ['(']; + for (i = 0; i < expr.elements.length; i++) { + res.push([objectTree(expr.elements[i], stats)]); + } + res.push(')'); + return res; -var processNextTick = _dereq_('process-nextick-args'); -/**/ + default: + return this.atomicTermToN3(expr); + } + } + __Serializer.prototype.termToN3 = termToN3; + var termToN3 = termToN3Method.bind(this); -module.exports = Writable; + function prefixDirectivesMethod() { + var str = ''; + if (this.defaultNamespace) { + str += '@prefix : ' + this.explicitURI(this.defaultNamespace) + '.\n'; + } + for (var ns in this.prefixes) { + if (!this.prefixes.hasOwnProperty(ns)) continue; + if (!this.namespacesUsed[ns]) continue; + str += '@prefix ' + this.prefixes[ns] + ': ' + this.explicitURI(ns) + '.\n'; + } + return str + '\n'; + } + var prefixDirectives = prefixDirectivesMethod.bind(this); + // Body of statementsToN3: + var tree = statementListToTree(sts); + return prefixDirectives() + treeToString(tree); + }; + // //////////////////////////////////////////// Atomic Terms -/* */ -function WriteReq(chunk, encoding, cb) { - this.chunk = chunk; - this.encoding = encoding; - this.callback = cb; - this.next = null; -} + // Deal with term level things and nesting with no bnode structure + __Serializer.prototype.atomicTermToN3 = function atomicTermToN3(expr, stats) { + switch (expr.termType) { + case 'BlankNode': + case 'Variable': + return expr.toNT(); + case 'Literal': + var val = expr.value.toString(); // should be a string already + if (expr.datatype && this.flags.indexOf('x') < 0) { + // Supress native numbers + switch (expr.datatype.uri) { -// It seems a linked list but it is not -// there will be only 2 of these for each stream -function CorkedRequest(state) { - var _this = this; + case 'http://www.w3.org/2001/XMLSchema#integer': + return val; - this.next = null; - this.entry = null; - this.finish = function () { - onCorkedFinish(_this, state); - }; -} -/* */ + case 'http://www.w3.org/2001/XMLSchema#decimal': + // In urtle must have dot + if (val.indexOf('.') < 0) val += '.0'; + return val; -/**/ -var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick; -/**/ + case 'http://www.w3.org/2001/XMLSchema#double': + // Must force use of 'e' + if (val.indexOf('.') < 0) val += '.0'; + if (val.indexOf('e') < 0) val += 'e0'; + return val; -/**/ -var Duplex; -/**/ + case 'http://www.w3.org/2001/XMLSchema#boolean': + return expr.value ? 'true' : 'false'; + } + } + var str = this.stringToN3(expr.value); + if (expr.language) { + str += '@' + expr.language; + } else if (!expr.datatype.equals(XSD.string)) { + str += '^^' + this.atomicTermToN3(expr.datatype, stats); + } + return str; + case 'NamedNode': + return this.symbolToN3(expr); + default: + throw new Error('Internal: atomicTermToN3 cannot handle ' + expr + ' of termType: ' + expr.termType); + } + }; -Writable.WritableState = WritableState; + // stringToN3: String escaping for N3 -/**/ -var util = _dereq_('core-util-is'); -util.inherits = _dereq_('inherits'); -/**/ + __Serializer.prototype.validPrefix = new RegExp(/^[a-zA-Z][a-zA-Z0-9]*$/); -/**/ -var internalUtil = { - deprecate: _dereq_('util-deprecate') -}; -/**/ + __Serializer.prototype.forbidden1 = new RegExp(/[\\"\b\f\r\v\t\n\u0080-\uffff]/gm); + __Serializer.prototype.forbidden3 = new RegExp(/[\\"\b\f\r\v\u0080-\uffff]/gm); + __Serializer.prototype.stringToN3 = function stringToN3(str, flags) { + if (!flags) flags = 'e'; + var res = ''; + var i, j, k; + var delim; + var forbidden; + if (str.length > 20 && // Long enough to make sense + str.slice(-1) !== '"' && // corner case' + flags.indexOf('n') < 0 && ( // Force single line + str.indexOf('\n') > 0 || str.indexOf('"') > 0)) { + delim = '"""'; + forbidden = __Serializer.prototype.forbidden3; + } else { + delim = '"'; + forbidden = __Serializer.prototype.forbidden1; + } + for (i = 0; i < str.length;) { + forbidden.lastIndex = 0; + var m = forbidden.exec(str.slice(i)); + if (m == null) break; + j = i + forbidden.lastIndex - 1; + res += str.slice(i, j); + var ch = str[j]; + if (ch === '"' && delim === '"""' && str.slice(j, j + 3) !== '"""') { + res += ch; + } else { + k = '\b\f\r\t\v\n\\"'.indexOf(ch); // No escaping of bell (7)? + if (k >= 0) { + res += '\\' + 'bfrtvn\\"'[k]; + } else { + if (flags.indexOf('e') >= 0) { + // Unicode escaping in strings not unix style + res += '\\u' + ('000' + ch.charCodeAt(0).toString(16).toLowerCase()).slice(-4); + } else { + // no 'e' flag + res += ch; + } + } + } + i = j + 1; + } + return delim + res + str.slice(i) + delim; + }; + // A single symbol, either in <> or namespace notation -/**/ -var Stream = _dereq_('./internal/streams/stream'); -/**/ + __Serializer.prototype.symbolToN3 = function symbolToN3(x) { + // c.f. symbolString() in notation3.py + var uri = x.uri; + var j = uri.indexOf('#'); + if (j < 0 && this.flags.indexOf('/') < 0) { + j = uri.lastIndexOf('/'); + } + if (j >= 0 && this.flags.indexOf('p') < 0 && ( + // Can split at namespace but only if http[s]: URI or file: or ws[s] (why not others?) + uri.indexOf('http') === 0 || uri.indexOf('ws') === 0 || uri.indexOf('file') === 0)) { + var canSplit = true; + for (var k = j + 1; k < uri.length; k++) { + if (__Serializer.prototype._notNameChars.indexOf(uri[k]) >= 0) { + canSplit = false; + break; + } + } + /* + if (uri.slice(0, j + 1) === this.base + '#') { // base-relative + if (canSplit) { + return ':' + uri.slice(j + 1) // assume deafult ns is local + } else { + return '<#' + uri.slice(j + 1) + '>' + } + } + */ + if (canSplit) { + var localid = uri.slice(j + 1); + var namesp = uri.slice(0, j + 1); + if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) { + // d -> suppress default + if (this.flags.indexOf('k') >= 0 && this.keyords.indexOf(localid) < 0) { + return localid; + } + return ':' + localid; + } + // this.checkIntegrity() // @@@ Remove when not testing + var prefix = this.prefixes[namesp]; + if (!prefix) prefix = this.makeUpPrefix(namesp); + if (prefix) { + this.namespacesUsed[namesp] = true; + return prefix + ':' + localid; + } + // Fall though if can't do qname + } + } + return this.explicitURI(uri); + }; + // String escaping utilities -/**/ -var Buffer = _dereq_('safe-buffer').Buffer; -var OurUint8Array = global.Uint8Array || function () {}; -function _uint8ArrayToBuffer(chunk) { - return Buffer.from(chunk); -} -function _isUint8Array(obj) { - return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; -} -/**/ + function hexify(str) { + // also used in parser + return encodeURI(str); + } -var destroyImpl = _dereq_('./internal/streams/destroy'); + function backslashUify(str) { + var res = ''; + var k; + for (var i = 0; i < str.length; i++) { + k = str.charCodeAt(i); + if (k > 65535) { + res += '\\U' + ('00000000' + k.toString(16)).slice(-8); // convert to upper? + } else if (k > 126) { + res += '\\u' + ('0000' + k.toString(16)).slice(-4); + } else { + res += str[i]; + } + } + return res; + } -util.inherits(Writable, Stream); + // /////////////////////////// Quad store serialization -function nop() {} + // @para. write - a function taking a single string to be output + // + __Serializer.prototype.writeStore = function (write) { + var kb = this.store; + var fetcher = kb.fetcher; + var session = fetcher && fetcher.appNode; -function WritableState(options, stream) { - Duplex = Duplex || _dereq_('./_stream_duplex'); + // The core data - options = options || {}; + var sources = this.store.index[3]; + for (var s in sources) { + // -> assume we can use -> as short for log:semantics + var source = kb.fromNT(s); + if (session && source.sameTerm(session)) continue; + write('\n' + this.atomicTermToN3(source) + ' ' + this.atomicTermToN3(kb.sym('http://www.w3.org/2000/10/swap/log#semantics')) + ' { ' + this.statementsToN3(kb.statementsMatching(undefined, undefined, undefined, source)) + ' }.\n'); + } - // object stream flag to indicate whether or not this stream - // contains buffers or objects. - this.objectMode = !!options.objectMode; + // The metadata from HTTP interactions: - if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode; + kb.statementsMatching(undefined, kb.sym('http://www.w3.org/2007/ont/link#requestedURI')).map(function (st) { + write('\n<' + st.object.value + '> log:metadata {\n'); + var sts = kb.statementsMatching(undefined, undefined, undefined, st.subject); + write(this.statementsToN3(this.statementsToN3(sts))); + write('}.\n'); + }); - // the point at which write() starts returning false - // Note: 0 is a valid value, means that we always return false if - // the entire buffer is not flushed immediately on write() - var hwm = options.highWaterMark; - var defaultHwm = this.objectMode ? 16 : 16 * 1024; - this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; + // Inferences we have made ourselves not attributable to anyone else - // cast to ints. - this.highWaterMark = Math.floor(this.highWaterMark); + var metaSources = []; + if (session) metaSources.push(session); + var metadata = []; + metaSources.map(function (source) { + metadata = metadata.concat(kb.statementsMatching(undefined, undefined, undefined, source)); + }); + write(this.statementsToN3(metadata)); + }; - // if _final has been called - this.finalCalled = false; + // ////////////////////////////////////////////// XML serialization - // drain event flag. - this.needDrain = false; - // at the start of calling end() - this.ending = false; - // when end() has been called, and returned - this.ended = false; - // when 'finish' is emitted - this.finished = false; + __Serializer.prototype.statementsToXML = function (sts) { + var indent = 4; + var width = 80; - // has it been destroyed - this.destroyed = false; + var namespaceCounts = []; // which have been used + namespaceCounts['http://www.w3.org/1999/02/22-rdf-syntax-ns#'] = true; - // should we decode strings into buffers before passing to _write? - // this is here so that some node-core streams can optimize string - // handling at a lower level. - var noDecode = options.decodeStrings === false; - this.decodeStrings = !noDecode; + var liPrefix = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#_'; // prefix for ordered list items - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; + // //////////////////////// Arrange the bits of XML text - // not an actual buffer we keep track of, but a measurement - // of how much we're waiting to get pushed to some underlying - // socket or file. - this.length = 0; + var spaces = function spaces(n) { + var s = ''; + for (var i = 0; i < n; i++) { + s += ' '; + }return s; + }; - // a flag to see when we're in the middle of a write. - this.writing = false; + var XMLtreeToLine = function XMLtreeToLine(tree) { + var str = ''; + for (var i = 0; i < tree.length; i++) { + var branch = tree[i]; + var s2 = typeof branch === 'string' ? branch : XMLtreeToLine(branch); + str += s2; + } + return str; + }; - // when true all writes will be buffered until .uncork() call - this.corked = 0; + // Convert a nested tree of lists and strings to a string + var XMLtreeToString = function XMLtreeToString(tree, level) { + var str = ''; + var line; + var lastLength = 100000; + if (!level) level = 0; + for (var i = 0; i < tree.length; i++) { + var branch = tree[i]; + if (typeof branch !== 'string') { + var substr = XMLtreeToString(branch, level + 1); + if (substr.length < 10 * (width - indent * level) && substr.indexOf('"""') < 0) { + // Don't mess up multiline strings + line = XMLtreeToLine(branch); + if (line.length < width - indent * level) { + branch = ' ' + line; // @@ Hack: treat as string below + substr = ''; + } + } + if (substr) lastLength = 10000; + str += substr; + } + if (typeof branch === 'string') { + if (lastLength < indent * level + 4) { + // continue + str = str.slice(0, -1) + ' ' + branch + '\n'; + lastLength += branch.length + 1; + } else { + line = spaces(indent * level) + branch; + str += line + '\n'; + lastLength = line.length; + } + } else {// not string + } + } + return str; + }; - // a flag to be able to tell if the onwrite cb is called immediately, - // or on a later tick. We set this to true at first, because any - // actions that shouldn't happen until "later" should generally also - // not happen before the first write call. - this.sync = true; + function statementListToXMLTreeMethod(statements) { + this.suggestPrefix('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'); + var stats = this.rootSubjects(statements); + var roots = stats.roots; + var results = []; + for (var i = 0; i < roots.length; i++) { + var root = roots[i]; + results.push(subjectXMLTree(root, stats)); + } + return results; + } + var statementListToXMLTree = statementListToXMLTreeMethod.bind(this); - // a flag to know if we're processing previously buffered items, which - // may call the _write() callback in the same tick, so that we don't - // end up in an overlapped onwrite situation. - this.bufferProcessing = false; + function escapeForXML(str) { + if (typeof str === 'undefined') return '@@@undefined@@@@'; + return str.replace(/[&<"]/g, function (m) { + switch (m[0]) { + case '&': + return '&'; + case '<': + return '<'; + case '"': + return '"'; // ' + } + }); + } - // the callback that's passed to _write(chunk,cb) - this.onwrite = function (er) { - onwrite(stream, er); - }; + function relURIMethod(term) { + return escapeForXML(this.base ? Util.uri.refTo(this.base, term.uri) : term.uri); + } + var relURI = relURIMethod.bind(this); - // the callback that the user supplies to write(chunk,encoding,cb) - this.writecb = null; + // The tree for a subject + function subjectXMLTreeMethod(subject, stats) { + var results = []; + var type, t, st, pred; + var sts = stats.subjects[this.toStr(subject)]; // relevant statements + if (typeof sts === 'undefined') { + // empty bnode + return propertyXMLTree(subject, stats); + } - // the amount that is being written when _write is called. - this.writelen = 0; + // Sort only on the predicate, leave the order at object + // level undisturbed. This leaves multilingual content in + // the order of entry (for partner literals), which helps + // readability. + // + // For the predicate sort, we attempt to split the uri + // as a hint to the sequence + sts.sort(function (a, b) { + var ap = a.predicate.uri; + var bp = b.predicate.uri; + if (ap.substring(0, liPrefix.length) === liPrefix || bp.substring(0, liPrefix.length) === liPrefix) { + // we're only interested in sorting list items + return ap.localeCompare(bp); + } - this.bufferedRequest = null; - this.lastBufferedRequest = null; + var as = ap.substring(liPrefix.length); + var bs = bp.substring(liPrefix.length); + var an = parseInt(as, 10); + var bn = parseInt(bs, 10); + if (isNaN(an) || isNaN(bn) || an !== as || bn !== bs) { + // we only care about integers + return ap.localeCompare(bp); + } - // number of pending user-supplied write callbacks - // this must be 0 before 'finish' can be emitted - this.pendingcb = 0; + return an - bn; + }); - // emit prefinish if the only thing we're waiting for is _write cbs - // This is relevant for synchronous Transform streams - this.prefinished = false; + for (var i = 0; i < sts.length; i++) { + st = sts[i]; + // look for a type + if (st.predicate.uri === 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' && !type && st.object.termType === 'symbol') { + type = st.object; + continue; // don't include it as a child element + } + + // see whether predicate can be replaced with "li" + pred = st.predicate; + if (pred.uri.substr(0, liPrefix.length) === liPrefix) { + var number = pred.uri.substr(liPrefix.length); + // make sure these are actually numeric list items + var intNumber = parseInt(number, 10); + if (number === intNumber.toString()) { + // was numeric; don't need to worry about ordering since we've already + // sorted the statements + pred = new NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#li'); + } + } - // True if the error was already emitted and should not be thrown again - this.errorEmitted = false; + t = qname(pred); + switch (st.object.termType) { + case 'BlankNode': + if (stats.incoming[st.object].length === 1) { + // there should always be something in the incoming array for a bnode + results = results.concat(['<' + t + ' rdf:parseType="Resource">', subjectXMLTree(st.object, stats), '']); + } else { + results = results.concat(['<' + t + ' rdf:nodeID="' + st.object.toNT().slice(2) + '"/>']); + } + break; + case 'NamedNode': + results = results.concat(['<' + t + ' rdf:resource="' + relURI(st.object) + '"/>']); + break; + case 'Literal': + results = results.concat(['<' + t + (st.object.datatype.equals(XSD.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.uri) + '"') + (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') + '>' + escapeForXML(st.object.value) + '']); + break; + case 'Collection': + results = results.concat(['<' + t + ' rdf:parseType="Collection">', collectionXMLTree(st.object, stats), '']); + break; + default: + throw new Error("Can't serialize object of type " + st.object.termType + ' into XML'); + } // switch + } - // count buffered requests - this.bufferedRequestCount = 0; + var tag = type ? qname(type) : 'rdf:Description'; - // allocate the first CorkedRequest, there is always - // one allocated and free to use, and we maintain at most two - this.corkedRequestsFree = new CorkedRequest(this); -} + var attrs = ''; + if (subject.termType === 'BlankNode') { + if (!stats.incoming[subject] || stats.incoming[subject].length !== 1) { + // not an anonymous bnode + attrs = ' rdf:nodeID="' + subject.toNT().slice(2) + '"'; + } + } else { + attrs = ' rdf:about="' + relURI(subject) + '"'; + } -WritableState.prototype.getBuffer = function getBuffer() { - var current = this.bufferedRequest; - var out = []; - while (current) { - out.push(current); - current = current.next; - } - return out; -}; + return ['<' + tag + attrs + '>'].concat([results]).concat(['']); + } -(function () { - try { - Object.defineProperty(WritableState.prototype, 'buffer', { - get: internalUtil.deprecate(function () { - return this.getBuffer(); - }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003') - }); - } catch (_) {} -})(); + var subjectXMLTree = subjectXMLTreeMethod.bind(this); -// Test _writableState for inheritance to account for Duplex streams, -// whose prototype chain only points to Readable. -var realHasInstance; -if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') { - realHasInstance = Function.prototype[Symbol.hasInstance]; - Object.defineProperty(Writable, Symbol.hasInstance, { - value: function (object) { - if (realHasInstance.call(this, object)) return true; + function collectionXMLTree(subject, stats) { + var res = []; + for (var i = 0; i < subject.elements.length; i++) { + res.push(subjectXMLTree(subject.elements[i], stats)); + } + return res; + } - return object && object._writableState instanceof WritableState; + // The property tree for a single subject or anonymos node + function propertyXMLTreeMethod(subject, stats) { + var results = []; + var sts = stats.subjects[this.toStr(subject)]; // relevant statements + if (!sts) return results; // No relevant statements + sts.sort(); + for (var i = 0; i < sts.length; i++) { + var st = sts[i]; + switch (st.object.termType) { + case 'BlankNode': + if (stats.rootsHash[st.object.toNT()]) { + // This bnode has been done as a root -- no content here @@ what bout first time + results = results.concat(['<' + qname(st.predicate) + ' rdf:nodeID="' + st.object.toNT().slice(2) + '">', '']); + } else { + results = results.concat(['<' + qname(st.predicate) + ' rdf:parseType="Resource">', propertyXMLTree(st.object, stats), '']); + } + break; + case 'NamedNode': + results = results.concat(['<' + qname(st.predicate) + ' rdf:resource="' + relURI(st.object) + '"/>']); + break; + case 'Literal': + results = results.concat(['<' + qname(st.predicate) + (st.object.datatype.equals(XSD.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.value) + '"') + (st.object.language ? ' xml:lang="' + st.object.language + '"' : '') + '>' + escapeForXML(st.object.value) + '']); + break; + case 'Collection': + results = results.concat(['<' + qname(st.predicate) + ' rdf:parseType="Collection">', collectionXMLTree(st.object, stats), '']); + break; + default: + throw new Error("Can't serialize object of type " + st.object.termType + ' into XML'); + } // switch + } + return results; } - }); -} else { - realHasInstance = function (object) { - return object instanceof this; - }; -} + var propertyXMLTree = propertyXMLTreeMethod.bind(this); -function Writable(options) { - Duplex = Duplex || _dereq_('./_stream_duplex'); + function qnameMethod(term) { + var uri = term.uri; - // Writable ctor is applied to Duplexes, too. - // `realHasInstance` is necessary because using plain `instanceof` - // would return false, as no `_writableState` property is attached. + var j = uri.indexOf('#'); + if (j < 0 && this.flags.indexOf('/') < 0) { + j = uri.lastIndexOf('/'); + } + if (j < 0) throw new Error('Cannot make qname out of <' + uri + '>'); - // Trying to use the custom `instanceof` for Writable here will also break the - // Node.js LazyTransform implementation, which has a non-trivial getter for - // `_writableState` that would lead to infinite recursion. - if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) { - return new Writable(options); - } + for (var k = j + 1; k < uri.length; k++) { + if (__Serializer.prototype._notNameChars.indexOf(uri[k]) >= 0) { + throw new Error('Invalid character "' + uri[k] + '" cannot be in XML qname for URI: ' + uri); + } + } + var localid = uri.slice(j + 1); + var namesp = uri.slice(0, j + 1); + if (this.defaultNamespace && this.defaultNamespace === namesp && this.flags.indexOf('d') < 0) { + // d -> suppress default + return localid; + } + var prefix = this.prefixes[namesp]; + if (!prefix) prefix = this.makeUpPrefix(namesp); + namespaceCounts[namesp] = true; + return prefix + ':' + localid; + } + var qname = qnameMethod.bind(this); - this._writableState = new WritableState(options, this); + // Body of toXML: - // legacy. - this.writable = true; + var tree = statementListToXMLTree(sts); + var str = '']; // @@ namespace declrations + return XMLtreeToString(tree2, -1); + }; // End @@ body - if (typeof options.writev === 'function') this._writev = options.writev; + var Serializer = function Serializer(store) { + return new __Serializer(store); + }; + return Serializer; +}(); - if (typeof options.destroy === 'function') this._destroy = options.destroy; +module.exports = Serializer; +},{"./blank-node":239,"./named-node":254,"./uri":269,"./util":270,"./xsd":272}],265:[function(_dereq_,module,exports){ +'use strict'; - if (typeof options.final === 'function') this._final = options.final; - } +// Converting between SPARQL queries and the $rdf query API +/* - Stream.call(this); +function SQuery () { + this.terms = [] + return this } -// Otherwise people can pipe Writable streams, which is just wrong. -Writable.prototype.pipe = function () { - this.emit('error', new Error('Cannot pipe, not readable')); -}; +STerm.prototype.toString = STerm.val +SQuery.prototype.add = function (str) {this.terms.push()}*/ -function writeAfterEnd(stream, cb) { - var er = new Error('write after end'); - // TODO: defer error events consistently everywhere, not just the cb - stream.emit('error', er); - processNextTick(cb, er); -} +var log = _dereq_('./log'); +var Query = _dereq_('./query').Query; +// const Fetcher = require('./fetcher') -// Checks that a user-supplied chunk is valid, especially for the particular -// mode the stream is in. Currently this means that `null` is never accepted -// and undefined/non-string values are only allowed in object mode. -function validChunk(stream, state, chunk, cb) { - var valid = true; - var er = false; +/** + * @SPARQL: SPARQL text that is converted to a query object which is returned. + * @testMode: testing flag. Prevents loading of sources. + */ +function SPARQLToQuery(SPARQL, testMode, kb) { + // AJAR_ClearTable() + var variableHash = []; + function makeVar(name) { + if (variableHash[name]) { + return variableHash[name]; + } + var newVar = kb.variable(name); + variableHash[name] = newVar; + return newVar; + } - if (chunk === null) { - er = new TypeError('May not write null values to stream'); - } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); + // term type functions + function isRealText(term) { + return typeof term === 'string' && term.match(/[^ \n\t]/); } - if (er) { - stream.emit('error', er); - processNextTick(cb, er); - valid = false; + function isVar(term) { + return typeof term === 'string' && term.match(/^[\?\$]/); } - return valid; -} - -Writable.prototype.write = function (chunk, encoding, cb) { - var state = this._writableState; - var ret = false; - var isBuf = _isUint8Array(chunk) && !state.objectMode; - - if (isBuf && !Buffer.isBuffer(chunk)) { - chunk = _uint8ArrayToBuffer(chunk); + function fixSymbolBrackets(term) { + if (typeof term === 'string') { + return term.replace(/^</, '<').replace(/>$/, '>'); + } else { + return term; + } } - - if (typeof encoding === 'function') { - cb = encoding; - encoding = null; + function isSymbol(term) { + return typeof term === 'string' && term.match(/^<[^>]*>$/); } - - if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; - - if (typeof cb !== 'function') cb = nop; - - if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { - state.pendingcb++; - ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); + function isBnode(term) { + return typeof term === 'string' && (term.match(/^_:/) || term.match(/^$/)); } - - return ret; -}; - -Writable.prototype.cork = function () { - var state = this._writableState; - - state.corked++; -}; - -Writable.prototype.uncork = function () { - var state = this._writableState; - - if (state.corked) { - state.corked--; - - if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); + function isPrefix(term) { + return typeof term === 'string' && term.match(/:$/); } -}; - -Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { - // node::ParseEncoding() requires lower case. - if (typeof encoding === 'string') encoding = encoding.toLowerCase(); - if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding); - this._writableState.defaultEncoding = encoding; - return this; -}; - -function decodeChunk(state, chunk, encoding) { - if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { - chunk = Buffer.from(chunk, encoding); + function isPrefixedSymbol(term) { + return typeof term === 'string' && term.match(/^:|^[^_][^:]*:/); } - return chunk; -} - -// if we're already writing something, then just put this -// in the queue, and wait our turn. Otherwise, call _write -// If we return false, then we need a drain event, so set that flag. -function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) { - if (!isBuf) { - var newChunk = decodeChunk(state, chunk, encoding); - if (chunk !== newChunk) { - isBuf = true; - encoding = 'buffer'; - chunk = newChunk; + function getPrefix(term) { + var a = term.split(':'); + return a[0]; + } + function getSuffix(term) { + var a = term.split(':'); + return a[1]; + } + function removeBrackets(term) { + if (isSymbol(term)) { + return term.slice(1, term.length - 1); + } else { + return term; } } - var len = state.objectMode ? 1 : chunk.length; - - state.length += len; - - var ret = state.length < state.highWaterMark; - // we must ensure that previous needDrain will not be reset to false. - if (!ret) state.needDrain = true; - - if (state.writing || state.corked) { - var last = state.lastBufferedRequest; - state.lastBufferedRequest = { - chunk: chunk, - encoding: encoding, - isBuf: isBuf, - callback: cb, - next: null - }; - if (last) { - last.next = state.lastBufferedRequest; + // takes a string and returns an array of strings and Literals in the place of literals + function parseLiterals(str) { + // var sin = (str.indexOf(/[ \n]\'/)==-1)?null:str.indexOf(/[ \n]\'/), doub = (str.indexOf(/[ \n]\"/)==-1)?null:str.indexOf(/[ \n]\"/) + var sin = str.indexOf("'") === -1 ? null : str.indexOf("'"); + var doub = str.indexOf('"') === -1 ? null : str.indexOf('"'); + // alert("S: "+sin+" D: "+doub) + if (!sin && !doub) { + var a = new Array(1); + a[0] = str; + return a; + } + var res = new Array(2); + var br; + var ind; + if (!sin || doub && doub < sin) { + br = '"'; + ind = doub; + } else if (!doub || sin && sin < doub) { + br = "'"; + ind = sin; } else { - state.bufferedRequest = state.lastBufferedRequest; + log.error('SQARQL QUERY OOPS!'); + return res; } - state.bufferedRequestCount += 1; - } else { - doWrite(stream, state, false, len, chunk, encoding, cb); + res[0] = str.slice(0, ind); + var end = str.slice(ind + 1).indexOf(br); + if (end === -1) { + log.error('SPARQL parsing error: no matching parentheses in literal ' + str); + return str; + } + // alert(str.slice(end + ind + 2).match(/^\^\^/)) + var end2; + if (str.slice(end + ind + 2).match(/^\^\^/)) { + end2 = str.slice(end + ind + 2).indexOf(' '); + // alert(end2) + res[1] = kb.literal(str.slice(ind + 1, ind + 1 + end), '', kb.sym(removeBrackets(str.slice(ind + 4 + end, ind + 2 + end + end2)))); + // alert(res[1].datatype.uri) + res = res.concat(parseLiterals(str.slice(end + ind + 3 + end2))); + } else if (str.slice(end + ind + 2).match(/^@/)) { + end2 = str.slice(end + ind + 2).indexOf(' '); + // alert(end2) + res[1] = kb.literal(str.slice(ind + 1, ind + 1 + end), str.slice(ind + 3 + end, ind + 2 + end + end2), null); + // alert(res[1].datatype.uri) + res = res.concat(parseLiterals(str.slice(end + ind + 2 + end2))); + } else { + res[1] = kb.literal(str.slice(ind + 1, ind + 1 + end), '', null); + log.info('Literal found: ' + res[1]); + res = res.concat(parseLiterals(str.slice(end + ind + 2))); // finds any other literals + } + return res; } - return ret; -} - -function doWrite(stream, state, writev, len, chunk, encoding, cb) { - state.writelen = len; - state.writecb = cb; - state.writing = true; - state.sync = true; - if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite); - state.sync = false; -} - -function onwriteError(stream, state, sync, er, cb) { - --state.pendingcb; - - if (sync) { - // defer the callback if we are being called synchronously - // to avoid piling up things on the stack - processNextTick(cb, er); - // this can emit finish, and it will always happen - // after error - processNextTick(finishMaybe, stream, state); - stream._writableState.errorEmitted = true; - stream.emit('error', er); - } else { - // the caller expect this to happen before if - // it is async - cb(er); - stream._writableState.errorEmitted = true; - stream.emit('error', er); - // this can emit finish, but finish must - // always follow error - finishMaybe(stream, state); + function spaceDelimit(str) { + str = str.replace(/\(/g, ' ( ').replace(/\)/g, ' ) ').replace(//g, '> ').replace(/{/g, ' { ').replace(/}/g, ' } ').replace(/[\t\n\r]/g, ' ').replace(/; /g, ' ; ').replace(/\. /g, ' . ').replace(/, /g, ' , '); + log.info('New str into spaceDelimit: \n' + str); + var res = []; + var br = str.split(' '); + for (var x in br) { + if (isRealText(br[x])) { + res = res.concat(br[x]); + } + } + return res; } -} - -function onwriteStateUpdate(state) { - state.writing = false; - state.writecb = null; - state.length -= state.writelen; - state.writelen = 0; -} - -function onwrite(stream, er) { - var state = stream._writableState; - var sync = state.sync; - var cb = state.writecb; - - onwriteStateUpdate(state); - - if (er) onwriteError(stream, state, sync, er, cb);else { - // Check if we're actually ready to finish, but don't emit yet - var finished = needFinish(state); - if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) { - clearBuffer(stream, state); + function replaceKeywords(input) { + var strarr = input; + for (var x = 0; x < strarr.length; x++) { + if (strarr[x] === 'a') { + strarr[x] = ''; + } + if (strarr[x] === 'is' && strarr[x + 2] === 'of') { + strarr.splice(x, 1); + strarr.splice(x + 1, 1); + var s = strarr[x - 1]; + strarr[x - 1] = strarr[x + 1]; + strarr[x + 1] = s; + } } + return strarr; + } - if (sync) { - /**/ - asyncWrite(afterWrite, stream, state, finished, cb); - /**/ - } else { - afterWrite(stream, state, finished, cb); + function toTerms(input) { + var res = []; + for (var x = 0; x < input.length; x++) { + if (typeof input[x] !== 'string') { + res[x] = input[x]; + continue; + } + input[x] = fixSymbolBrackets(input[x]); + if (isVar(input[x])) { + res[x] = makeVar(input[x].slice(1)); + } else if (isBnode(input[x])) { + log.info(input[x] + ' was identified as a bnode.'); + res[x] = kb.bnode(); + } else if (isSymbol(input[x])) { + log.info(input[x] + ' was identified as a symbol.'); + res[x] = kb.sym(removeBrackets(input[x])); + } else if (isPrefixedSymbol(input[x])) { + log.info(input[x] + ' was identified as a prefixed symbol'); + if (prefixes[getPrefix(input[x])]) { + res[x] = kb.sym(input[x] = prefixes[getPrefix(input[x])] + getSuffix(input[x])); + } else { + log.error('SPARQL error: ' + input[x] + ' with prefix ' + getPrefix(input[x]) + ' does not have a correct prefix entry.'); + res[x] = input[x]; + } + } else { + res[x] = input[x]; + } } + return res; } -} - -function afterWrite(stream, state, finished, cb) { - if (!finished) onwriteDrain(stream, state); - state.pendingcb--; - cb(); - finishMaybe(stream, state); -} -// Must force callback to be called on nextTick, so that we don't -// emit 'drain' before the write() consumer gets the 'false' return -// value, and has a chance to attach a 'drain' listener. -function onwriteDrain(stream, state) { - if (state.length === 0 && state.needDrain) { - state.needDrain = false; - stream.emit('drain'); + function tokenize(str) { + var token1 = parseLiterals(str); + var token2 = []; + for (var x in token1) { + if (typeof token1[x] === 'string') { + token2 = token2.concat(spaceDelimit(token1[x])); + } else { + token2 = token2.concat(token1[x]); + } + } + token2 = replaceKeywords(token2); + log.info('SPARQL Tokens: ' + token2); + return token2; } -} - -// if there's something in the buffer waiting, then process it -function clearBuffer(stream, state) { - state.bufferProcessing = true; - var entry = state.bufferedRequest; - - if (stream._writev && entry && entry.next) { - // Fast case, write everything using _writev() - var l = state.bufferedRequestCount; - var buffer = new Array(l); - var holder = state.corkedRequestsFree; - holder.entry = entry; - var count = 0; - var allBuffers = true; - while (entry) { - buffer[count] = entry; - if (!entry.isBuf) allBuffers = false; - entry = entry.next; - count += 1; + // CASE-INSENSITIVE + function arrayIndexOf(str, arr) { + for (var i = 0; i < arr.length; i++) { + if (typeof arr[i] !== 'string') { + continue; + } + if (arr[i].toLowerCase() === str.toLowerCase()) { + return i; + } } - buffer.allBuffers = allBuffers; - - doWrite(stream, state, true, state.length, buffer, '', holder.finish); + // log.warn("No instance of "+str+" in array "+arr) + return null; + } - // doWrite is almost always async, defer these to save a bit of time - // as the hot path ends with doWrite - state.pendingcb++; - state.lastBufferedRequest = null; - if (holder.next) { - state.corkedRequestsFree = holder.next; - holder.next = null; - } else { - state.corkedRequestsFree = new CorkedRequest(state); + // CASE-INSENSITIVE + function arrayIndicesOf(str, arr) { + var ind = []; + for (var i = 0; i < arr.length; i++) { + if (typeof arr[i] !== 'string') { + continue; + } + if (arr[i].toLowerCase() === str.toLowerCase()) { + ind.push(i); + } } - } else { - // Slow case, write chunks one-by-one - while (entry) { - var chunk = entry.chunk; - var encoding = entry.encoding; - var cb = entry.callback; - var len = state.objectMode ? 1 : chunk.length; + return ind; + } - doWrite(stream, state, false, len, chunk, encoding, cb); - entry = entry.next; - // if we didn't call the onwrite immediately, then - // it means that we need to wait until it does. - // also, that means that the chunk and cb are currently - // being processed, so move the buffer counter past them. - if (state.writing) { - break; + function setVars(input, query) { + log.info('SPARQL vars: ' + input); + for (var x in input) { + if (isVar(input[x])) { + log.info('Added ' + input[x] + ' to query variables from SPARQL'); + var v = makeVar(input[x].slice(1)); + query.vars.push(v); + v.label = input[x].slice(1); + } else { + log.warn('Incorrect SPARQL variable in SELECT: ' + input[x]); } } - - if (entry === null) state.lastBufferedRequest = null; } - state.bufferedRequestCount = 0; - state.bufferedRequest = entry; - state.bufferProcessing = false; -} - -Writable.prototype._write = function (chunk, encoding, cb) { - cb(new Error('_write() is not implemented')); -}; + function getPrefixDeclarations(input) { + var prefInd = arrayIndicesOf('PREFIX', input); + var res = []; + for (var i in prefInd) { + var a = input[prefInd[i] + 1]; + var b = input[prefInd[i] + 2]; + if (!isPrefix(a)) { + log.error('Invalid SPARQL prefix: ' + a); + } else if (!isSymbol(b)) { + log.error('Invalid SPARQL symbol: ' + b); + } else { + log.info('Prefix found: ' + a + ' -> ' + b); + var pref = getPrefix(a); + var symbol = removeBrackets(b); + res[pref] = symbol; + } + } + return res; + } -Writable.prototype._writev = null; + function getMatchingBracket(arr, open, close) { + log.info('Looking for a close bracket of type ' + close + ' in ' + arr); + var index = 0; + for (var i = 0; i < arr.length; i++) { + if (arr[i] === open) { + index++; + } + if (arr[i] === close) { + index--; + } + if (index < 0) { + return i; + } + } + log.error('Statement had no close parenthesis in SPARQL query'); + return 0; + } -Writable.prototype.end = function (chunk, encoding, cb) { - var state = this._writableState; + function constraintGreaterThan(value) { + this.describe = function (varstr) { + return varstr + ' > ' + value.toNT(); + }; + this.test = function (term) { + if (term.value.match(/[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/)) { + return parseFloat(term.value) > parseFloat(value); + } else { + return term.toNT() > value.toNT(); + } + }; + return this; + } - if (typeof chunk === 'function') { - cb = chunk; - chunk = null; - encoding = null; - } else if (typeof encoding === 'function') { - cb = encoding; - encoding = null; + function constraintLessThan(value) { + // this is not the recommended usage. Should only work on literal, numeric, dateTime + this.describe = function (varstr) { + return varstr + ' < ' + value.toNT(); + }; + this.test = function (term) { + // this.describe = function (varstr) { return varstr + " < "+value } + if (term.value.match(/[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?/)) { + return parseFloat(term.value) < parseFloat(value); + } else { + return term.toNT() < value.toNT(); + } + }; + return this; + } + // This should only work on literals but doesn't. + function ConstraintEqualTo(value) { + this.describe = function (varstr) { + return varstr + ' = ' + value.toNT(); + }; + this.test = function (term) { + return value.sameTerm(term); + }; + return this; } - if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); + // value must be a literal + function ConstraintRegexp(value) { + this.describe = function (varstr) { + return "REGEXP( '" + value + "' , " + varstr + ' )'; + }; + this.test = function (term) { + var str = value; + // str = str.replace(/^//,"").replace(//$/,"") + var rg = new RegExp(str); + if (term.value) { + return rg.test(term.value); + } else { + return false; + } + }; + } - // .end() fully uncorks - if (state.corked) { - state.corked = 1; - this.uncork(); + function setConstraint(input, pat) { + if (input.length === 3 && input[0].termType === 'Variable' && (input[2].termType === 'NamedNode' || input[2].termType === 'Literal')) { + if (input[1] === '=') { + log.debug('Constraint added: ' + input); + pat.constraints[input[0]] = new ConstraintEqualTo(input[2]); + } else if (input[1] === '>') { + log.debug('Constraint added: ' + input); + pat.constraints[input[0]] = new ConstraintEqualTo(input[2]); + } else if (input[1] === '<') { + log.debug('Constraint added: ' + input); + pat.constraints[input[0]] = new ConstraintEqualTo(input[2]); + } else { + log.warn("I don't know how to handle the constraint: " + input); + } + } else if (input.length === 6 && typeof input[0] === 'string' && input[0].toLowerCase() === 'regexp' && input[1] === '(' && input[5] === ')' && input[3] === ',' && input[4].termType === 'Variable' && input[2].termType === 'Literal') { + log.debug('Constraint added: ' + input); + pat.constraints[input[4]] = new ConstraintRegexp(input[2].value); + } + // log.warn("I don't know how to handle the constraint: "+input) + // alert("length: "+input.length+" input 0 type: "+input[0].termType+" input 1: "+input[1]+" input[2] type: "+input[2].termType) } - // ignore unnecessary end() calls. - if (!state.ending && !state.finished) endWritable(this, state, cb); -}; + function setOptional(terms, pat) { + log.debug('Optional query: ' + terms + ' not yet implemented.'); + var opt = kb.formula(); + setWhere(terms, opt); + pat.optional.push(opt); + } -function needFinish(state) { - return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing; -} -function callFinal(stream, state) { - stream._final(function (err) { - state.pendingcb--; - if (err) { - stream.emit('error', err); + function setWhere(input, pat) { + var terms = toTerms(input); + var end; + log.debug('WHERE: ' + terms); + var opt; + // var opt = arrayIndicesOf("OPTIONAL",terms) + while (arrayIndexOf('OPTIONAL', terms)) { + opt = arrayIndexOf('OPTIONAL', terms); + log.debug('OPT: ' + opt + ' ' + terms[opt] + ' in ' + terms); + if (terms[opt + 1] !== '{') { + log.warn('Bad optional opening bracket in word ' + opt); + } + end = getMatchingBracket(terms.slice(opt + 2), '{', '}'); + if (end === -1) { + log.error('No matching bracket in word ' + opt); + } else { + setOptional(terms.slice(opt + 2, opt + 2 + end), pat); + // alert(pat.statements[0].toNT()) + opt = arrayIndexOf('OPTIONAL', terms); + end = getMatchingBracket(terms.slice(opt + 2), '{', '}'); + terms.splice(opt, end + 3); + } } - state.prefinished = true; - stream.emit('prefinish'); - finishMaybe(stream, state); - }); -} -function prefinish(stream, state) { - if (!state.prefinished && !state.finalCalled) { - if (typeof stream._final === 'function') { - state.pendingcb++; - state.finalCalled = true; - processNextTick(callFinal, stream, state); - } else { - state.prefinished = true; - stream.emit('prefinish'); + log.debug('WHERE after optionals: ' + terms); + while (arrayIndexOf('FILTER', terms)) { + var filt = arrayIndexOf('FILTER', terms); + if (terms[filt + 1] !== '(') { + log.warn('Bad filter opening bracket in word ' + filt); + } + end = getMatchingBracket(terms.slice(filt + 2), '(', ')'); + if (end === -1) { + log.error('No matching bracket in word ' + filt); + } else { + setConstraint(terms.slice(filt + 2, filt + 2 + end), pat); + filt = arrayIndexOf('FILTER', terms); + end = getMatchingBracket(terms.slice(filt + 2), '(', ')'); + terms.splice(filt, end + 3); + } } + log.debug('WHERE after filters and optionals: ' + terms); + extractStatements(terms, pat); } -} -function finishMaybe(stream, state) { - var need = needFinish(state); - if (need) { - prefinish(stream, state); - if (state.pendingcb === 0) { - state.finished = true; - stream.emit('finish'); + function extractStatements(terms, formula) { + var arrayZero = new Array(1); + arrayZero[0] = -1; // this is just to add the beginning of the where to the periods index. + var per = arrayZero.concat(arrayIndicesOf('.', terms)); + var stat = []; + for (var x = 0; x < per.length - 1; x++) { + stat[x] = terms.slice(per[x] + 1, per[x + 1]); + } + // Now it's in an array of statements + for (x in stat) { + // THIS MUST BE CHANGED FOR COMMA, SEMICOLON + log.info('s+p+o ' + x + ' = ' + stat[x]); + var subj = stat[x][0]; + stat[x].splice(0, 1); + var sem = arrayZero.concat(arrayIndicesOf(';', stat[x])); + sem.push(stat[x].length); + var stat2 = []; + for (var y = 0; y < sem.length - 1; y++) { + stat2[y] = stat[x].slice(sem[y] + 1, sem[y + 1]); + } + for (x in stat2) { + log.info('p+o ' + x + ' = ' + stat[x]); + var pred = stat2[x][0]; + stat2[x].splice(0, 1); + var com = arrayZero.concat(arrayIndicesOf(',', stat2[x])); + com.push(stat2[x].length); + var stat3 = []; + for (y = 0; y < com.length - 1; y++) { + stat3[y] = stat2[x].slice(com[y] + 1, com[y + 1]); + } + for (x in stat3) { + var obj = stat3[x][0]; + log.info('Subj=' + subj + ' Pred=' + pred + ' Obj=' + obj); + formula.add(subj, pred, obj); + } + } } } - return need; -} -function endWritable(stream, state, cb) { - state.ending = true; - finishMaybe(stream, state); - if (cb) { - if (state.finished) processNextTick(cb);else stream.once('finish', cb); + // ******************************* Body of SPARQLToQuery ***************************// + log.info('SPARQL input: \n' + SPARQL); + var q = new Query(); + var sp = tokenize(SPARQL); // first tokenize everything + var prefixes = getPrefixDeclarations(sp); + if (!prefixes.rdf) { + prefixes.rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; } - state.ended = true; - stream.writable = false; -} - -function onCorkedFinish(corkReq, state, err) { - var entry = corkReq.entry; - corkReq.entry = null; - while (entry) { - var cb = entry.callback; - state.pendingcb--; - cb(err); - entry = entry.next; + if (!prefixes.rdfs) { + prefixes.rdfs = 'http://www.w3.org/2000/01/rdf-schema#'; } - if (state.corkedRequestsFree) { - state.corkedRequestsFree.next = corkReq; - } else { - state.corkedRequestsFree = corkReq; + var selectLoc = arrayIndexOf('SELECT', sp); + var whereLoc = arrayIndexOf('WHERE', sp); + if (selectLoc < 0 || whereLoc < 0 || selectLoc > whereLoc) { + log.error('Invalid or nonexistent SELECT and WHERE tags in SPARQL query'); + return false; } -} + setVars(sp.slice(selectLoc + 1, whereLoc), q); -Object.defineProperty(Writable.prototype, 'destroyed', { - get: function () { - if (this._writableState === undefined) { - return false; - } - return this._writableState.destroyed; - }, - set: function (value) { - // we ignore the value if the stream - // has not been initialized yet - if (!this._writableState) { - return; - } + setWhere(sp.slice(whereLoc + 2, sp.length - 1), q.pat); - // backward compatibility, the user is explicitly - // managing destroyed - this._writableState.destroyed = value; + if (testMode) { + return q; } -}); -Writable.prototype.destroy = destroyImpl.destroy; -Writable.prototype._undestroy = destroyImpl.undestroy; -Writable.prototype._destroy = function (err, cb) { - this.end(); - cb(err); -}; -}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + for (var x in q.pat.statements) { + var st = q.pat.statements[x]; + if (st.subject.termType === 'NamedNode') { + /* && sf.isPending(st.subject.uri) */ // This doesn't work. + // sf.requestURI(st.subject.uri,"sparql:"+st.subject) Kenny: I remove these two + if (kb.fetcher) { + kb.fetcher.lookUpThing(st.subject, 'sparql:' + st.subject); + } + } + if (st.object.termType === 'NamedNode') { + /* && sf.isPending(st.object.uri) */ + // sf.requestURI(st.object.uri,"sparql:"+st.object) + if (kb.fetcher) { + kb.fetcher.lookUpThing(st.object, 'sparql:' + st.object); + } + } + } + // alert(q.pat) + return q; + // checkVars() + // *******************************************************************// +} -},{"./_stream_duplex":85,"./internal/streams/destroy":91,"./internal/streams/stream":92,"_process":37,"core-util-is":8,"inherits":15,"process-nextick-args":36,"safe-buffer":99,"util-deprecate":109}],90:[function(_dereq_,module,exports){ +module.exports = SPARQLToQuery; +},{"./log":252,"./query":260}],266:[function(_dereq_,module,exports){ 'use strict'; -/**/ +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -var Buffer = _dereq_('safe-buffer').Buffer; -/**/ +var Node = _dereq_('./node'); + +var Statement = function () { + function Statement(subject, predicate, object, graph) { + _classCallCheck(this, Statement); + + this.subject = Node.fromValue(subject); + this.predicate = Node.fromValue(predicate); + this.object = Node.fromValue(object); + this.why = graph; // property currently used by rdflib + } + + _createClass(Statement, [{ + key: 'equals', + value: function equals(other) { + return other.subject.equals(this.subject) && other.predicate.equals(this.predicate) && other.object.equals(this.object) && other.graph.equals(this.graph); + } + }, { + key: 'substitute', + value: function substitute(bindings) { + var y = new Statement(this.subject.substitute(bindings), this.predicate.substitute(bindings), this.object.substitute(bindings), this.why.substitute(bindings)); // 2016 + console.log('@@@ statement substitute:' + y); + return y; + } + }, { + key: 'toCanonical', + value: function toCanonical() { + var terms = [this.subject.toCanonical(), this.predicate.toCanonical(), this.object.toCanonical()]; + if (this.graph && this.graph.termType !== 'DefaultGraph') { + terms.push(this.graph.toCanonical()); + } + return terms.join(' ') + ' .'; + } + }, { + key: 'toNT', + value: function toNT() { + return [this.subject.toNT(), this.predicate.toNT(), this.object.toNT()].join(' ') + ' .'; + } + }, { + key: 'toString', + value: function toString() { + return this.toNT(); + } + }, { + key: 'graph', + get: function get() { + return this.why; + }, + set: function set(g) { + this.why = g; + } + }]); + + return Statement; +}(); + +module.exports = Statement; +},{"./node":256}],267:[function(_dereq_,module,exports){ +'use strict'; -function copyBuffer(src, target, offset) { - src.copy(target, offset); -} +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; -module.exports = function () { - function BufferList() { - _classCallCheck(this, BufferList); +var _indexedFormula = _dereq_('./indexed-formula'); - this.head = null; - this.tail = null; - this.length = 0; - } +var _indexedFormula2 = _interopRequireDefault(_indexedFormula); - BufferList.prototype.push = function push(v) { - var entry = { data: v, next: null }; - if (this.length > 0) this.tail.next = entry;else this.head = entry; - this.tail = entry; - ++this.length; - }; +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - BufferList.prototype.unshift = function unshift(v) { - var entry = { data: v, next: this.head }; - if (this.length === 0) this.tail = entry; - this.head = entry; - ++this.length; - }; +// Joe Presbrey +// 2007-07-15 +// 2010-08-08 TimBL folded in Kenny's WEBDAV +// 2010-12-07 TimBL addred local file write code +var docpart = _dereq_('./uri').docpart; +var Fetcher = _dereq_('./fetcher'); +var graph = _dereq_('./data-factory').graph; - BufferList.prototype.shift = function shift() { - if (this.length === 0) return; - var ret = this.head.data; - if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next; - --this.length; - return ret; - }; +var namedNode = _dereq_('./data-factory').namedNode; +var Namespace = _dereq_('./namespace'); +var Serializer = _dereq_('./serializer'); +var uriJoin = _dereq_('./uri').join; +var Util = _dereq_('./util'); - BufferList.prototype.clear = function clear() { - this.head = this.tail = null; - this.length = 0; - }; +var UpdateManager = function () { + var sparql = function sparql(store) { + this.store = store; + if (store.updater) { + throw new Error("You can't have two UpdateManagers for the same store"); + } + if (!store.fetcher) { + // The store must also/already have a fetcher + new Fetcher(store); + } + store.updater = this; + this.ifps = {}; + this.fps = {}; + this.ns = {}; + this.ns.link = Namespace('http://www.w3.org/2007/ont/link#'); + this.ns.http = Namespace('http://www.w3.org/2007/ont/http#'); + this.ns.httph = Namespace('http://www.w3.org/2007/ont/httph#'); + this.ns.ldp = Namespace('http://www.w3.org/ns/ldp#'); + this.ns.rdf = Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#'); + this.ns.rdfs = Namespace('http://www.w3.org/2000/01/rdf-schema#'); + this.ns.rdf = Namespace('http://www.w3.org/1999/02/22-rdf-syntax-ns#'); + this.ns.owl = Namespace('http://www.w3.org/2002/07/owl#'); - BufferList.prototype.join = function join(s) { - if (this.length === 0) return ''; - var p = this.head; - var ret = '' + p.data; - while (p = p.next) { - ret += s + p.data; - }return ret; + this.patchControl = []; // index of objects fro coordinating incomng and outgoing patches }; - BufferList.prototype.concat = function concat(n) { - if (this.length === 0) return Buffer.alloc(0); - if (this.length === 1) return this.head.data; - var ret = Buffer.allocUnsafe(n >>> 0); - var p = this.head; - var i = 0; - while (p) { - copyBuffer(p.data, ret, i); - i += p.data.length; - p = p.next; + sparql.prototype.patchControlFor = function (doc) { + if (!this.patchControl[doc.uri]) { + this.patchControl[doc.uri] = []; } - return ret; + return this.patchControl[doc.uri]; }; - return BufferList; -}(); -},{"safe-buffer":99}],91:[function(_dereq_,module,exports){ -'use strict'; + // Returns The method string SPARQL or DAV or LOCALFILE or false if known, undefined if not known. + // + // Files have to have a specific annotaton that they are machine written, for safety. + // We don't actually check for write access on files. + // + sparql.prototype.editable = function (uri, kb) { + if (!uri) { + return false; // Eg subject is bnode, no known doc to write to + } + if (!kb) { + kb = this.store; + } -/**/ + if (uri.slice(0, 8) === 'file:///') { + if (kb.holds(kb.sym(uri), namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode('http://www.w3.org/2007/ont/link#MachineEditableDocument'))) { + return 'LOCALFILE'; + } -var processNextTick = _dereq_('process-nextick-args'); -/**/ + var sts = kb.statementsMatching(kb.sym(uri), undefined, undefined); -// undocumented cb() API, needed for core, not for public API -function destroy(err, cb) { - var _this = this; + console.log('sparql.editable: Not MachineEditableDocument file ' + uri + '\n'); + console.log(sts.map(function (x) { + return x.toNT(); + }).join('\n')); + return false; + // @@ Would be nifty of course to see whether we actually have write acess first. + } - var readableDestroyed = this._readableState && this._readableState.destroyed; - var writableDestroyed = this._writableState && this._writableState.destroyed; + var request; + var definitive = false; + var requests = kb.each(undefined, this.ns.link('requestedURI'), docpart(uri)); - if (readableDestroyed || writableDestroyed) { - if (cb) { - cb(err); - } else if (err && (!this._writableState || !this._writableState.errorEmitted)) { - processNextTick(emitErrorNT, this, err); + // Hack for the moment @@@@ 2016-02-12 + if (kb.holds(namedNode(uri), this.ns.rdf('type'), this.ns.ldp('Resource'))) { + return 'SPARQL'; } - return; - } + var i; + var method; + for (var r = 0; r < requests.length; r++) { + request = requests[r]; + if (request !== undefined) { + var response = kb.any(request, this.ns.link('response')); + if (request !== undefined) { + var acceptPatch = kb.each(response, this.ns.httph('accept-patch')); + if (acceptPatch.length) { + for (i = 0; i < acceptPatch.length; i++) { + method = acceptPatch[i].value.trim(); + if (method.indexOf('application/sparql-update') >= 0) return 'SPARQL'; + } + } + var author_via = kb.each(response, this.ns.httph('ms-author-via')); + if (author_via.length) { + for (i = 0; i < author_via.length; i++) { + method = author_via[i].value.trim(); + if (method.indexOf('SPARQL') >= 0) { + return 'SPARQL'; + } + if (method.indexOf('DAV') >= 0) { + return 'DAV'; + } + } + } + var status = kb.each(response, this.ns.http('status')); + if (status.length) { + for (i = 0; i < status.length; i++) { + if (status[i] === 200 || status[i] === 404) { + definitive = true; + // return false // A definitive answer + } + } + } + } else { + console.log('sparql.editable: No response for ' + uri + '\n'); + } + } + } + if (requests.length === 0) { + console.log('sparql.editable: No request for ' + uri + '\n'); + } else { + if (definitive) { + return false; // We have got a request and it did NOT say editable => not editable + } + } + console.log('sparql.editable: inconclusive for ' + uri + '\n'); + return undefined; // We don't know (yet) as we haven't had a response (yet) + }; - // we set destroyed to true before firing error callbacks in order - // to make it re-entrance safe in case destroy() is called within callbacks + // ///////// The identification of bnodes - if (this._readableState) { - this._readableState.destroyed = true; - } + sparql.prototype.anonymize = function (obj) { + return obj.toNT().substr(0, 2) === '_:' && this._mentioned(obj) ? '?' + obj.toNT().substr(2) : obj.toNT(); + }; - // if this is a duplex stream mark the writable part as destroyed as well - if (this._writableState) { - this._writableState.destroyed = true; - } + sparql.prototype.anonymizeNT = function (stmt) { + return this.anonymize(stmt.subject) + ' ' + this.anonymize(stmt.predicate) + ' ' + this.anonymize(stmt.object) + ' .'; + }; - this._destroy(err || null, function (err) { - if (!cb && err) { - processNextTick(emitErrorNT, _this, err); - if (_this._writableState) { - _this._writableState.errorEmitted = true; + // A list of all bnodes occuring in a statement + sparql.prototype._statement_bnodes = function (st) { + return [st.subject, st.predicate, st.object].filter(function (x) { + return x.isBlank; + }); + }; + + // A list of all bnodes occuring in a list of statements + sparql.prototype._statement_array_bnodes = function (sts) { + var bnodes = []; + for (var i = 0; i < sts.length; i++) { + bnodes = bnodes.concat(this._statement_bnodes(sts[i])); + } + bnodes.sort(); // in place sort - result may have duplicates + var bnodes2 = []; + for (var j = 0; j < bnodes.length; j++) { + if (j === 0 || !bnodes[j].sameTerm(bnodes[j - 1])) { + bnodes2.push(bnodes[j]); } - } else if (cb) { - cb(err); } - }); -} - -function undestroy() { - if (this._readableState) { - this._readableState.destroyed = false; - this._readableState.reading = false; - this._readableState.ended = false; - this._readableState.endEmitted = false; - } - - if (this._writableState) { - this._writableState.destroyed = false; - this._writableState.ended = false; - this._writableState.ending = false; - this._writableState.finished = false; - this._writableState.errorEmitted = false; - } -} - -function emitErrorNT(self, err) { - self.emit('error', err); -} + return bnodes2; + }; -module.exports = { - destroy: destroy, - undestroy: undestroy -}; -},{"process-nextick-args":36}],92:[function(_dereq_,module,exports){ -module.exports = _dereq_('events').EventEmitter; + sparql.prototype._cache_ifps = function () { + // Make a cached list of [Inverse-]Functional properties + // Call this once before calling context_statements + this.ifps = {}; + var a = this.store.each(undefined, this.ns.rdf('type'), this.ns.owl('InverseFunctionalProperty')); + for (var i = 0; i < a.length; i++) { + this.ifps[a[i].uri] = true; + } + this.fps = {}; + a = this.store.each(undefined, this.ns.rdf('type'), this.ns.owl('FunctionalProperty')); + for (i = 0; i < a.length; i++) { + this.fps[a[i].uri] = true; + } + }; -},{"events":10}],93:[function(_dereq_,module,exports){ -arguments[4][6][0].apply(exports,arguments) -},{"dup":6}],94:[function(_dereq_,module,exports){ -'use strict'; + // Returns a context to bind a given node, up to a given depth + sparql.prototype._bnode_context2 = function (x, source, depth) { + // Return a list of statements which indirectly identify a node + // Depth > 1 if try further indirection. + // Return array of statements (possibly empty), or null if failure + var sts = this.store.statementsMatching(undefined, undefined, x, source); // incoming links + var y; + var res; + for (var i = 0; i < sts.length; i++) { + if (this.fps[sts[i].predicate.uri]) { + y = sts[i].subject; + if (!y.isBlank) { + return [sts[i]]; + } + if (depth) { + res = this._bnode_context2(y, source, depth - 1); + if (res) { + return res.concat([sts[i]]); + } + } + } + } + // outgoing links + sts = this.store.statementsMatching(x, undefined, undefined, source); + for (i = 0; i < sts.length; i++) { + if (this.ifps[sts[i].predicate.uri]) { + y = sts[i].object; + if (!y.isBlank) { + return [sts[i]]; + } + if (depth) { + res = this._bnode_context2(y, source, depth - 1); + if (res) { + return res.concat([sts[i]]); + } + } + } + } + return null; // Failure + }; -var Buffer = _dereq_('safe-buffer').Buffer; + // Returns the smallest context to bind a given single bnode + sparql.prototype._bnode_context_1 = function (x, source) { + // Return a list of statements which indirectly identify a node + // Breadth-first + var self = this; + for (var depth = 0; depth < 3; depth++) { + // Try simple first + var con = this._bnode_context2(x, source, depth); + if (con !== null) return con; + } + // If we can't guarantee unique with logic just send all info about node + return this.store.connectedStatements(x, source); // was: + // throw new Error('Unable to uniquely identify bnode: ' + x.toNT()) + }; -var isEncoding = Buffer.isEncoding || function (encoding) { - encoding = '' + encoding; - switch (encoding && encoding.toLowerCase()) { - case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw': - return true; - default: - return false; - } -}; + sparql.prototype._mentioned = function (x) { + return this.store.statementsMatching(x).length !== 0 || // Don't pin fresh bnodes + this.store.statementsMatching(undefined, x).length !== 0 || this.store.statementsMatching(undefined, undefined, x).length !== 0; + }; -function _normalizeEncoding(enc) { - if (!enc) return 'utf8'; - var retried; - while (true) { - switch (enc) { - case 'utf8': - case 'utf-8': - return 'utf8'; - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return 'utf16le'; - case 'latin1': - case 'binary': - return 'latin1'; - case 'base64': - case 'ascii': - case 'hex': - return enc; - default: - if (retried) return; // undefined - enc = ('' + enc).toLowerCase(); - retried = true; + sparql.prototype._bnode_context = function (bnodes, doc) { + var context = []; + if (bnodes.length) { + this._cache_ifps(); + for (var i = 0; i < bnodes.length; i++) { + // Does this occur in old graph? + var bnode = bnodes[i]; + if (!this._mentioned(bnode)) continue; + context = context.concat(this._bnode_context_1(bnode, doc)); + } } - } -}; + return context; + }; -// Do not cache `Buffer.isEncoding` when checking encoding names as some -// modules monkey-patch it to support additional encodings -function normalizeEncoding(enc) { - var nenc = _normalizeEncoding(enc); - if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc); - return nenc || enc; -} + /* Weird code does not make sense -- some code corruption along the line -- st undefined -- weird + sparql.prototype._bnode_context = function(bnodes) { + var context = [] + if (bnodes.length) { + if (this.store.statementsMatching(st.subject.isBlank?undefined:st.subject, + st.predicate.isBlank?undefined:st.predicate, + st.object.isBlank?undefined:st.object, + st.why).length <= 1) { + context = context.concat(st) + } else { + this._cache_ifps() + for (x in bnodes) { + context = context.concat(this._bnode_context_1(bnodes[x], st.why)) + } + } + } + return context + } + */ + // Returns the best context for a single statement + sparql.prototype._statement_context = function (st) { + var bnodes = this._statement_bnodes(st); + return this._bnode_context(bnodes, st.why); + }; -// StringDecoder provides an interface for efficiently splitting a series of -// buffers into a series of JS strings without breaking apart multi-byte -// characters. -exports.StringDecoder = StringDecoder; -function StringDecoder(encoding) { - this.encoding = normalizeEncoding(encoding); - var nb; - switch (this.encoding) { - case 'utf16le': - this.text = utf16Text; - this.end = utf16End; - nb = 4; - break; - case 'utf8': - this.fillLast = utf8FillLast; - nb = 4; - break; - case 'base64': - this.text = base64Text; - this.end = base64End; - nb = 3; - break; - default: - this.write = simpleWrite; - this.end = simpleEnd; - return; - } - this.lastNeed = 0; - this.lastTotal = 0; - this.lastChar = Buffer.allocUnsafe(nb); -} + sparql.prototype._context_where = function (context) { + var sparql = this; + return !context || context.length === 0 ? '' : 'WHERE { ' + context.map(function (x) { + return sparql.anonymizeNT(x); + }).join('\n') + ' }\n'; + }; -StringDecoder.prototype.write = function (buf) { - if (buf.length === 0) return ''; - var r; - var i; - if (this.lastNeed) { - r = this.fillLast(buf); - if (r === undefined) return ''; - i = this.lastNeed; - this.lastNeed = 0; - } else { - i = 0; - } - if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i); - return r || ''; -}; + sparql.prototype._fire = function (uri, query, callback) { + if (!uri) { + throw new Error('No URI given for remote editing operation: ' + query); + } + console.log('sparql: sending update to <' + uri + '>'); + var xhr = Util.XMLHTTPFactory(); + xhr.options = {}; -StringDecoder.prototype.end = utf8End; + xhr.onreadystatechange = function () { + // dump("SPARQL update ready state for <"+uri+"> readyState="+xhr.readyState+"\n"+query+"\n") + if (xhr.readyState === 4) { + var success = !xhr.status || xhr.status >= 200 && xhr.status < 300; + if (!success) { + console.log('sparql: update failed for <' + uri + '> status=' + xhr.status + ', ' + xhr.statusText + ', body length=' + xhr.responseText.length + '\n for query: ' + query); + } else { + console.log('sparql: update Ok for <' + uri + '>'); + } + callback(uri, success, xhr.responseText, xhr); + } + }; -// Returns only complete characters in a Buffer -StringDecoder.prototype.text = utf8Text; + xhr.open('PATCH', uri, true); // async=true + xhr.setRequestHeader('Content-type', 'application/sparql-update'); + xhr.send(query); + }; -// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer -StringDecoder.prototype.fillLast = function (buf) { - if (this.lastNeed <= buf.length) { - buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed); - return this.lastChar.toString(this.encoding, 0, this.lastTotal); - } - buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length); - this.lastNeed -= buf.length; -}; + // This does NOT update the statement. + // It returns an object whcih includes + // function which can be used to change the object of the statement. + // + sparql.prototype.update_statement = function (statement) { + if (statement && !statement.why) { + return; + } + var sparql = this; + var context = this._statement_context(statement); -// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a -// continuation byte. -function utf8CheckByte(byte) { - if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4; - return -1; -} + return { + statement: statement ? [statement.subject, statement.predicate, statement.object, statement.why] : undefined, + statementNT: statement ? this.anonymizeNT(statement) : undefined, + where: sparql._context_where(context), -// Checks at most 3 bytes at the end of a Buffer in order to detect an -// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4) -// needed to complete the UTF-8 character (if applicable) are returned. -function utf8CheckIncomplete(self, buf, i) { - var j = buf.length - 1; - if (j < i) return 0; - var nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) self.lastNeed = nb - 1; - return nb; - } - if (--j < i) return 0; - nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) self.lastNeed = nb - 2; - return nb; - } - if (--j < i) return 0; - nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) { - if (nb === 2) nb = 0;else self.lastNeed = nb - 3; - } - return nb; - } - return 0; -} + set_object: function set_object(obj, callback) { + var query = this.where; + query += 'DELETE DATA { ' + this.statementNT + ' } ;\n'; + query += 'INSERT DATA { ' + this.anonymize(this.statement[0]) + ' ' + this.anonymize(this.statement[1]) + ' ' + this.anonymize(obj) + ' ' + ' . }\n'; -// Validates as many continuation bytes for a multi-byte UTF-8 character as -// needed or are available. If we see a non-continuation byte where we expect -// one, we "replace" the validated continuation bytes we've seen so far with -// UTF-8 replacement characters ('\ufffd'), to match v8's UTF-8 decoding -// behavior. The continuation byte check is included three times in the case -// where all of the continuation bytes for a character exist in the same buffer. -// It is also done this way as a slight performance increase instead of using a -// loop. -function utf8CheckExtraBytes(self, buf, p) { - if ((buf[0] & 0xC0) !== 0x80) { - self.lastNeed = 0; - return '\ufffd'.repeat(p); - } - if (self.lastNeed > 1 && buf.length > 1) { - if ((buf[1] & 0xC0) !== 0x80) { - self.lastNeed = 1; - return '\ufffd'.repeat(p + 1); - } - if (self.lastNeed > 2 && buf.length > 2) { - if ((buf[2] & 0xC0) !== 0x80) { - self.lastNeed = 2; - return '\ufffd'.repeat(p + 2); + sparql._fire(this.statement[3].uri, query, callback); } + }; + }; + + sparql.prototype.insert_statement = function (st, callback) { + var st0 = st instanceof Array ? st[0] : st; + var query = this._context_where(this._statement_context(st0)); + + if (st instanceof Array) { + var stText = ''; + for (var i = 0; i < st.length; i++) { + stText += st[i] + '\n'; + }query += 'INSERT DATA { ' + stText + ' }\n'; + } else { + query += 'INSERT DATA { ' + this.anonymize(st.subject) + ' ' + this.anonymize(st.predicate) + ' ' + this.anonymize(st.object) + ' ' + ' . }\n'; } - } -} -// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer. -function utf8FillLast(buf) { - var p = this.lastTotal - this.lastNeed; - var r = utf8CheckExtraBytes(this, buf, p); - if (r !== undefined) return r; - if (this.lastNeed <= buf.length) { - buf.copy(this.lastChar, p, 0, this.lastNeed); - return this.lastChar.toString(this.encoding, 0, this.lastTotal); - } - buf.copy(this.lastChar, p, 0, buf.length); - this.lastNeed -= buf.length; -} + this._fire(st0.why.uri, query, callback); + }; -// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a -// partial character, the character's bytes are buffered until the required -// number of bytes are available. -function utf8Text(buf, i) { - var total = utf8CheckIncomplete(this, buf, i); - if (!this.lastNeed) return buf.toString('utf8', i); - this.lastTotal = total; - var end = buf.length - (total - this.lastNeed); - buf.copy(this.lastChar, 0, end); - return buf.toString('utf8', i, end); -} + sparql.prototype.delete_statement = function (st, callback) { + var st0 = st instanceof Array ? st[0] : st; + var query = this._context_where(this._statement_context(st0)); -// For UTF-8, a replacement character for each buffered byte of a (partial) -// character needs to be added to the output. -function utf8End(buf) { - var r = buf && buf.length ? this.write(buf) : ''; - if (this.lastNeed) return r + '\ufffd'.repeat(this.lastTotal - this.lastNeed); - return r; -} + if (st instanceof Array) { + var stText = ''; + for (var i = 0; i < st.length; i++) { + stText += st[i] + '\n'; + }query += 'DELETE DATA { ' + stText + ' }\n'; + } else { + query += 'DELETE DATA { ' + this.anonymize(st.subject) + ' ' + this.anonymize(st.predicate) + ' ' + this.anonymize(st.object) + ' ' + ' . }\n'; + } -// UTF-16LE typically needs two bytes per character, but even if we have an even -// number of bytes available, we need to check if we end on a leading/high -// surrogate. In that case, we need to wait for the next two bytes in order to -// decode the last character properly. -function utf16Text(buf, i) { - if ((buf.length - i) % 2 === 0) { - var r = buf.toString('utf16le', i); - if (r) { - var c = r.charCodeAt(r.length - 1); - if (c >= 0xD800 && c <= 0xDBFF) { - this.lastNeed = 2; - this.lastTotal = 4; - this.lastChar[0] = buf[buf.length - 2]; - this.lastChar[1] = buf[buf.length - 1]; - return r.slice(0, -1); + this._fire(st0.why.uri, query, callback); + }; + + // Request a now or future action to refresh changes coming downstream + // + // This is designed to allow the system to re-request the server version, + // when a websocket has pinged to say there are changes. + // If thewebsocket, by contrast, has sent a patch, then this may not be necessary. + // This may be called out of context so *this* cannot be used. + + sparql.prototype.requestDownstreamAction = function (doc, action) { + var control = this.patchControlFor(doc); + if (!control.pendingUpstream) { + action(doc); + } else { + if (control.downstreamAction) { + if (control.downstreamAction === action) { + return; + } else { + throw new Error("Can't wait for > 1 differnt downstream actions"); + } + } else { + control.downstreamAction = action; } } - return r; - } - this.lastNeed = 1; - this.lastTotal = 2; - this.lastChar[0] = buf[buf.length - 1]; - return buf.toString('utf16le', i, buf.length - 1); -} - -// For UTF-16LE we do not explicitly append special replacement characters if we -// end on a partial character, we simply let v8 handle that. -function utf16End(buf) { - var r = buf && buf.length ? this.write(buf) : ''; - if (this.lastNeed) { - var end = this.lastTotal - this.lastNeed; - return r + this.lastChar.toString('utf16le', 0, end); - } - return r; -} + }; -function base64Text(buf, i) { - var n = (buf.length - i) % 3; - if (n === 0) return buf.toString('base64', i); - this.lastNeed = 3 - n; - this.lastTotal = 3; - if (n === 1) { - this.lastChar[0] = buf[buf.length - 1]; - } else { - this.lastChar[0] = buf[buf.length - 2]; - this.lastChar[1] = buf[buf.length - 1]; - } - return buf.toString('base64', i, buf.length - n); -} + // We want to start counting websockt notifications + // to distinguish the ones from others from our own. + sparql.prototype.clearUpstreamCount = function (doc) { + var control = this.patchControlFor(doc); + control.upstreamCount = 0; + }; -function base64End(buf) { - var r = buf && buf.length ? this.write(buf) : ''; - if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed); - return r; -} + sparql.prototype.getUpdatesVia = function (doc) { + var linkHeaders = this.store.fetcher.getHeader(doc, 'updates-via'); + if (!linkHeaders || !linkHeaders.length) return null; + return linkHeaders[0].trim(); + }; -// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex) -function simpleWrite(buf) { - return buf.toString(this.encoding); -} + sparql.prototype.addDownstreamChangeListener = function (doc, listener) { + var control = this.patchControlFor(doc); + if (!control.downstreamChangeListeners) control.downstreamChangeListeners = []; + control.downstreamChangeListeners.push(listener); + var self = this; + this.setRefreshHandler(doc, function (doc) { + // a function not a method + self.reloadAndSync(doc); + }); + }; -function simpleEnd(buf) { - return buf && buf.length ? this.write(buf) : ''; -} -},{"safe-buffer":99}],95:[function(_dereq_,module,exports){ -module.exports = _dereq_('./readable').PassThrough + sparql.prototype.reloadAndSync = function (doc) { + var control = this.patchControlFor(doc); + var updater = this; -},{"./readable":96}],96:[function(_dereq_,module,exports){ -exports = module.exports = _dereq_('./lib/_stream_readable.js'); -exports.Stream = exports; -exports.Readable = exports; -exports.Writable = _dereq_('./lib/_stream_writable.js'); -exports.Duplex = _dereq_('./lib/_stream_duplex.js'); -exports.Transform = _dereq_('./lib/_stream_transform.js'); -exports.PassThrough = _dereq_('./lib/_stream_passthrough.js'); + if (control.reloading) { + console.log(' Already reloading - stop'); + return; // once only needed + } + control.reloading = true; + var retryTimeout = 1000; // ms + var tryReload = function tryReload() { + console.log('try reload - timeout = ' + retryTimeout); + updater.reload(updater.store, doc, function (ok, message, xhr) { + control.reloading = false; + if (ok) { + if (control.downstreamChangeListeners) { + for (var i = 0; i < control.downstreamChangeListeners.length; i++) { + console.log(' Calling downstream listener ' + i); + control.downstreamChangeListeners[i](); + } + } + } else { + if (xhr.status === 0) { + console.log('Network error refreshing the data. Retrying in ' + retryTimeout / 1000); + control.reloading = true; + retryTimeout = retryTimeout * 2; + setTimeout(tryReload, retryTimeout); + } else { + console.log('Error ' + xhr.status + 'refreshing the data:' + message + '. Stopped' + doc); + } + } + }); + }; + tryReload(); + }; -},{"./lib/_stream_duplex.js":85,"./lib/_stream_passthrough.js":86,"./lib/_stream_readable.js":87,"./lib/_stream_transform.js":88,"./lib/_stream_writable.js":89}],97:[function(_dereq_,module,exports){ -module.exports = _dereq_('./readable').Transform + // Set up websocket to listen on + // + // There is coordination between upstream changes and downstream ones + // so that a reload is not done in the middle of an upsteeam patch. + // If you usie this API then you get called when a change happens, and you + // have to reload the file yourself, and then refresh the UI. + // Alternative is addDownstreamChangeListener(), where you do not + // have to do the reload yourslf. Do mot mix them. + // + // kb contains the HTTP metadata from prefvious operations + // + sparql.prototype.setRefreshHandler = function (doc, handler) { + var wssURI = this.getUpdatesVia(doc); // relative + // var kb = this.store + var theHandler = handler; + var self = this; + var updater = this; + var retryTimeout = 1500; // *2 will be 3 Seconds, 6, 12, etc + var retries = 0; -},{"./readable":96}],98:[function(_dereq_,module,exports){ -module.exports = _dereq_('./lib/_stream_writable.js'); + if (!wssURI) { + console.log('Server doies not support live updates thoughUpdates-Via :-('); + return false; + } -},{"./lib/_stream_writable.js":89}],99:[function(_dereq_,module,exports){ -/* eslint-disable node/no-deprecated-api */ -var buffer = _dereq_('buffer') -var Buffer = buffer.Buffer + wssURI = uriJoin(wssURI, doc.uri); + wssURI = wssURI.replace(/^http:/, 'ws:').replace(/^https:/, 'wss:'); + console.log('Web socket URI ' + wssURI); -// alternative to using Object.keys for old browsers -function copyProps (src, dst) { - for (var key in src) { - dst[key] = src[key] - } -} -if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { - module.exports = buffer -} else { - // Copy properties from require('buffer') - copyProps(buffer, exports) - exports.Buffer = SafeBuffer -} + var openWebsocket = function openWebsocket() { + // From https://github.com/solid/solid-spec#live-updates + var socket; + if (typeof WebSocket !== 'undefined') { + socket = new WebSocket(wssURI); + } else if (typeof Services !== 'undefined') { + // Firefox add on http://stackoverflow.com/questions/24244886/is-websocket-supported-in-firefox-for-android-addons + socket = Services.wm.getMostRecentWindow('navigator:browser').WebSocket(wssURI); + } else if (typeof window !== 'undefined' && window.WebSocket) { + socket = window.WebSocket(wssURI); + } else { + console.log('Live update disabled, as WebSocket not supported by platform :-('); + return; + } + socket.onopen = function () { + console.log(' websocket open'); + retryTimeout = 1500; // reset timeout to fast on success + this.send('sub ' + doc.uri); + if (retries) { + console.log('Web socket has been down, better check for any news.'); + updater.requestDownstreamAction(doc, theHandler); + } + }; + var control = self.patchControlFor(doc); + control.upstreamCount = 0; -function SafeBuffer (arg, encodingOrOffset, length) { - return Buffer(arg, encodingOrOffset, length) -} + // https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent + // + // 1000 CLOSE_NORMAL Normal closure; the connection successfully completed whatever purpose for which it was created. + // 1001 CLOSE_GOING_AWAY The endpoint is going away, either + // because of a server failure or because the browser is navigating away from the page that opened the connection. + // 1002 CLOSE_PROTOCOL_ERROR The endpoint is terminating the connection due to a protocol error. + // 1003 CLOSE_UNSUPPORTED The connection is being terminated because the endpoint + // received data of a type it cannot accept (for example, a text-only endpoint received binary data). + // 1004 Reserved. A meaning might be defined in the future. + // 1005 CLOSE_NO_STATUS Reserved. Indicates that no status code was provided even though one was expected. + // 1006 CLOSE_ABNORMAL Reserved. Used to indicate that a connection was closed abnormally ( + // + // + socket.onclose = function (event) { + console.log('*** Websocket closed with code ' + event.code + ", reason '" + event.reason + "' clean = " + event.clean); + retryTimeout *= 2; + retries += 1; + console.log('Retrying in ' + retryTimeout + 'ms'); // (ask user?) + setTimeout(function () { + console.log('Trying websocket again'); + openWebsocket(); + }, retryTimeout); + }; + socket.onmessage = function (msg) { + if (msg.data && msg.data.slice(0, 3) === 'pub') { + if ('upstreamCount' in control) { + control.upstreamCount -= 1; + if (control.upstreamCount >= 0) { + console.log('just an echo: ' + control.upstreamCount); + return; // Just an echo + } + } + console.log('Assume a real downstream change: ' + control.upstreamCount + ' -> 0'); + control.upstreamCount = 0; + self.requestDownstreamAction(doc, theHandler); + } + }; + }; // openWebsocket + openWebsocket(); -// Copy static methods from Buffer -copyProps(Buffer, SafeBuffer) + return true; + }; -SafeBuffer.from = function (arg, encodingOrOffset, length) { - if (typeof arg === 'number') { - throw new TypeError('Argument must not be a number') - } - return Buffer(arg, encodingOrOffset, length) -} + // This high-level function updates the local store iff the web is changed successfully. + // + // - deletions, insertions may be undefined or single statements or lists or formulae. + // (may contain bnodes which can be indirectly identified by a where clause) + // + // - callback is called as callback(uri, success, errorbody) + // + sparql.prototype.update = function (deletions, insertions, callback) { + try { + var kb = this.store; + var ds = !deletions ? [] : deletions instanceof _indexedFormula2.default ? deletions.statements : deletions instanceof Array ? deletions : [deletions]; + var is = !insertions ? [] : insertions instanceof _indexedFormula2.default ? insertions.statements : insertions instanceof Array ? insertions : [insertions]; + if (!(ds instanceof Array)) { + throw new Error('Type Error ' + (typeof ds === 'undefined' ? 'undefined' : _typeof(ds)) + ': ' + ds); + } + if (!(is instanceof Array)) { + throw new Error('Type Error ' + (typeof is === 'undefined' ? 'undefined' : _typeof(is)) + ': ' + is); + } + if (ds.length === 0 && is.length === 0) { + return callback(null, true); // success -- nothing needed to be done. + } + var doc = ds.length ? ds[0].why : is[0].why; + var control = this.patchControlFor(doc); + var startTime = Date.now(); -SafeBuffer.alloc = function (size, fill, encoding) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - var buf = Buffer(size) - if (fill !== undefined) { - if (typeof encoding === 'string') { - buf.fill(fill, encoding) - } else { - buf.fill(fill) - } - } else { - buf.fill(0) - } - return buf -} + var props = ['subject', 'predicate', 'object', 'why']; + var verbs = ['insert', 'delete']; + var clauses = { 'delete': ds, 'insert': is }; + verbs.map(function (verb) { + clauses[verb].map(function (st) { + if (!doc.sameTerm(st.why)) { + throw new Error('update: destination ' + doc + ' inconsistent with delete quad ' + st.why); + } + props.map(function (prop) { + if (typeof st[prop] === 'undefined') { + throw new Error('update: undefined ' + prop + ' of statement.'); + } + }); + }); + }); -SafeBuffer.allocUnsafe = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - return Buffer(size) -} + var protocol = this.editable(doc.uri, kb); + if (!protocol) { + throw new Error("Can't make changes in uneditable " + doc); + } + var i; + var newSts; + var documentString; + var sz; + if (protocol.indexOf('SPARQL') >= 0) { + var bnodes = []; + if (ds.length) bnodes = this._statement_array_bnodes(ds); + if (is.length) bnodes = bnodes.concat(this._statement_array_bnodes(is)); + var context = this._bnode_context(bnodes, doc); + var whereClause = this._context_where(context); + var query = ''; + if (whereClause.length) { + // Is there a WHERE clause? + if (ds.length) { + query += 'DELETE { '; + for (i = 0; i < ds.length; i++) { + query += this.anonymizeNT(ds[i]) + '\n'; + } + query += ' }\n'; + } + if (is.length) { + query += 'INSERT { '; + for (i = 0; i < is.length; i++) { + query += this.anonymizeNT(is[i]) + '\n'; + } + query += ' }\n'; + } + query += whereClause; + } else { + // no where clause + if (ds.length) { + query += 'DELETE DATA { '; + for (i = 0; i < ds.length; i++) { + query += this.anonymizeNT(ds[i]) + '\n'; + } + query += ' } \n'; + } + if (is.length) { + if (ds.length) query += ' ; '; + query += 'INSERT DATA { '; + for (i = 0; i < is.length; i++) { + query += this.anonymizeNT(is[i]) + '\n'; + } + query += ' }\n'; + } + } + // Track pending upstream patches until they have fnished their callback + control.pendingUpstream = control.pendingUpstream ? control.pendingUpstream + 1 : 1; + if ('upstreamCount' in control) { + control.upstreamCount += 1; // count changes we originated ourselves + console.log('upstream count up to : ' + control.upstreamCount); + } -SafeBuffer.allocUnsafeSlow = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - return buffer.SlowBuffer(size) -} + this._fire(doc.uri, query, function (uri, success, body, xhr) { + xhr.elapsedTime_ms = Date.now() - startTime; + console.log(' sparql: Return ' + (success ? 'success' : 'FAILURE ' + xhr.status) + ' elapsed ' + xhr.elapsedTime_ms + 'ms'); + if (success) { + try { + kb.remove(ds); + } catch (e) { + success = false; + body = 'Remote Ok BUT error deleting ' + ds.length + ' from store!!! ' + e; + } // Add in any case -- help recover from weirdness?? + for (var i = 0; i < is.length; i++) { + kb.add(is[i].subject, is[i].predicate, is[i].object, doc); + } + } -},{"buffer":5}],100:[function(_dereq_,module,exports){ -(function (Buffer){ -;(function (sax) { // wrapper for non-node envs - sax.parser = function (strict, opt) { return new SAXParser(strict, opt) } - sax.SAXParser = SAXParser - sax.SAXStream = SAXStream - sax.createStream = createStream + callback(uri, success, body, xhr); + control.pendingUpstream -= 1; + // When upstream patches have been sent, reload state if downstream waiting + if (control.pendingUpstream === 0 && control.downstreamAction) { + var downstreamAction = control.downstreamAction; + delete control.downstreamAction; + console.log('delayed downstream action:'); + downstreamAction(doc); + } + }); + } else if (protocol.indexOf('DAV') >= 0) { + // The code below is derived from Kenny's UpdateCenter.js + documentString; + var request = kb.any(doc, this.ns.link('request')); + if (!request) { + throw new Error('No record of our HTTP GET request for document: ' + doc); + } // should not happen + var response = kb.any(request, this.ns.link('response')); + if (!response) { + return null; // throw "No record HTTP GET response for document: "+doc + } + var content_type = kb.the(response, this.ns.httph('content-type')).value; - // When we pass the MAX_BUFFER_LENGTH position, start checking for buffer overruns. - // When we check, schedule the next check for MAX_BUFFER_LENGTH - (max(buffer lengths)), - // since that's the earliest that a buffer overrun could occur. This way, checks are - // as rare as required, but as often as necessary to ensure never crossing this bound. - // Furthermore, buffers are only tested at most once per write(), so passing a very - // large string into write() might have undesirable effects, but this is manageable by - // the caller, so it is assumed to be safe. Thus, a call to write() may, in the extreme - // edge case, result in creating at most one complete copy of the string passed in. - // Set to Infinity to have unlimited buffers. - sax.MAX_BUFFER_LENGTH = 64 * 1024 + // prepare contents of revised document + newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // copy! + for (i = 0; i < ds.length; i++) { + Util.RDFArrayRemove(newSts, ds[i]); + } + for (i = 0; i < is.length; i++) { + newSts.push(is[i]); + } - var buffers = [ - 'comment', 'sgmlDecl', 'textNode', 'tagName', 'doctype', - 'procInstName', 'procInstBody', 'entity', 'attribName', - 'attribValue', 'cdata', 'script' - ] + // serialize to te appropriate format + sz = Serializer(kb); + sz.suggestNamespaces(kb.namespaces); + sz.setBase(doc.uri); // ?? beware of this - kenny (why? tim) + switch (content_type) { + case 'application/rdf+xml': + documentString = sz.statementsToXML(newSts); + break; + case 'text/n3': + case 'text/turtle': + case 'application/x-turtle': // Legacy + case 'application/n3': + // Legacy + documentString = sz.statementsToN3(newSts); + break; + default: + throw new Error('Content-type ' + content_type + ' not supported for data write'); + } - sax.EVENTS = [ - 'text', - 'processinginstruction', - 'sgmldeclaration', - 'doctype', - 'comment', - 'opentagstart', - 'attribute', - 'opentag', - 'closetag', - 'opencdata', - 'cdata', - 'closecdata', - 'error', - 'end', - 'ready', - 'script', - 'opennamespace', - 'closenamespace' - ] + // Write the new version back - function SAXParser (strict, opt) { - if (!(this instanceof SAXParser)) { - return new SAXParser(strict, opt) - } + var candidateTarget = kb.the(response, this.ns.httph('content-location')); + var targetURI; + if (candidateTarget) { + targetURI = uriJoin(candidateTarget.value, targetURI); + } + var xhr = Util.XMLHTTPFactory(); + xhr.options = {}; + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + // formula from sparqlUpdate.js, what about redirects? + var success = !xhr.status || xhr.status >= 200 && xhr.status < 300; + if (success) { + for (var i = 0; i < ds.length; i++) { + kb.remove(ds[i]); + } + for (i = 0; i < is.length; i++) { + kb.add(is[i].subject, is[i].predicate, is[i].object, doc); + } + } + callback(doc.uri, success, xhr.responseText); + } + }; + xhr.open('PUT', targetURI, true); + // assume the server does PUT content-negotiation. + xhr.setRequestHeader('Content-type', content_type); // OK? + xhr.send(documentString); + } else { + if (protocol.indexOf('LOCALFILE') >= 0) { + try { + console.log('Writing back to local file\n'); + // See http://simon-jung.blogspot.com/2007/10/firefox-extension-file-io.html + // prepare contents of revised document + newSts = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // copy! + for (i = 0; i < ds.length; i++) { + Util.RDFArrayRemove(newSts, ds[i]); + } + for (i = 0; i < is.length; i++) { + newSts.push(is[i]); + } + // serialize to the appropriate format + documentString; + sz = Serializer(kb); + sz.suggestNamespaces(kb.namespaces); + sz.setBase(doc.uri); // ?? beware of this - kenny (why? tim) + var dot = doc.uri.lastIndexOf('.'); + if (dot < 1) { + throw new Error('Rewriting file: No filename extension: ' + doc.uri); + } + var ext = doc.uri.slice(dot + 1); + switch (ext) { + case 'rdf': + case 'owl': // Just my experence ...@@ we should keep the format in which it was parsed + case 'xml': + documentString = sz.statementsToXML(newSts); + break; + case 'n3': + case 'nt': + case 'ttl': + documentString = sz.statementsToN3(newSts); + break; + default: + throw new Error('File extension .' + ext + ' not supported for data write'); + } + // Write the new version back + // create component for file writing + console.log('Writing back: <<<' + documentString + '>>>'); + var filename = doc.uri.slice(7); // chop off file:// leaving /path + // console.log("Writeback: Filename: "+filename+"\n") + var file = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile); + file.initWithPath(filename); + if (!file.exists()) { + throw new Error('Rewriting file <' + doc.uri + '> but it does not exist!'); + } + // { + // file.create( Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 420) + // } + // create file output stream and use write/create/truncate mode + // 0x02 writing, 0x08 create file, 0x20 truncate length if exist + var stream = Components.classes['@mozilla.org/network/file-output-stream;1'].createInstance(Components.interfaces.nsIFileOutputStream); - var parser = this - clearBuffers(parser) - parser.q = parser.c = '' - parser.bufferCheckPosition = sax.MAX_BUFFER_LENGTH - parser.opt = opt || {} - parser.opt.lowercase = parser.opt.lowercase || parser.opt.lowercasetags - parser.looseCase = parser.opt.lowercase ? 'toLowerCase' : 'toUpperCase' - parser.tags = [] - parser.closed = parser.closedRoot = parser.sawRoot = false - parser.tag = parser.error = null - parser.strict = !!strict - parser.noscript = !!(strict || parser.opt.noscript) - parser.state = S.BEGIN - parser.strictEntities = parser.opt.strictEntities - parser.ENTITIES = parser.strictEntities ? Object.create(sax.XML_ENTITIES) : Object.create(sax.ENTITIES) - parser.attribList = [] + // Various JS systems object to 0666 in struct mode as dangerous + stream.init(file, 0x02 | 0x08 | 0x20, parseInt('0666', 8), 0); - // namespaces form a prototype chain. - // it always points at the current tag, - // which protos to its parent tag. - if (parser.opt.xmlns) { - parser.ns = Object.create(rootNS) - } + // write data to file then close output stream + stream.write(documentString, documentString.length); + stream.close(); - // mostly just for error reporting - parser.trackPosition = parser.opt.position !== false - if (parser.trackPosition) { - parser.position = parser.line = parser.column = 0 + for (i = 0; i < ds.length; i++) { + kb.remove(ds[i]); + } + for (i = 0; i < is.length; i++) { + kb.add(is[i].subject, is[i].predicate, is[i].object, doc); + } + callback(doc.uri, true, ''); // success! + } catch (e) { + callback(doc.uri, false, 'Exception trying to write back file <' + doc.uri + '>\n' + // + tabulator.Util.stackString(e)) + ); + } + } else { + throw new Error("Unhandled edit method: '" + protocol + "' for " + doc); + } + } + } catch (e) { + callback(undefined, false, 'Exception in update: ' + e + '\n' + $rdf.Util.stackString(e)); } - emit(parser, 'onready') - } + }; // wnd update - if (!Object.create) { - Object.create = function (o) { - function F () {} - F.prototype = o - var newf = new F() - return newf - } - } + // This suitable for an inital creation of a document + // + // data: string, or array of statements + // + sparql.prototype.put = function (doc, data, content_type, callback) { + var documentString; + var kb = this.store; - if (!Object.keys) { - Object.keys = function (o) { - var a = [] - for (var i in o) if (o.hasOwnProperty(i)) a.push(i) - return a + if ((typeof data === 'undefined' ? 'undefined' : _typeof(data)) === _typeof('')) { + documentString = data; + } else { + // serialize to te appropriate format + var sz = Serializer(kb); + sz.suggestNamespaces(kb.namespaces); + sz.setBase(doc.uri); + switch (content_type) { + case 'application/rdf+xml': + documentString = sz.statementsToXML(data); + break; + case 'text/n3': + case 'text/turtle': + case 'application/x-turtle': // Legacy + case 'application/n3': + // Legacy + documentString = sz.statementsToN3(data); + break; + default: + throw new Error('Content-type ' + content_type + ' not supported for data PUT'); + } } - } - - function checkBufferLength (parser) { - var maxAllowed = Math.max(sax.MAX_BUFFER_LENGTH, 10) - var maxActual = 0 - for (var i = 0, l = buffers.length; i < l; i++) { - var len = parser[buffers[i]].length - if (len > maxAllowed) { - // Text/cdata nodes can get big, and since they're buffered, - // we can get here under normal conditions. - // Avoid issues by emitting the text node now, - // so at least it won't get any bigger. - switch (buffers[i]) { - case 'textNode': - closeText(parser) - break + var xhr = Util.XMLHTTPFactory(); + xhr.options = {}; + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + // formula from sparqlUpdate.js, what about redirects? + var success = !xhr.status || xhr.status >= 200 && xhr.status < 300; + if (success && typeof data !== 'string') { + data.map(function (st) { + kb.addStatement(st); + }); + // kb.fetcher.requested[doc.uri] = true // as though fetched + } + if (success) { + delete kb.fetcher.nonexistant[doc.uri]; + delete kb.fetcher.requested[doc.uri]; + // @@ later we can fake it has been requestd if put gives us the header sand we save them. + } + callback(doc.uri, success, xhr.responseText, xhr); + } + }; + xhr.open('PUT', doc.uri, true); + xhr.setRequestHeader('Content-type', content_type); + xhr.send(documentString); + }; - case 'cdata': - emitNode(parser, 'oncdata', parser.cdata) - parser.cdata = '' - break + // Reload a document. + // + // Fast and cheap, no metaata + // Measure times for the document + // Load it provisionally + // Don't delete the statemenst before the load, or it will leave a broken document + // in the meantime. - case 'script': - emitNode(parser, 'onscript', parser.script) - parser.script = '' - break + sparql.prototype.reload = function (kb, doc, callback) { + var startTime = Date.now(); + // force sets no-cache and + kb.fetcher.nowOrWhenFetched(doc.uri, { force: true, noMeta: true, clearPreviousData: true }, function (ok, body, xhr) { + if (!ok) { + console.log(' ERROR reloading data: ' + body); + callback(false, 'Error reloading data: ' + body, xhr); + } else if (xhr.onErrorWasCalled || xhr.status !== 200) { + console.log(' Non-HTTP error reloading data! onErrorWasCalled=' + xhr.onErrorWasCalled + ' status: ' + xhr.status); + callback(false, 'Non-HTTP error reloading data: ' + body, xhr); + } else { + var elapsedTime_ms = Date.now() - startTime; + if (!doc.reloadTime_total) doc.reloadTime_total = 0; + if (!doc.reloadTime_count) doc.reloadTime_count = 0; + doc.reloadTime_total += elapsedTime_ms; + doc.reloadTime_count += 1; + console.log(' Fetch took ' + elapsedTime_ms + 'ms, av. of ' + doc.reloadTime_count + ' = ' + doc.reloadTime_total / doc.reloadTime_count + 'ms.'); + callback(true); + } + }); + }; - default: - error(parser, 'Max buffer length exceeded: ' + buffers[i]) + sparql.prototype.oldReload = function (kb, doc, callback) { + var g2 = graph(); // A separate store to hold the data as we load it + var f2 = fetcher(g2); + var startTime = Date.now(); + // force sets no-cache and + f2.nowOrWhenFetched(doc.uri, { force: true, noMeta: true, clearPreviousData: true }, function (ok, body, xhr) { + if (!ok) { + console.log(' ERROR reloading data: ' + body); + callback(false, 'Error reloading data: ' + body, xhr); + } else if (xhr.onErrorWasCalled || xhr.status !== 200) { + console.log(' Non-HTTP error reloading data! onErrorWasCalled=' + xhr.onErrorWasCalled + ' status: ' + xhr.status); + callback(false, 'Non-HTTP error reloading data: ' + body, xhr); + } else { + var sts1 = kb.statementsMatching(undefined, undefined, undefined, doc).slice(); // Take a copy!! + var sts2 = g2.statementsMatching(undefined, undefined, undefined, doc).slice(); + console.log(' replacing ' + sts1.length + ' with ' + sts2.length + ' out of total statements ' + kb.statements.length); + kb.remove(sts1); + kb.add(sts2); + var elapsedTime_ms = Date.now() - startTime; + if (sts2.length === 0) { + console.log('????????????????? 0000000'); } + if (!doc.reloadTime_total) doc.reloadTime_total = 0; + if (!doc.reloadTime_count) doc.reloadTime_count = 0; + doc.reloadTime_total += elapsedTime_ms; + doc.reloadTime_count += 1; + console.log(' fetch took ' + elapsedTime_ms + 'ms, av. of ' + doc.reloadTime_count + ' = ' + doc.reloadTime_total / doc.reloadTime_count + 'ms.'); + callback(true); } - maxActual = Math.max(maxActual, len) - } - // schedule the next check for the earliest possible buffer overrun. - var m = sax.MAX_BUFFER_LENGTH - maxActual - parser.bufferCheckPosition = m + parser.position - } + }); + }; + return sparql; +}(); - function clearBuffers (parser) { - for (var i = 0, l = buffers.length; i < l; i++) { - parser[buffers[i]] = '' - } - } +module.exports = UpdateManager; +},{"./data-factory":243,"./fetcher":246,"./indexed-formula":249,"./namespace":255,"./serializer":264,"./uri":269,"./util":270}],268:[function(_dereq_,module,exports){ +'use strict'; - function flushBuffers (parser) { - closeText(parser) - if (parser.cdata !== '') { - emitNode(parser, 'oncdata', parser.cdata) - parser.cdata = '' - } - if (parser.script !== '') { - emitNode(parser, 'onscript', parser.script) - parser.script = '' - } - } +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - SAXParser.prototype = { - end: function () { end(this) }, - write: write, - resume: function () { this.error = null; return this }, - close: function () { return this.write(null) }, - flush: function () { flushBuffers(this) } - } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - var Stream - try { - Stream = _dereq_('stream').Stream - } catch (ex) { - Stream = function () {} - } +/* + * Updates-Via + */ +var namedNode = _dereq_('./data-factory').namedNode; - var streamWraps = sax.EVENTS.filter(function (ev) { - return ev !== 'error' && ev !== 'end' - }) +var UpdatesSocket = function () { + function UpdatesSocket(parent, via) { + _classCallCheck(this, UpdatesSocket); - function createStream (strict, opt) { - return new SAXStream(strict, opt) + this.parent = parent; + this.via = via; + this.connected = false; + this.pending = {}; + this.subscribed = {}; + this.socket = {}; + try { + this.socket = new WebSocket(via); + this.socket.onopen = this.onOpen; + this.socket.onclose = this.onClose; + this.socket.onmessage = this.onMessage; + this.socket.onerror = this.onError; + } catch (error) { + this.onError(error); + } } - function SAXStream (strict, opt) { - if (!(this instanceof SAXStream)) { - return new SAXStream(strict, opt) + _createClass(UpdatesSocket, [{ + key: '_decode', + value: function _decode(q) { + var elt; + var i; + var k; + var r; + var ref; + var ref1; + var v; + r = {}; + ref = function () { + var j, len, ref, results; + ref = q.split('&'); + results = []; + for (j = 0, len = ref.length; j < len; j++) { + elt = ref[j]; + results.push(elt.split('=')); + } + return results; + }(); + for (i in ref) { + elt = ref[i]; + ref1 = [decodeURIComponent(elt[0]), decodeURIComponent(elt[1])]; + k = ref1[0]; + v = ref1[1]; + if (r[k] == null) { + r[k] = []; + } + r[k].push(v); + } + return r; } - - Stream.apply(this) - - this._parser = new SAXParser(strict, opt) - this.writable = true - this.readable = true - - var me = this - - this._parser.onend = function () { - me.emit('end') + }, { + key: '_send', + value: function _send(method, uri, data) { + var base, message; + message = [method, uri, data].join(' '); + return typeof (base = this.socket).send === 'function' ? base.send(message) : void 0; + } + }, { + key: '_subscribe', + value: function _subscribe(uri) { + this._send('sub', uri, ''); + this.subscribed[uri] = true; + return this.subscribed[uri]; } - - this._parser.onerror = function (er) { - me.emit('error', er) - - // if didn't throw, then means error was handled. - // go ahead and clear error, so we can write again. - me._parser.error = null + }, { + key: 'onClose', + value: function onClose(e) { + var uri; + this.connected = false; + for (uri in this.subscribed) { + this.pending[uri] = true; + } + this.subscribed = {}; + return this.subscribed; } - - this._decoder = null - - streamWraps.forEach(function (ev) { - Object.defineProperty(me, 'on' + ev, { - get: function () { - return me._parser['on' + ev] - }, - set: function (h) { - if (!h) { - me.removeAllListeners(ev) - me._parser['on' + ev] = h - return h - } - me.on(ev, h) - }, - enumerable: true, - configurable: false - }) - }) - } - - SAXStream.prototype = Object.create(Stream.prototype, { - constructor: { - value: SAXStream + }, { + key: 'onError', + value: function onError(e) { + throw new Error('onError' + e); } - }) - - SAXStream.prototype.write = function (data) { - if (typeof Buffer === 'function' && - typeof Buffer.isBuffer === 'function' && - Buffer.isBuffer(data)) { - if (!this._decoder) { - var SD = _dereq_('string_decoder').StringDecoder - this._decoder = new SD('utf8') + }, { + key: 'onMessage', + value: function onMessage(e) { + var base, message; + message = e.data.split(' '); + if (message[0] === 'ping') { + return typeof (base = this.socket).send === 'function' ? base.send('pong ' + message.slice(1).join(' ')) : void 0; + } else if (message[0] === 'pub') { + return this.parent.onUpdate(message[1], this._decode(message[2])); } - data = this._decoder.write(data) } - - this._parser.write(data.toString()) - this.emit('data', data) - return true - } - - SAXStream.prototype.end = function (chunk) { - if (chunk && chunk.length) { - this.write(chunk) + }, { + key: 'onOpen', + value: function onOpen(e) { + var results, uri; + this.connected = true; + results = []; + for (uri in this.pending) { + delete this.pending[uri]; + results.push(this._subscribe(uri)); + } + return results; } - this._parser.end() - return true - } - - SAXStream.prototype.on = function (ev, handler) { - var me = this - if (!me._parser['on' + ev] && streamWraps.indexOf(ev) !== -1) { - me._parser['on' + ev] = function () { - var args = arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments) - args.splice(0, 0, ev) - me.emit.apply(me, args) + }, { + key: 'subscribe', + value: function subscribe(uri) { + if (this.connected) { + return this._subscribe(uri); + } else { + this.pending[uri] = true; + return this.pending[uri]; } } + }]); - return Stream.prototype.on.call(me, ev, handler) - } - - // this really needs to be replaced with character classes. - // XML allows all manner of ridiculous numbers and digits. - var CDATA = '[CDATA[' - var DOCTYPE = 'DOCTYPE' - var XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace' - var XMLNS_NAMESPACE = 'http://www.w3.org/2000/xmlns/' - var rootNS = { xml: XML_NAMESPACE, xmlns: XMLNS_NAMESPACE } - - // http://www.w3.org/TR/REC-xml/#NT-NameStartChar - // This implementation works on strings, a single character at a time - // as such, it cannot ever support astral-plane characters (10000-EFFFF) - // without a significant breaking change to either this parser, or the - // JavaScript language. Implementation of an emoji-capable xml parser - // is left as an exercise for the reader. - var nameStart = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/ - - var nameBody = /[:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/ - - var entityStart = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/ - var entityBody = /[#:_A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u00B7\u0300-\u036F\u203F-\u2040.\d-]/ - - function isWhitespace (c) { - return c === ' ' || c === '\n' || c === '\r' || c === '\t' - } + return UpdatesSocket; +}(); - function isQuote (c) { - return c === '"' || c === '\'' - } +var UpdatesVia = function () { + function UpdatesVia(fetcher) { + _classCallCheck(this, UpdatesVia); - function isAttribEnd (c) { - return c === '>' || isWhitespace(c) + this.fetcher = fetcher; + this.graph = {}; + this.via = {}; + this.fetcher.addCallback('headers', this.onHeaders); } - function isMatch (regex, c) { - return regex.test(c) - } + _createClass(UpdatesVia, [{ + key: 'onHeaders', + value: function onHeaders(d) { + var etag, uri, via; + if (d.headers == null) { + return true; + } + if (typeof WebSocket === 'undefined' || WebSocket === null) { + return true; + } + etag = d.headers['etag']; + via = d.headers['updates-via']; + uri = d.uri; + if (etag && via) { + this.graph[uri] = { + etag: etag, + via: via + }; + this.register(via, uri); + } + return true; + } + }, { + key: 'onUpdate', + value: function onUpdate(uri, d) { + return this.fetcher.refresh(namedNode(uri)); + } + }, { + key: 'register', + value: function register(via, uri) { + if (this.via[via] == null) { + this.via[via] = new UpdatesSocket(this, via); + } + return this.via[via].subscribe(uri); + } + }]); - function notMatch (regex, c) { - return !isMatch(regex, c) - } + return UpdatesVia; +}(); - var S = 0 - sax.STATE = { - BEGIN: S++, // leading byte order mark or whitespace - BEGIN_WHITESPACE: S++, // leading whitespace - TEXT: S++, // general stuff - TEXT_ENTITY: S++, // & and such. - OPEN_WAKA: S++, // < - SGML_DECL: S++, // - SCRIPT: S++, //