diff --git a/README.md b/README.md index 965732c8..7dc91641 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,9 @@ edge.data('bendPointPositions'); `sbgnviz.register(options)` Register with libraries before creating instances +`sbgnviz.validMapProperties` +A lookup object for valid map properties. + `var instance = sbgnviz(options)` Creates an extension instance with the given options @@ -178,8 +181,8 @@ Loads the given sbgnml file. Optionally apply a callback function upon loading. `instance.loadSBGNMLText(textData)` Loads a graph from the given text data in sbgnml format. -`instance.saveAsSbgnml(filename)` -Exports the current graph to an sbgnml file with the given filename. +`instance.saveAsSbgnml(filename[, version])` +Exports the current graph to an sbgnml file with the given filename. A SBGN-ML version can be provided, either 0.2 or 0.3. No version defaults to 0.3. `instance.enablePorts()` Enable node ports. diff --git a/package.json b/package.json index 76c12fd3..f0589d7e 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "cytoscape": "iVis-at-Bilkent/cytoscape.js#unstable" }, "dependencies": { - "libsbgn.js": "^0.1.3", + "libsbgn.js": "github:sbgn/libsbgn.js#master", "pretty-data": "^0.40.0", "xml2js": "^0.4.17" }, diff --git a/sbgnviz.js b/sbgnviz.js index 3b065bff..6316dc00 100644 --- a/sbgnviz.js +++ b/sbgnviz.js @@ -1126,137 +1126,11 @@ }).call(this,_dereq_('_process')) -},{"_process":43}],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":43}],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,17158 +4101,14786 @@ 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":108}],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)); + // object stream flag to indicate whether or not this stream + // contains buffers or objects. + this.objectMode = !!options.objectMode; - // make property an array if value not present or always an array - if(!_isArray(subject[property]) && - (!hasValue || options.propertyIsArray)) { - subject[property] = [subject[property]]; - } + if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode; - // add new value - if(!hasValue) { - subject[property].push(value); - } - } else { - // add new value as set or single value - subject[property] = options.propertyIsArray ? [value] : value; - } -}; + // 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; -/** - * 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; -}; + // cast to ints. + this.highWaterMark = Math.floor(this.highWaterMark); -/** - * Removes a property from a subject. - * - * @param subject the subject. - * @param property the property. - */ -jsonld.removeProperty = function(subject, property) { - delete subject[property]; -}; + // if _final has been called + this.finalCalled = false; -/** - * 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; - } + // 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; - // filter out value - var values = jsonld.getValues(subject, property).filter(function(e) { - return !jsonld.compareValues(e, value); - }); + // has it been destroyed + this.destroyed = false; - if(values.length === 0) { - jsonld.removeProperty(subject, property); - } else if(values.length === 1 && !options.propertyIsArray) { - subject[property] = values[0]; - } else { - subject[property] = values; - } -}; + // 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; -/** - * 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; - } + // 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'; - // 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; - } + // 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; - // 3. equal @ids - if(_isObject(v1) && ('@id' in v1) && _isObject(v2) && ('@id' in v2)) { - return v1['@id'] === v2['@id']; - } + // a flag to see when we're in the middle of a write. + this.writing = false; - return false; -}; + // when true all writes will be buffered until .uncork() call + this.corked = 0; -/** - * 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; + // 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; - // return null for invalid key - if(key === null) { - return rval; - } + // 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 default language - if(type === '@language' && (type in ctx)) { - rval = ctx[type]; - } + // the callback that's passed to _write(chunk,cb) + this.onwrite = function (er) { + onwrite(stream, er); + }; - // get specific entry information - if(ctx.mappings[key]) { - var entry = ctx.mappings[key]; + // the callback that the user supplies to write(chunk,encoding,cb) + this.writecb = null; - if(_isUndefined(type)) { - // return whole entry - rval = entry; - } else if(type in entry) { - // return entry value for type - rval = entry[type]; - } - } + // the amount that is being written when _write is called. + this.writelen = 0; - return rval; -}; + this.bufferedRequest = null; + this.lastBufferedRequest = null; -/** 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; -}; - -/** - * 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. + source.on('data', ondata); - // Note: Optimize by generating non-normalized blank node map concurrently. - var nonNormalized = {}; - - 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); - } - - // 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); - } - - // 5.4.5.2) Use the Issue Identifier algorithm, passing issuer - // copy and related and append the result to path. - path += issuerCopy.getId(related); - - // 5.4.5.3) Append <, the hash in result, and > to path. - path += '<' + result.hash + '>'; - - // 5.4.5.4) Set issuer copy to the identifier issuer in - // result. - issuerCopy = result.issuer; +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.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); - } +var ClientRequest = module.exports = function (opts) { + var self = this + stream.Writable.call(self) - // 5.5) Append chosen path to data to hash. - md.update(chosenPath); + 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.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}); - }); -}; + 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) -// helper for creating hash to related blank nodes map -Normalize.prototype.createHashToRelated = function(id, issuer, callback) { - var self = this; + self.on('finish', function () { + self._onFinish() + }) +} - // 1) Create a hash to related blank nodes map for storing hashes that - // identify related blank nodes. - var hashToRelated = {}; +inherits(ClientRequest, stream.Writable) - // 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.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 - // 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); - }); -}; + self._headers[lowerName] = { + name: name, + value: value + } +} -// 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); - } -}; +ClientRequest.prototype.getHeader = function (name) { + var self = this + return self._headers[name.toLowerCase()].value +} -return Normalize; +ClientRequest.prototype.removeHeader = function (name) { + var self = this + delete self._headers[name.toLowerCase()] +} -})(); // end of define URDNA2015 +ClientRequest.prototype._onFinish = function () { + var self = this -/////////////////////////////// DEFINE URGNA2012 ////////////////////////////// + if (self._destroyed) + return + var opts = self._opts -var URGNA2012 = (function() { + 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() + } + } -var Normalize = function(options) { - URDNA2015.call(this, options); - this.name = 'URGNA2012'; -}; -Normalize.prototype = new URDNA2015(); + if (self._mode === 'fetch') { + var headers = keys(headersObj).map(function (name) { + return [headersObj[name].name, headersObj[name].value] + }) -// 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; -}; + 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 + } -// helper for getting a related predicate -Normalize.prototype.getRelatedPredicate = function(quad) { - return quad.predicate.value; -}; + // Can't set responseType on really old browsers + if ('responseType' in xhr) + xhr.responseType = self._mode.split(':')[0] -// helper for creating hash to related blank nodes map -Normalize.prototype.createHashToRelated = function(id, issuer, callback) { - var self = this; + if ('withCredentials' in xhr) + xhr.withCredentials = !!opts.withCredentials - // 1) Create a hash to related blank nodes map for storing hashes that - // identify related blank nodes. - var hashToRelated = {}; + if (self._mode === 'text' && 'overrideMimeType' in xhr) + xhr.overrideMimeType('text/plain; charset=x-user-defined') - // 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; + foreach(keys(headersObj), function (name) { + xhr.setRequestHeader(headersObj[name].name, headersObj[name].value) + }) - // 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); - }); -}; + 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() + } + } -return Normalize; + xhr.onerror = function () { + if (self._destroyed) + return + self.emit('error', new Error('XHR error')) + } -})(); // end of define URGNA2012 + try { + xhr.send(body) + } catch (err) { + process.nextTick(function () { + self.emit('error', err) + }) + return + } + } +} /** - * 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. + * 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 _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; - } +function statusValid (xhr) { + try { + return (xhr.status !== null) + } catch (e) { + return false + } +} - // add non-object to list - if(!_isObject(input)) { - if(list) { - list.push(input); - } - return; - } +ClientRequest.prototype._onXHRProgress = 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 (!statusValid(self._xhr) || self._destroyed) + return - // Note: At this point, input must be a subject. + if (!self._response) + self._connect() - // 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); - } - } - } + self._response._onXHRProgress() +} - // get name for subject - if(_isUndefined(name)) { - name = _isBlankNode(input) ? issuer.getId(input['@id']) : input['@id']; - } +ClientRequest.prototype._connect = function () { + var self = this - // add subject reference to list - if(list) { - list.push({'@id': name}); - } + if (self._destroyed) + return - // 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]; + self._response = new IncomingMessage(self._xhr, self._fetchResponse, self._mode) + self.emit('response', self._response) +} - // skip @id - if(property === '@id') { - continue; - } +ClientRequest.prototype._write = function (chunk, encoding, cb) { + var self = this - // 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; - } + self._body.push(chunk) + cb() +} - // 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.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 +} - // 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; - } - - // iterate over objects - var objects = input[property]; +ClientRequest.prototype.end = function (data, encoding, cb) { + var self = this + if (typeof data === 'function') { + cb = data + data = undefined + } - // if property is a bnode, assign it a new id - if(property.indexOf('_:') === 0) { - property = issuer.getId(property); - } + stream.Writable.prototype.end.call(self, data, encoding, cb) +} - // 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]; +ClientRequest.prototype.flushHeaders = function () {} +ClientRequest.prototype.setTimeout = function () {} +ClientRequest.prototype.setNoDelay = function () {} +ClientRequest.prototype.setSocketKeepAlive = function () {} - if(property === '@type') { - // rename @type blank nodes - o = (o.indexOf('_:') === 0) ? issuer.getId(o) : o; - } +// 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' +] - // 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']; +}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},_dereq_("buffer").Buffer) - // 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}); - } - } - } -} +},{"./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') -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; +var rStates = exports.readyStates = { + UNSENT: 0, + OPENED: 1, + HEADERS_RECEIVED: 2, + LOADING: 3, + DONE: 4 } -/** - * 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]; +var IncomingMessage = exports.IncomingMessage = function (xhr, response, mode) { + var self = this + stream.Readable.call(self) - // 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') - }; + self._mode = mode + self.headers = {} + self.rawHeaders = [] + self.trailers = {} + self.rawTrailers = [] - // filter out subjects that match the frame - var matches = _filterSubjects(state, subjects, frame, flags); + // 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') + }) + }) - // 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]; + if (mode === 'fetch') { + self._fetchResponse = response - 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.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]) + } - // add existing linked subject - _addFrameOutput(parent, property, state.link[id]); - continue; - } + // 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() - /* 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 = {}; - } + } else { + self._xhr = xhr + self._pos = 0 - // start output for subject - var output = {}; - output['@id'] = id; - state.link[id] = output; + 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 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; - } + 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 + } + } +} - // 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}; - } +inherits(IncomingMessage, stream.Readable) - // push matching subject onto stack to enable circular embed checks - state.subjectStack.push(subject); +IncomingMessage.prototype._read = function () {} - // iterate over subject properties - var props = Object.keys(subject).sort(); - for(var i = 0; i < props.length; i++) { - var prop = props[i]; +IncomingMessage.prototype._onXHRProgress = function () { + var self = this - // copy keywords to output - if(_isKeyword(prop)) { - output[prop] = _clone(subject[prop]); - continue; - } + var xhr = self._xhr - // explicit is on and property isn't in the frame, skip processing - if(flags.explicit && !(prop in frame)) { - continue; - } + 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 - // add objects - var objects = subject[prop]; - for(var oi = 0; oi < objects.length; ++oi) { - var o = objects[oi]; + 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 + } - // recurse into list - if(_isList(o)) { - // add empty list - var list = {'@list': []}; - _addFrameOutput(output, prop, list); + // The ms-stream case handles end separately in reader.onload() + if (self._xhr.readyState === rStates.DONE && self._mode !== 'ms-stream') { + self.push(null) + } +} - // 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; - } +}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},_dereq_("buffer").Buffer) - 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)); - } - } - } +},{"./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" +} - // handle defaults - var props = Object.keys(frame).sort(); - for(var i = 0; i < props.length; ++i) { - var prop = props[i]; +},{}],42:[function(_dereq_,module,exports){ - // skip keywords - if(_isKeyword(prop)) { - continue; - } +var hasOwn = Object.prototype.hasOwnProperty; +var toString = Object.prototype.toString; - // 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']); +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(!_isArray(preserve)) { - preserve = [preserve]; + } else { + for (var k in obj) { + if (hasOwn.call(obj, k)) { + fn.call(ctx, obj[k], k, obj); + } } - output[prop] = [{'@preserve': preserve}]; - } } +}; - // add output to parent - _addFrameOutput(parent, property, output); - // pop matching subject from circular ref-checking stack - state.subjectStack.pop(); +},{}],43:[function(_dereq_,module,exports){ + +var indexOf = [].indexOf; + +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}); - } -} -/** - * 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; + // 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 = '/'; } - // ensure value is interpreted as a string - value = String(value); - - // define term dependency if not defined - if(localCtx && value in localCtx && defined[value] !== true) { - _createTermDefinition(activeCtx, localCtx, value, defined); + //to support http.request + if (this.pathname || this.search) { + var p = this.pathname || ''; + var s = this.search || ''; + this.path = p + s; } - relativeTo = relativeTo || {}; - if(relativeTo.vocab) { - var mapping = activeCtx.mappings[value]; + // finally, reconstruct the href based on what has been validated. + this.href = this.format(); + return this; +}; - // value is explicitly ignored with a null mapping - if(mapping === null) { - return null; - } +// 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(); +} - if(mapping) { - // value is a term - return mapping['@id']; - } +Url.prototype.format = function() { + var auth = this.auth || ''; + if (auth) { + auth = encodeURIComponent(auth); + auth = auth.replace(/%3A/i, ':'); + auth += '@'; } - // 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 protocol = this.protocol || '', + pathname = this.pathname || '', + hash = this.hash || '', + host = false, + query = ''; - // do not expand blank nodes (prefix of '_') or already-absolute - // IRIs (suffix of '//') - if(prefix === '_' || suffix.indexOf('//') === 0) { - return value; + 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; } + } - // prefix dependency not defined, define it - if(localCtx && prefix in localCtx) { - _createTermDefinition(activeCtx, localCtx, prefix, defined); - } + if (this.query && + isObject(this.query) && + Object.keys(this.query).length) { + query = querystring.stringify(this.query); + } - // use mapping if prefix is defined - var mapping = activeCtx.mappings[prefix]; - if(mapping) { - return mapping['@id'] + suffix; - } + var search = this.search || (query && ('?' + query)) || ''; - // already absolute IRI - return value; - } + if (protocol && protocol.substr(-1) !== ':') protocol += ':'; - // prepend vocab - if(relativeTo.vocab && '@vocab' in activeCtx) { - return activeCtx['@vocab'] + value; + // 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 = ''; } - // prepend base - var rval = value; - if(relativeTo.base) { - rval = jsonld.prependBase(activeCtx['@base'], rval); - } + if (hash && hash.charAt(0) !== '#') hash = '#' + hash; + if (search && search.charAt(0) !== '?') search = '?' + search; - return rval; + pathname = pathname.replace(/[?#]/g, function(match) { + return encodeURIComponent(match); + }); + search = search.replace('#', '%23'); + + return protocol + host + pathname + search + hash; +}; + +function urlResolve(source, relative) { + return urlParse(source, false, true).resolve(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.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); +} + +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; - } - } -} + 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; + } + }; -return factory; + 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--; -}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},"/node_modules/jsonld/js") + if (state === lib$es6$promise$$internal$$REJECTED) { + lib$es6$promise$$internal$$reject(promise, value); + } else { + enumerator._result[i] = value; + } + } -},{"_process":43,"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 (enumerator._remaining === 0) { + lib$es6$promise$$internal$$fulfill(promise, enumerator._result); + } + }; -module.exports = pkg; + lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) { + var enumerator = this; -},{"./src/libsbgn":29}],20:[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; + 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; } - }; - -}).call(this); - -},{}],21:[function(_dereq_,module,exports){ -// Generated by CoffeeScript 1.12.7 -(function() { - "use strict"; - var builder, defaults, escapeCDATA, requiresCDATA, wrapCDATA, - hasProp = {}.hasOwnProperty; - - builder = _dereq_('xmlbuilder'); + 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; - defaults = _dereq_('./defaults').defaults; + var promise = new Constructor(lib$es6$promise$$internal$$noop); - requiresCDATA = function(entry) { - return typeof entry === "string" && (entry.indexOf('&') >= 0 || entry.indexOf('>') >= 0 || entry.indexOf('<') >= 0); - }; + if (!lib$es6$promise$utils$$isArray(entries)) { + lib$es6$promise$$internal$$reject(promise, new TypeError('You must pass an array to race.')); + return promise; + } - wrapCDATA = function(entry) { - return ""; - }; + var length = entries.length; - escapeCDATA = function(entry) { - return entry.replace(']]>', ']]]]>'); - }; + function onFulfillment(value) { + lib$es6$promise$$internal$$resolve(promise, value); + } - 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; + function onRejection(reason) { + lib$es6$promise$$internal$$reject(promise, reason); } - for (key in opts) { - if (!hasProp.call(opts, key)) continue; - value = opts[key]; - this.options[key] = value; + + 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); } + + 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; - 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; + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; } - 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); - }; - return Builder; + 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; - })(); + var lib$es6$promise$promise$$counter = 0; -}).call(this); + function lib$es6$promise$promise$$needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); + } -},{"./defaults":22,"xmlbuilder":146}],22:[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 + 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."); } - }; -}).call(this); + 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. -},{}],23:[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; + Terminology + ----------- - sax = _dereq_('sax'); + - `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. - events = _dereq_('events'); + A promise can be in one of three states: pending, fulfilled, or rejected. - bom = _dereq_('./bom'); + 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. - processors = _dereq_('./processors'); + 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. - setImmediate = _dereq_('timers').setImmediate; - defaults = _dereq_('./defaults').defaults; + Basic Usage: + ------------ - isEmpty = function(thing) { - return typeof thing === "object" && (thing != null) && Object.keys(thing).length === 0; - }; + ```js + var promise = new Promise(function(resolve, reject) { + // on success + resolve(value); - 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; - }; + // on failure + reject(reason); + }); - exports.Parser = (function(superClass) { - extend(Parser, superClass); + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` - 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(); - } + Advanced Usage: + --------------- - 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); - } + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + var xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + 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 + ']')); + } + } + }; + }); } - }; - Parser.prototype.assignOrPush = function(obj, key, newValue) { - if (!(key in obj)) { - if (!this.options.explicitArray) { - return obj[key] = newValue; - } else { - return obj[key] = [newValue]; + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @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 = []; + + if (lib$es6$promise$$internal$$noop !== resolver) { + if (!lib$es6$promise$utils$$isFunction(resolver)) { + lib$es6$promise$promise$$needsResolver(); } - } else { - if (!(obj[key] instanceof Array)) { - obj[key] = [obj[key]]; + + if (!(this instanceof lib$es6$promise$promise$$Promise)) { + lib$es6$promise$promise$$needsNew(); } - return obj[key].push(newValue); + + lib$es6$promise$$internal$$initializePromise(this, resolver); } - }; + } - 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 + 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; + + lib$es6$promise$promise$$Promise.prototype = { + constructor: lib$es6$promise$promise$$Promise, + + /** + 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. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why }); - 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); - } - }; - })(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 { - 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]; - } - } - 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); - }; + ``` - 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); - }); - 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; - } - } - }; + Chaining + -------- - return Parser; + 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. - })(events.EventEmitter); + ```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'` + }); - 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 = {}; - } - parser = new exports.Parser(options); - return parser.parseString(str, cb); - }; + 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. -}).call(this); + ```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 + }); + ``` -},{"./bom":20,"./defaults":22,"./processors":24,"events":10,"sax":106,"timers":113}],24:[function(_dereq_,module,exports){ -// Generated by CoffeeScript 1.12.7 -(function() { - "use strict"; - var prefixMatch; + Assimilation + ------------ - prefixMatch = new RegExp(/(?!xmlns)^.*:/); + 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*. - exports.normalize = function(str) { - return str.toLowerCase(); - }; + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` - exports.firstCharLowerCase = function(str) { - return str.charAt(0).toLowerCase() + str.slice(1); - }; + If the assimliated promise rejects, then the downstream promise will also reject. - exports.stripPrefix = function(str) { - return str.replace(prefixMatch, ''); - }; + ```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 + }); + ``` - exports.parseNumbers = function(str) { - if (!isNaN(str)) { - str = str % 1 === 0 ? parseInt(str, 10) : parseFloat(str); - } - return str; - }; + Simple Example + -------------- - exports.parseBooleans = function(str) { - if (/^(?:true|false)$/i.test(str)) { - str = str.toLowerCase() === 'true'; - } - return str; - }; + Synchronous Example -}).call(this); + ```javascript + var result; -},{}],25:[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; + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` - defaults = _dereq_('./defaults'); + Errback Example - builder = _dereq_('./builder'); + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` - parser = _dereq_('./parser'); + Promise Example; - processors = _dereq_('./processors'); + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` - exports.defaults = defaults.defaults; + Advanced Example + -------------- - exports.processors = processors; + Synchronous Example - exports.ValidationError = (function(superClass) { - extend(ValidationError, superClass); + ```javascript + var author, books; - function ValidationError(message) { - this.message = message; - } + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` - return ValidationError; + Errback Example - })(Error); + ```js - exports.Builder = builder.Builder; + function foundBooks(books) { - exports.Parser = parser.Parser; + } - exports.parseString = parser.parseString; + function failure(reason) { -}).call(this); + } -},{"./builder":21,"./defaults":22,"./parser":23,"./processors":24}],26:[function(_dereq_,module,exports){ -var N3 = _dereq_('n3'); + 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 ns = {}; + Promise Example; -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/"}; + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` -// pure shortcut function -ns.expandPrefix = function(prefix) { - return N3.Util.expandPrefixedName(prefix, ns.prefixes) -}; + @method then + @param {Function} onFulfilled + @param {Function} onRejected + Useful for tooling. + @return {Promise} + */ + then: function(onFulfillment, onRejection) { + var parent = this; + var state = parent._state; -// 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 (state === lib$es6$promise$$internal$$FULFILLED && !onFulfillment || state === lib$es6$promise$$internal$$REJECTED && !onRejection) { + return this; + } -controlledVocabularyList = [ - "bqmodel:is", - "bqmodel:isDerivedFrom", - "bqmodel:isDescribedBy", - "bqmodel:isInstanceOf", - "bqmodel:hasInstance", + var child = new this.constructor(lib$es6$promise$$internal$$noop); + var result = parent._result; - "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", + 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); + } - "sio:SIO_000223" -]; + return child; + }, -ns.isControlledVocabulary = {}; -for(var i=0; i 0; -}; + 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'); + } + } -ns.countBagElements = function(graph, subject) { - return graph.countTriples(subject, null, null) - 1; -}; + var P = local.Promise; -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] = []; - } + if (P && Object.prototype.toString.call(P.resolve()) === '[object Promise]' && !P.cast) { + return; + } - // 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; -}; + local.Promise = lib$es6$promise$promise$$default; + } + var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill; -/** - * 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)]; - } -}; + var lib$es6$promise$umd$$ES6Promise = { + 'Promise': lib$es6$promise$promise$$default, + 'polyfill': lib$es6$promise$polyfill$$default + }; -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; -}; + /* 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; + } -/** - * 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]); - } -}; + lib$es6$promise$polyfill$$default(); +}).call(this); -module.exports = ns; -},{"n3":31}],27:[function(_dereq_,module,exports){ + +}).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){ /** - * 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. + * A JavaScript implementation of the JSON-LD API. * - * 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. + * @author Dave Longley * - * # Controlled vocabulary + * @license BSD 3-Clause License + * Copyright (c) 2011-2015 Digital Bazaar, Inc. + * All rights reserved. * - * 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-- + * 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. * - * See {@link Extension} for more general information on extensions in the SBGN-ML format. + * 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. * - * You can access the following classes like this: libsbgn.annot.Annotation + * 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. * - * @module libsbgn-annotations - * @namespace libsbgn.annot -*/ - -var checkParams = _dereq_('./utilities').checkParams; -var $rdf = _dereq_('rdflib'); -var N3 = _dereq_('n3'); -var Util = _dereq_('./annotation-utils'); -var utils = _dereq_('./utilities'); - -var ns = {}; - -//ns.xmlns = "http://www.sbml.org/sbml/level3/version1/render/version1"; - -// ------- 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; -}; - -/** - * @param {RdfElement} rdfElement + * 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. */ -Annotation.prototype.setRdfElement = function(rdfElement) { - this.rdfElement = rdfElement; -}; +(function() { -Annotation.prototype.buildJsObj = function () { - var annotationJsonObj = {}; +// 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.rdfElement != null) { - annotationJsonObj = this.rdfElement.buildJsObj(); - } +// attaches jsonld API to the given object +var wrapper = function(jsonld) { - return annotationJsonObj; -}; +/* Core API */ /** - * @return {string} + * 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. */ -Annotation.prototype.toXML = function() { - return utils.buildString({annotation: this.buildJsObj()}) -}; - -Annotation.fromXML = function (string) { - var annotation; - function fn (err, result) { - annotation = Annotation.fromObj(result); - }; - utils.parseStringKeepPrefix(string, fn); - return annotation; -}; +jsonld.compact = function(input, ctx, options, callback) { + if(arguments.length < 2) { + return jsonld.nextTick(function() { + callback(new TypeError('Could not compact, too few arguments.')); + }); + } -Annotation.fromObj = function (jsObj) { - if (typeof jsObj.annotation == 'undefined') { - throw new Error("Bad XML provided, expected tagName annotation, got: " + Object.keys(jsObj)[0]); - } + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; - var annotation = new ns.Annotation(); - jsObj = jsObj.annotation; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return annotation; - } + if(ctx === null) { + return jsonld.nextTick(function() { + callback(new JsonLdError( + 'The compaction context must not be null.', + 'jsonld.CompactError', {code: 'invalid local context'})); + }); + } - // children - if(jsObj['rdf:RDF']) { - var obj = {}; - obj['rdf:RDF'] = jsObj['rdf:RDF'][0]; - var rdf = ns.RdfElement.fromObj(obj); - annotation.setRdfElement(rdf); - } + // nothing to compact + if(input === null) { + return jsonld.nextTick(function() { + callback(null, null); + }); + } - return annotation; -}; + // 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; + } -ns.Annotation = Annotation; -// ------- END ANNOTATION ------- + var expand = function(input, options, callback) { + if(options.skipExpansion) { + return jsonld.nextTick(function() { + callback(null, input); + }); + } + jsonld.expand(input, options, callback); + }; -// ------- 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; - } -}; + // 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})); + } -StoreObject.prototype.getCustomPropertiesOfId = function (id) { - return Util.getCustomPropertiesOfId(this.store, id); -}; + // 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})); + } -StoreObject.prototype.getAllIds = function () { - return Util.getAllIds(this.store); -}; + var compacted; + try { + // do compaction + compacted = new Processor().compact(activeCtx, null, expanded, options); + } catch(ex) { + return callback(ex); + } -StoreObject.prototype.addCustomProperty = function (id, kvObject) { - return Util.addCustomProperty(this.store, id, kvObject); -}; + cleanup(null, compacted, activeCtx, options); + }); + }); -StoreObject.prototype.getResourcesOfId = function(id) { - return Util.getResourcesOfId(this.store, id); -}; + // performs clean up after compaction + function cleanup(err, compacted, activeCtx, options) { + if(err) { + return callback(err); + } -StoreObject.prototype.addResource = function (id, kvObject) { - return Util.addResource(this.store, id, kvObject); -}; + 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]; + } -ns.StoreObject = StoreObject; -// ------- END STOREOBJECT ------- + // follow @context key + if(_isObject(ctx) && '@context' in ctx) { + ctx = ctx['@context']; + } -// ------- GLOBALSTORE ------- -var GlobalRdfStore = function (params) { - ns.StoreObject.call(this, params); -}; -GlobalRdfStore.prototype = Object.create(ns.StoreObject.prototype); -GlobalRdfStore.prototype.constructor = GlobalRdfStore; + // 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]); + } + } -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; - -RdfElement.uri = 'http://www.eisbm.org/'; - -/** - * @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; - } - - 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; - } + // remove array if only one context + var hasContext = (ctx.length > 0); + if(ctx.length === 1) { + ctx = ctx[0]; + } - function replaceParseType(string) { - var regexp = / rdf:parseType="Resource"/g; - return string.replace(regexp, ''); - } + // 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 replaceSlashInID(string) { - return string.replace(new RegExp(/rdf:about="\//g), 'rdf:about="'); - } - - var result = replaceSlashInID(replaceParseType(replaceLi(replaceBag(serialize)))); - - return result; + callback(null, compacted, activeCtx); + } }; /** - * @param {Element} xml - * @return {RdfElement} + * 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. */ -RdfElement.fromString = function (stringXml) { - - var rdfElement = new RdfElement(); - var graph = $rdf.graph(); +jsonld.expand = function(input, options, callback) { + if(arguments.length < 1) { + return jsonld.nextTick(function() { + callback(new TypeError('Could not expand, too few arguments.')); + }); + } - // 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'); + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; - var parser = N3.Parser(); - var store = N3.Store(); - store.addPrefixes(Util.prefixes); - store.addTriples(parser.parse(turtle)); - - rdfElement.store = store; + // set default options + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } + if(!('keepFreeFloatingNodes' in options)) { + options.keepFreeFloatingNodes = false; + } - return rdfElement; -}; + 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}); + }); -RdfElement.fromXML = function (string) { - var rdfElement; - function fn (err, result) { - rdfElement = RdfElement.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.parseStringKeepPrefix(string, fn); - return rdfElement; -}; + 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); + } -RdfElement.prototype.buildJsObj = function () { - var rdfElementJsObj; - function fn (err, result) { - rdfElementJsObj = result; - }; - utils.parseStringKeepPrefix(this.toXML(), fn); - return rdfElementJsObj; -}; + var expanded; + try { + var processor = new Processor(); + var activeCtx = _getInitialContext(options); + var document = input.document; + var remoteContext = input.remoteContext['@context']; -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]); - } + // process optional expandContext + if(input.expandContext) { + activeCtx = processor.processContext( + activeCtx, input.expandContext['@context'], options); + } - var rdfElement = new ns.RdfElement(); - jsObj = jsObj['rdf:RDF']; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return rdfElement; - } + // process remote context from HTTP Link Header + if(remoteContext) { + activeCtx = processor.processContext( + activeCtx, remoteContext, options); + } - var obj = {}; - obj['rdf:RDF'] = jsObj; - rdfElement = ns.RdfElement.fromString(utils.buildString(obj)); + // expand document + expanded = processor.expand( + activeCtx, null, document, options, false); - return rdfElement; -}; + // 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 = []; + } -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()); + // normalize to an array + if(!_isArray(expanded)) { + expanded = [expanded]; + } + } catch(ex) { + return callback(ex); + } + callback(null, expanded); + }); + } }; -ns.RdfElement = RdfElement; -// ------- END RDFELEMENT ------- - - -ns.rdflib = $rdf; -ns.Util = Util; - -module.exports = ns; - -},{"./annotation-utils":26,"./utilities":30,"n3":31,"rdflib":57}],28:[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 + * Performs JSON-LD flattening. * - * @module libsbgn-render - * @namespace libsbgn.render -*/ - -var utils = _dereq_('./utilities'); -var checkParams = utils.checkParams; -var xml2js = _dereq_('xml2js'); - -var ns = {}; + * @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.')); + }); + } -ns.xmlns = "http://www.sbml.org/sbml/level3/version1/render/version1"; + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } else if(typeof ctx === 'function') { + callback = ctx; + ctx = null; + options = {}; + } + options = options || {}; -// ------- 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; -}; + // set default options + if(!('base' in options)) { + options.base = (typeof input === 'string') ? input : ''; + } + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } -/** - * @return {Object} - xml2js formatted object - */ -ColorDefinition.prototype.buildJsObj = function () { - var colordefObj = {}; + // 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})); + } - // 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; -}; + var flattened; + try { + // do flattening + flattened = new Processor().flatten(_input); + } catch(ex) { + return callback(ex); + } -/** - * @return {string} - */ -ColorDefinition.prototype.toXML = function () { - return utils.buildString({colorDefinition: this.buildJsObj()}) -}; + if(ctx === null) { + return callback(null, flattened); + } -/** - * @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; + // 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 {ColorDefinition} + * 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. */ -ColorDefinition.fromObj = function (jsObj) { - if (typeof jsObj.colorDefinition == 'undefined') { - throw new Error("Bad XML provided, expected tagName colorDefinition, 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 colorDefinition = new ns.ColorDefinition(); - jsObj = jsObj.colorDefinition; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return colorDefinition; - } + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; - 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 = {}; -}; + // 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; -/** - * @param {ColorDefinition} colorDefinition - */ -ListOfColorDefinitions.prototype.addColorDefinition = function (colorDefinition) { - this.colorDefinitions.push(colorDefinition); - this.colorIndex[colorDefinition.id] = colorDefinition.value; -}; + 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}); + }); -/** - * Convenient method to get a color value directly. - * @param {string} id - * @return {string} - */ -ListOfColorDefinitions.prototype.getColorById = function (id) { - return this.colorIndex[id]; -}; + 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 = {}; + } -/** - * Convenient method to get all the color values in the list. - * @return {string[]} - */ -ListOfColorDefinitions.prototype.getAllColors = function () { - return Object.values(this.colorIndex); -}; + // 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})); + } -/** - * @return {Object} - xml2js formatted object - */ -ListOfColorDefinitions.prototype.buildJsObj = function () { - var listOfColorDefinitionsObj = {}; + // 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})); + } - for(var i=0; i < this.colorDefinitions.length; i++) { - if (i==0) { - listOfColorDefinitionsObj.colorDefinition = []; - } - listOfColorDefinitionsObj.colorDefinition.push(this.colorDefinitions[i].buildJsObj()); - } + var framed; + try { + // do framing + framed = new Processor().frame(expanded, expandedFrame, opts); + } catch(ex) { + return callback(ex); + } - return listOfColorDefinitionsObj; + // 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); + }); + }); + }); + } }; /** - * @return {string} + * **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. */ -ListOfColorDefinitions.prototype.toXML = function () { - return utils.buildString({listOfColorDefinitions: this.buildJsObj()}) +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 {String} string - * @return {ListOfColorDefinitions} + * **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. */ -ListOfColorDefinitions.fromXML = function (string) { - var listOfColorDefinitions; - function fn (err, result) { - listOfColorDefinitions = ListOfColorDefinitions.fromObj(result); - }; - utils.parseString(string, fn); - return listOfColorDefinitions; -}; +jsonld.objectify = function(input, ctx, options, callback) { + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; -/** - * @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]); - } + // set default options + if(!('base' in options)) { + options.base = (typeof input === 'string') ? input : ''; + } + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } - var listOfColorDefinitions = new ns.ListOfColorDefinitions(); - jsObj = jsObj.listOfColorDefinitions; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return listOfColorDefinitions; - } + // 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})); + } - // 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); - } - } + var flattened; + try { + // flatten the graph + flattened = new Processor().flatten(_input); + } catch(ex) { + return callback(ex); + } - return listOfColorDefinitions; -}; + // 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]; -ns.ListOfColorDefinitions = ListOfColorDefinitions; -// ------- END LISTOFCOLORDEFINITIONS ------- + var recurse = function(subject) { + // can't replace just a string + if(!_isObject(subject) && !_isArray(subject)) { + return; + } -// ------- 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; -}; + // bottom out recursion on re-visit + if(_isObject(subject)) { + if(recurse.visited[subject['@id']]) { + return; + } + recurse.visited[subject['@id']] = true; + } -/** - * @return {Object} - xml2js formatted object - */ -RenderGroup.prototype.buildJsObj = function () { - var renderGroupObj = {}; + // each array element *or* object key + for(var k in subject) { + var obj = subject[k]; + var isid = (jsonld.getContextValue(ctx, k, '@type') === '@id'); - // 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; -}; + // can't replace a non-object or non-array unless it's an @id + if(!_isArray(obj) && !_isObject(obj) && !isid) { + continue; + } -/** - * @return {string} - */ -RenderGroup.prototype.toXML = function () { - return utils.buildString({g: this.buildJsObj()}) -}; + 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); -/** - * @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; + 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); + }); + }); }; /** - * @param {Object} jsObj - xml2js formatted object - * @return {RenderGroup} + * 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. */ -RenderGroup.fromObj = function (jsObj) { - if (typeof jsObj.g == 'undefined') { - throw new Error("Bad XML provided, expected tagName g, got: " + Object.keys(jsObj)[0]); - } +jsonld.normalize = function(input, options, callback) { + if(arguments.length < 1) { + return jsonld.nextTick(function() { + callback(new TypeError('Could not normalize, too few arguments.')); + }); + } - var g = new ns.RenderGroup(); - jsObj = jsObj.g; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return g; - } + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; - 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; -}; + // 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; + } -ns.RenderGroup = RenderGroup; -// ------- END RENDERGROUP ------- + 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); + }); + } +}; -// ------- 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 + * 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. */ -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; -}; +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.')); + }); + } -/** - * @param {RenderGroup} renderGroup - */ -Style.prototype.setRenderGroup = function (renderGroup) { - this.renderGroup = renderGroup; -}; + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; -/** - * @return {string[]} - */ -Style.prototype.getIdListAsArray = function () { - return this.idList.split(' '); -} + // set default options + if(!('useRdfType' in options)) { + options.useRdfType = false; + } + if(!('useNativeTypes' in options)) { + options.useNativeTypes = false; + } -/** - * @param {string[]} idArray - */ -Style.prototype.setIdListFromArray = function (idArray) { - this.idList = idArray.join(' '); -} + if(!('format' in options) && _isString(dataset)) { + // set default format to nquads + if(!('format' in options)) { + options.format = 'application/nquads'; + } + } -/** - * 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 = {}; + 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; + }; + } - // 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); + 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); + } - // children - if(this.renderGroup != null) { - styleObj.g = this.renderGroup.buildJsObj(); - } - return styleObj; + function fromRDF(dataset, options, callback) { + // convert from RDF + new Processor().fromRDF(dataset, options, callback); + } + }); }; /** - * @return {string} + * 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. */ -Style.prototype.toXML = function () { - return utils.buildString({style: this.buildJsObj()}) +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.')); + }); + } + + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; + + // set default options + if(!('base' in options)) { + options.base = (typeof input === 'string') ? input : ''; + } + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } + + // 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})); + } + + 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); + }); }; /** - * @param {String} string - * @return {Style} + * **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. */ -Style.fromXML = function (string) { - var style; - function fn (err, result) { - style = Style.fromObj(result); - }; - utils.parseString(string, fn); - return style; +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.')); + }); + } + + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; + + // set default options + if(!('base' in options)) { + options.base = (typeof input === 'string') ? input : ''; + } + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } + + // 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 nodeMap; + try { + nodeMap = new Processor().createNodeMap(_input, options); + } catch(ex) { + return callback(ex); + } + + callback(null, nodeMap); + }); }; /** - * @param {Object} jsObj - xml2js formatted object - * @return {Style} + * **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. */ -Style.fromObj = function (jsObj) { - if (typeof jsObj.style == 'undefined') { - throw new Error("Bad XML provided, expected tagName style, got: " + Object.keys(jsObj)[0]); - } +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.')); + }); + } - var style = new ns.Style(); - jsObj = jsObj.style; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return style; - } + // get arguments + if(typeof options === 'function') { + callback = options; + options = {}; + } else if(typeof ctx === 'function') { + callback = ctx; + ctx = null; + options = {}; + } + options = options || {}; - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - style.id = attributes.id || null; - style.name = attributes.name || null; - style.idList = attributes.idList || null; - } + // 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 - if(jsObj.g) { - var g = ns.RenderGroup.fromObj({g: jsObj.g[0]}); - style.setRenderGroup(g); - } + 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 style; -}; + function merge(expanded) { + var mergeNodes = true; + if('mergeNodes' in options) { + mergeNodes = options.mergeNodes; + } -ns.Style = Style; -// ------- END STYLE ------- + var issuer = options.namer || options.issuer || new IdentifierIssuer('_:b'); + var graphs = {'@default': {}}; -// ------- LISTOFSTYLES ------- -/** - * Represents the <listOfStyles> element. - * @class - */ -var ListOfStyles = function() { - this.styles = []; -}; + 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 + '-') + }); -/** - * @param {Style} style - */ -ListOfStyles.prototype.addStyle = function (style) { - this.styles.push(style); -}; + // 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); -/** - * 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; -} + 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]; + } + } + } + } + } -/** - * @return {Object} - xml2js formatted object - */ -ListOfStyles.prototype.buildJsObj = function () { - var listOfStylesObj = {}; + // add all non-default graphs to default graph + defaultGraph = _mergeNodeMaps(graphs); + } catch(ex) { + return callback(ex); + } - for(var i=0; i < this.styles.length; i++) { - if (i==0) { - listOfStylesObj.style = []; - } - listOfStylesObj.style.push(this.styles[i].buildJsObj()); - } + // 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 listOfStylesObj; + 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); + }); + } }; /** - * @return {string} + * 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). */ -ListOfStyles.prototype.toXML = function () { - return utils.buildString({listOfStyles: this.buildJsObj()}) +jsonld.relabelBlankNodes = function(input, options) { + options = options || {}; + var issuer = options.namer || options.issuer || new IdentifierIssuer('_:b'); + return _labelBlankNodes(issuer, input); }; /** - * @param {String} string - * @return {ListOfStyles} + * Prepends a base IRI to the given relative IRI. + * + * @param base the base IRI. + * @param iri the relative IRI. + * + * @return the absolute IRI. */ -ListOfStyles.fromXML = function (string) { - var listOfStyles; - function fn (err, result) { - listOfStyles = ListOfStyles.fromObj(result); - }; - utils.parseString(string, fn); - return listOfStyles; +jsonld.prependBase = function(base, iri) { + return _prependBase(base, iri); }; /** - * @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 + * 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. */ -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; +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 {ListOfColorDefinitions} listOfColorDefinitions + * Deprecated default document loader. Use or override jsonld.documentLoader + * instead. */ -RenderInformation.prototype.setListOfColorDefinitions = function(listOfColorDefinitions) { - this.listOfColorDefinitions = listOfColorDefinitions; +jsonld.loadDocument = function(url, callback) { + var promise = jsonld.documentLoader(url, callback); + if(promise && 'then' in promise) { + promise.then(callback.bind(null, null), callback); + } }; -/** - * @param {ListOfStyles} listOfStyles - */ -RenderInformation.prototype.setListOfStyles = function(listOfStyles) { - this.listOfStyles = listOfStyles; -}; +/* 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. */ -RenderInformation.prototype.buildJsObj = function () { - var renderInformationObj = {}; +jsonld.promises = function(options) { + options = options || {}; + var slice = Array.prototype.slice; + var promisify = jsonld.promisify; - // 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); + // 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 = {}; + } - // children - if(this.listOfColorDefinitions != null) { - renderInformationObj.listOfColorDefinitions = this.listOfColorDefinitions.buildJsObj(); - } - if(this.listOfStyles != null) { - renderInformationObj.listOfStyles = this.listOfStyles.buildJsObj(); - } - return renderInformationObj; -}; + // 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 -/** - * @return {string} - */ -RenderInformation.prototype.toXML = function() { - return utils.buildString({renderInformation: this.buildJsObj()}) -}; + 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))); + }; -/** - * @param {String} string - * @return {RenderInformation} - */ -RenderInformation.fromXML = function (string) { - var renderInformation; - function fn (err, result) { - renderInformation = RenderInformation.fromObj(result); + 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))); }; - utils.parseString(string, fn); - return renderInformation; + 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; }; /** - * @param {Object} jsObj - xml2js formatted object - * @return {RenderInformation} + * Converts a node.js async op into a promise w/boxed resolved value(s). + * + * @param op the operation to convert. + * + * @return the promise. */ -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.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); + } + })); + }); +}; - 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; - } +// extend jsonld.promises w/jsonld.js methods +jsonld.promises({api: jsonld.promises}); - // 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); - } +/* WebIDL API */ - return renderInformation; +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; -ns.RenderInformation = RenderInformation; -// ------- END RENDERINFORMATION ------- - -module.exports = ns; -},{"./utilities":30,"xml2js":25}],29:[function(_dereq_,module,exports){ -/** - * The API contains two other submodules: {@link libsbgn.render} and {@link libsbgn.annot} - * @module libsbgn - * @namespace libsbgn -*/ +// 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 renderExt = _dereq_('./libsbgn-render'); -var annotExt = _dereq_('./libsbgn-annotations'); -var xml2js = _dereq_('xml2js'); -var utils = _dereq_('./utilities'); -var checkParams = utils.checkParams; +if(canDefineProperty) { + Object.defineProperty(JsonLdProcessor, 'prototype', { + writable: false, + enumerable: false + }); + Object.defineProperty(JsonLdProcessor.prototype, 'constructor', { + writable: true, + enumerable: false, + configurable: true, + value: JsonLdProcessor + }); +} -var ns = {}; // namespace that encapsulates all exportable features +// 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; + } +} -ns.xmlns = "http://sbgn.org/libsbgn/0.3"; +/* Utility API */ -// ------- 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; -}; +// define setImmediate and nextTick +//// nextTick implementation with browser-compatible fallback //// +// from https://github.com/caolan/async/blob/master/lib/async.js -/** - * Allows inheriting objects to get an extension element. - * @param {Extension} extension - */ -SBGNBase.prototype.setExtension = function (extension) { - this.extension = extension; -}; +// capture the global reference to guard against fakeTimer mocks +var _setImmediate = typeof setImmediate === 'function' && setImmediate; -/** - * Allows inheriting objects to get a notes element. - * @param {Notes} notes - */ -SBGNBase.prototype.setNotes = function (notes) { - this.notes = notes; +var _delay = _setImmediate ? function(fn) { + // not a direct alias (for IE10 compatibility) + _setImmediate(fn); +} : function(fn) { + setTimeout(fn, 0); }; -/** - * 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(); - } -}; +if(typeof process === 'object' && typeof process.nextTick === 'function') { + jsonld.nextTick = process.nextTick; +} else { + jsonld.nextTick = _delay; +} +jsonld.setImmediate = _setImmediate ? _delay : jsonld.nextTick; /** - * Get the appropriate properties from jsObj. - * @param {Object} jsObj - xml2js formatted object + * 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. */ -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); - } +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; }; -ns.SBGNBase = SBGNBase; -// ------- END SBGNBase ------- -// ------- SBGN ------- /** - * Represents the <sbgn> element. - * @class - * @extends SBGNBase - * @param {Object} params - * @param {string=} params.xmlns - * @param {Map[]=} params.maps + * Creates a simple queue for requesting documents. */ -var Sbgn = function (params) { - ns.SBGNBase.call(this, params); - var params = checkParams(params, ['xmlns', 'maps']); - this.xmlns = params.xmlns; - this.maps = params.maps || []; +jsonld.RequestQueue = function() { + this._requests = {}; }; - -Sbgn.prototype = Object.create(ns.SBGNBase.prototype); -Sbgn.prototype.constructor = Sbgn; - -/** - * @param {Map} map - */ -Sbgn.prototype.addMap = function (map) { - this.maps.push(map); +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 - */ -Sbgn.prototype.buildJsObj = function () { - var sbgnObj = {}; + // callback must be given if not using promises + if(!callback && !self._usePromise) { + throw new Error('callback must be specified.'); + } - // attributes - var attributes = {}; - if(this.xmlns != null) { - attributes.xmlns = this.xmlns; - } - utils.addAttributes(sbgnObj, attributes); + // 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); + }); + }); + } - // 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; + // 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. */ -Sbgn.prototype.toXML = function () { - return utils.buildString({sbgn: this.buildJsObj()}); +jsonld.DocumentCache = function(size) { + this.order = []; + this.cache = {}; + this.size = size || 50; + this.expires = 30 * 1000; }; - -/** - * @param {String} string - * @return {Sbgn} - */ -Sbgn.fromXML = function (string) { - var sbgn; - function fn (err, result) { - sbgn = Sbgn.fromObj(result); +jsonld.DocumentCache.prototype.get = function(url) { + if(url in this.cache) { + var entry = this.cache[url]; + if(entry.expires >= +new Date()) { + return entry.ctx; } - 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; + delete this.cache[url]; + this.order.splice(this.order.indexOf(url), 1); + } + return null; }; -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 || []; +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)}; }; -Map.prototype = Object.create(ns.SBGNBase.prototype); -Map.prototype.constructor = Map; - /** - * @param {Glyph} glyph + * Creates an active context cache. + * + * @param size the maximum size of the cache. */ -Map.prototype.addGlyph = function (glyph) { - this.glyphs.push(glyph); +jsonld.ActiveContextCache = function(size) { + this.order = []; + this.cache = {}; + this.size = size || 100; }; - -/** - * @param {Arc} arc - */ -Map.prototype.addArc = function (arc) { - this.arcs.push(arc); +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; }; - -/** - * @param {Bbox} bbox - */ -Map.prototype.setBbox = function (bbox) { - this.bbox = bbox; +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 {Arcgroup} arc + * Default JSON-LD cache. */ -Map.prototype.addArcgroup = function (arcgroup) { - this.arcgroups.push(arcgroup); +jsonld.cache = { + activeCtx: new jsonld.ActiveContextCache() }; /** - * @param {string} class_ - * @return {Gyph[]} + * Document loaders. */ -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.documentLoaders = {}; /** - * @return {Object} - xml2js formatted object + * 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. */ -Map.prototype.buildJsObj = function () { - var mapObj = {}; +jsonld.documentLoaders.jquery = function($, options) { + options = options || {}; + var queue = new jsonld.RequestQueue(); - // 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); + // 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); - // 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 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}; -/** - * @return {string} - */ -Map.prototype.toXML = function () { - return utils.buildString({map: this.buildJsObj()}); -}; + // 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; + } + } -/** - * @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; + 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 {Object} jsObj - xml2js formatted object - * @return {Map} + * 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. */ -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; - } +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(); - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - map.id = attributes.id || null; - map.language = attributes.language || null; - map.version = attributes.version || null; - } + 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); + }); - 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); - } - } + 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); - map.baseFromObj(jsObj); - return map; -}; + function handleResponse(err, res, body) { + doc = {contextUrl: null, documentUrl: url, document: body || null}; -ns.Map = Map; -// ------- END MAP ------- + // 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); + } -// ------- 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 = {}; -}; + // 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; + } + } -/** - * @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; - } - } + // 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 {string} extensionName - * @return {boolean} + * 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. */ -Extension.prototype.has = function (extensionName) { - return this.list.hasOwnProperty(extensionName); -}; +jsonld.documentLoaders.xhr = function(options) { + options = options || {}; + var rlink = /(^|(\r\n))link:/i; + var queue = new jsonld.RequestQueue(); -/** - * @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; - } -}; + // 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); -/** - * @return {Object} - xml2js formatted object - */ -Extension.prototype.buildJsObj = function () { - var extensionObj = {}; + 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}); + } - 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; -}; + var doc = {contextUrl: null, documentUrl: url, document: req.response}; -/** - * @return {string} - */ -Extension.prototype.toXML = function () { - return utils.buildString({extension: this.buildJsObj()}) + // 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 {String} string - * @return {Extension} + * 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. */ -Extension.fromXML = function (string) { - var extension; - function fn (err, result) { - extension = Extension.fromObj(result); - }; - utils.parseString(string, fn); - return extension; +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 {Object} jsObj - xml2js formatted object - * @return {Extension} + * 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. */ -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; - } +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 children = Object.keys(jsObj); - for (var extName in jsObj) { - //var extName = Object.keys(jsObj[i])[0]; - var extJsObj = jsObj[extName]; + // set default options + if(!('base' in options)) { + options.base = ''; + } + if(!('documentLoader' in options)) { + options.documentLoader = jsonld.loadDocument; + } - //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 initial context early for null context + if(localCtx === null) { + return callback(null, _getInitialContext(options)); + } - return extension; + // 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); + }); }; -ns.Extension = Extension; -// ------- END EXTENSION ------- - -// ------- NOTES ------- /** - * Represents the <notes> element. - * Its single content attribute stores xhtml elements as string. - * @class + * 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. */ -var Notes = function () { - this.content = ""; +jsonld.hasProperty = function(subject, property) { + var rval = false; + if(property in subject) { + var value = subject[property]; + rval = (!_isArray(value) || value.length > 0); + } + return rval; }; /** - * Overwrite the content. - * @param {String} string + * 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. */ -Notes.prototype.setContent = function (string) { - this.content = string; +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; }; /** - * @param {String} string + * 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). */ -Notes.prototype.appendContent = function (string) { - this.content += string; -}; +jsonld.addValue = function(subject, property, value, options) { + options = options || {}; + if(!('propertyIsArray' in options)) { + options.propertyIsArray = false; + } + if(!('allowDuplicate' in options)) { + options.allowDuplicate = true; + } -/** - * @return {Object} - xml2js formatted object - */ -Notes.prototype.buildJsObj = function () { + 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)); - var parsedContent = ""; - if(this.content != "") { // xml2js refuses to parse empty strings - utils.parseString(this.content, function (err, result) { - parsedContent = result; - }); - } + // make property an array if value not present or always an array + if(!_isArray(subject[property]) && + (!hasValue || options.propertyIsArray)) { + subject[property] = [subject[property]]; + } - return parsedContent; + // add new value + if(!hasValue) { + subject[property].push(value); + } + } else { + // add new value as set or single value + subject[property] = options.propertyIsArray ? [value] : value; + } }; /** - * @return {string} + * 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. */ -Notes.prototype.toXML = function () { - return utils.buildString({notes: this.buildJsObj()}) +jsonld.getValues = function(subject, property) { + var rval = subject[property] || []; + if(!_isArray(rval)) { + rval = [rval]; + } + return rval; }; /** - * @param {String} string - * @return {Notes} + * Removes a property from a subject. + * + * @param subject the subject. + * @param property the property. */ -Notes.fromXML = function (string) { - var notes; - function fn (err, result) { - notes = Notes.fromObj(result); - }; - utils.parseString(string, fn); - return notes; +jsonld.removeProperty = function(subject, property) { + delete subject[property]; }; /** - * @param {Object} jsObj - xml2js formatted object - * @return {Notes} + * 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). */ -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; - } +jsonld.removeValue = function(subject, property, value, options) { + options = options || {}; + if(!('propertyIsArray' in options)) { + options.propertyIsArray = false; + } - 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 + // filter out value + var values = jsonld.getValues(subject, property).filter(function(e) { + return !jsonld.compareValues(e, value); + }); - return notes; + if(values.length === 0) { + jsonld.removeProperty(subject, property); + } else if(values.length === 1 && !options.propertyIsArray) { + subject[property] = values[0]; + } else { + subject[property] = values; + } }; -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 + * 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. */ -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; +jsonld.compareValues = function(v1, v2) { + // 1. equal primitives + if(v1 === v2) { + return true; + } - // 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 || []; -}; + // 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; + } -Glyph.prototype = Object.create(ns.SBGNBase.prototype); -Glyph.prototype.constructor = Glyph; + // 3. equal @ids + if(_isObject(v1) && ('@id' in v1) && _isObject(v2) && ('@id' in v2)) { + return v1['@id'] === v2['@id']; + } -/** - * @param {Label} label - */ -Glyph.prototype.setLabel = function (label) { - this.label = label; + return false; }; /** - * @param {StateType} state + * 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. */ -Glyph.prototype.setState = function (state) { - this.state = state; -}; +jsonld.getContextValue = function(ctx, key, type) { + var rval = null; -/** - * @param {Bbox} bbox - */ -Glyph.prototype.setBbox = function (bbox) { - this.bbox = bbox; -}; + // return null for invalid key + if(key === null) { + return rval; + } -/** - * @param {CloneType} clone - */ -Glyph.prototype.setClone = function (clone) { - this.clone = clone; -}; + // get default language + if(type === '@language' && (type in ctx)) { + rval = ctx[type]; + } -/** - * @param {Callout} callout - */ -Glyph.prototype.setCallout = function (callout) { - this.callout = callout; -}; + // get specific entry information + if(ctx.mappings[key]) { + var entry = ctx.mappings[key]; -/** - * @param {EntityType} entity - */ -Glyph.prototype.setEntity = function (entity) { - this.entity = entity; + if(_isUndefined(type)) { + // return whole entry + rval = entry; + } else if(type in entry) { + // return entry value for type + rval = entry[type]; + } + } + + return rval; }; +/** Registered RDF dataset parsers hashed by content-type. */ +var _rdfParsers = {}; + /** - * @param {Glyph} glyphMember + * 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). */ -Glyph.prototype.addGlyphMember = function (glyphMember) { - this.glyphMembers.push(glyphMember); +jsonld.registerRDFParser = function(contentType, parser) { + _rdfParsers[contentType] = parser; }; /** - * @param {Port} port + * Unregisters an RDF dataset parser by content-type. + * + * @param contentType the content-type for the parser. */ -Glyph.prototype.addPort = function (port) { - this.ports.push(port); +jsonld.unregisterRDFParser = function(contentType) { + delete _rdfParsers[contentType]; }; -/** - * @return {Object} - xml2js formatted object - */ -Glyph.prototype.buildJsObj = function () { - var glyphObj = {}; +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 + }; + } +} - // 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); +// 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'; - // 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; -}; +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'; + +var LINK_HEADER_REL = 'http://www.w3.org/ns/json-ld#context'; +var MAX_CONTEXT_URLS = 10; /** - * @return {string} + * A JSON-LD Error. + * + * @param msg the error message. + * @param type the error type. + * @param details the error details. */ -Glyph.prototype.toXML = function () { - return utils.buildString({glyph: this.buildJsObj()}) +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(); +} /** - * @param {String} string - * @return {Glyph} + * Constructs a new JSON-LD Processor. */ -Glyph.fromXML = function (string) { - var glyph; - function fn (err, result) { - glyph = Glyph.fromObj(result); - }; - utils.parseString(string, fn); - return glyph; -}; +var Processor = function() {}; /** - * @param {Object} jsObj - xml2js formatted object - * @return {Glyph} + * 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. */ -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; - } +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; + } - // 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); - } + // 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; + } + } + } - 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); - } - } + // 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; + } - glyph.baseFromObj(jsObj); - return glyph; -}; + // FIXME: avoid misuse of active property as an expanded property? + var insideReverse = (activeProperty === '@reverse'); -ns.Glyph = Glyph; -// ------- END GLYPH ------- + var rval = {}; -// ------- 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; -}; + 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}); + } -Label.prototype = Object.create(ns.SBGNBase.prototype); -Label.prototype.constructor = ns.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 {Bbox} bbox - */ -Label.prototype.setBbox = function (bbox) { - this.bbox = bbox; -}; + // compact @id and @type(s) + if(expandedProperty === '@id' || expandedProperty === '@type') { + var compactedValue; -/** - * @return {Object} - xml2js formatted object - */ -Label.prototype.buildJsObj = function () { - var labelObj = {}; + // 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})); + } + } - // 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); + // 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; + } - this.baseToJsObj(labelObj); - if(this.bbox != null) { - labelObj.bbox = this.bbox.buildJsObj(); - } - return labelObj; -}; + // handle @reverse + if(expandedProperty === '@reverse') { + // recursively compact expanded value + var compactedValue = this.compact( + activeCtx, '@reverse', expandedValue, options); -/** - * @return {string} - */ -Label.prototype.toXML = function () { - return utils.buildString({label: this.buildJsObj()}) -}; + // 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 {String} string - * @return {Label} - */ -Label.fromXML = function (string) { - var label; - function fn (err, result) { - label = Label.fromObj(result); - }; - utils.parseString(string, fn); - return label; -}; + if(Object.keys(compactedValue).length > 0) { + // use keyword alias and add value + var alias = _compactIri(activeCtx, expandedProperty); + jsonld.addValue(rval, alias, compactedValue); + } -/** - * @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]); - } + continue; + } - var label = new ns.Label(); - jsObj = jsObj.label; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return label; - } + // handle @index property + if(expandedProperty === '@index') { + // drop @index if inside an @index container + var container = jsonld.getContextValue( + activeCtx, activeProperty, '@container'); + if(container === '@index') { + continue; + } - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - label.text = attributes.text || null; - } + // use keyword alias and add value + var alias = _compactIri(activeCtx, expandedProperty); + jsonld.addValue(rval, alias, expandedValue); + continue; + } - if(jsObj.bbox) { - var bbox = ns.Bbox.fromObj({bbox: jsObj.bbox[0]}); - label.setBbox(bbox); - } - label.baseFromObj(jsObj); - return label; -}; + // 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; + } -ns.Label = Label; -// ------- END LABEL ------- + // Note: expanded value must be an array due to expansion algorithm. -// ------- 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); -}; + // preserve empty arrays + if(expandedValue.length === 0) { + var itemActiveProperty = _compactIri( + activeCtx, expandedProperty, expandedValue, {vocab: true}, + insideReverse); + jsonld.addValue( + rval, itemActiveProperty, expandedValue, {propertyIsArray: true}); + } -Bbox.prototype = Object.create(ns.SBGNBase.prototype); -Bbox.prototype.constructor = ns.Bbox; + // recusively process array values + for(var vi = 0; vi < expandedValue.length; ++vi) { + var expandedItem = expandedValue[vi]; -/** - * @return {Object} - xml2js formatted object - */ -Bbox.prototype.buildJsObj = function () { - var bboxObj = {}; + // compact property and get container type + var itemActiveProperty = _compactIri( + activeCtx, expandedProperty, expandedItem, {vocab: true}, + insideReverse); + var container = jsonld.getContextValue( + activeCtx, itemActiveProperty, '@container'); - // 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; -}; + // get @list value if appropriate + var isList = _isList(expandedItem); + var list = null; + if(isList) { + list = expandedItem['@list']; + } -/** - * @return {string} - */ -Bbox.prototype.toXML = function () { - return utils.buildString({bbox: this.buildJsObj()}) -}; + // recursively compact expanded item + var compactedItem = this.compact( + activeCtx, itemActiveProperty, isList ? list : expandedItem, options); -/** - * @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; -}; + // handle @list + if(isList) { + // ensure @list value is an array + if(!_isArray(compactedItem)) { + compactedItem = [compactedItem]; + } -/** - * @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]); - } + if(container !== '@list') { + // wrap using @list alias + var wrapper = {}; + wrapper[_compactIri(activeCtx, '@list')] = compactedItem; + compactedItem = wrapper; - var bbox = new ns.Bbox(); - jsObj = jsObj.bbox; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return bbox; - } + // 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'}); + } + } - 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; -}; + // 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 = {}; + } -ns.Bbox = Bbox; -// ------- END BBOX ------- + // if container is a language map, simplify compacted value to + // a simple string + if(container === '@language' && _isValue(compactedItem)) { + compactedItem = compactedItem['@value']; + } -// ------- 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; -}; + // 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 {Object} - xml2js formatted object - */ -StateType.prototype.buildJsObj = function () { - var stateObj = {}; + // add compact value + jsonld.addValue( + rval, itemActiveProperty, compactedItem, + {propertyIsArray: isArray}); + } + } + } - // 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 rval; + } -/** - * @return {string} - */ -StateType.prototype.toXML = function () { - return utils.buildString({state: this.buildJsObj()}) + // only primitives remain which are already compact + return element; }; /** - * @param {String} string - * @return {StateType} + * 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. */ -StateType.fromXML = function (string) { - var state; - function fn (err, result) { - state = StateType.fromObj(result); - }; - utils.parseString(string, fn); - return state; -}; +Processor.prototype.expand = function( + activeCtx, activeProperty, element, options, insideList) { + var self = this; -/** - * @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]); - } + // nothing to expand + if(element === null || element === undefined) { + return null; + } - var state = new ns.StateType(); - jsObj = jsObj.state; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return state; - } + 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(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - state.value = attributes.value || null; - state.variable = attributes.variable || null; - } - return state; -}; + // expand element according to value expansion rules + return _expandValue(activeCtx, activeProperty, element); + } -ns.StateType = StateType; -// ------- END STATE ------- + // 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; + } -// ------- 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; -}; + // recursively expand object: -/** - * @param {Label} label - */ -CloneType.prototype.setLabel = function (label) { - this.label = label; -}; + // if element has a context, process it + if('@context' in element) { + activeCtx = self.processContext(activeCtx, element['@context'], options); + } -/** - * @return {Object} - xml2js formatted object - */ -CloneType.prototype.buildJsObj = function () { - var cloneObj = {}; + // expand the active property + var expandedActiveProperty = _expandIri( + activeCtx, activeProperty, {vocab: true}); - // children - if(this.label != null) { - cloneObj.label = this.label.buildJsObj(); - } - return cloneObj; -}; + 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 {string} - */ -CloneType.prototype.toXML = function () { - return utils.buildString({clone: this.buildJsObj()}) -}; + // skip @context + if(key === '@context') { + continue; + } -/** - * @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; -}; + // expand property + var expandedProperty = _expandIri(activeCtx, key, {vocab: true}); -/** - * @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]); - } + // drop non-absolute IRI keys that aren't keywords + if(expandedProperty === null || + !(_isAbsoluteIri(expandedProperty) || _isKeyword(expandedProperty))) { + continue; + } - var clone = new ns.CloneType(); - jsObj = jsObj.clone; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return clone; - } + 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}); + } + } - // children - if(jsObj.label) { - var label = ns.Label.fromObj({label: jsObj.label[0]}); - clone.setLabel(label); - } - return clone; -}; + // 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}); + } + } -ns.CloneType = CloneType; -// ------- END CLONE ------- + if(expandedProperty === '@type') { + _validateTypeValue(value); + } -// ------- 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; -}; + // @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}); + } -/** - * @return {Object} - xml2js formatted object - */ -EntityType.prototype.buildJsObj = function () { - var entityObj = {}; + // @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}); + } - // 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; -}; + // @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(); + } -/** - * @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]); - } + // @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}); + } + } - var entity = new ns.EntityType(); - jsObj = jsObj.entity; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return entity; - } + // @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}); + } - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - entity.name = attributes.name || null; - } - return entity; -}; + expandedValue = self.expand(activeCtx, '@reverse', value, options); -ns.EntityType = EntityType; -// ------- END ENTITYTYPE ------- + // properties double-reversed + if('@reverse' in expandedValue) { + for(var property in expandedValue['@reverse']) { + jsonld.addValue( + rval, property, expandedValue['@reverse'][property], + {propertyIsArray: true}); + } + } -// ------- 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); -}; + // 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}); + } + } -Port.prototype = Object.create(ns.SBGNBase.prototype); -Port.prototype.constructor = ns.Port; + continue; + } -/** - * @return {Object} - xml2js formatted object - */ -Port.prototype.buildJsObj = function () { - var portObj = {}; + var container = jsonld.getContextValue(activeCtx, key, '@container'); - // 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; -}; + 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); + } + } -/** - * @return {string} - */ -Port.prototype.toXML = function () { - return utils.buildString({port: this.buildJsObj()}) -}; + // drop null values if property is not @value + if(expandedValue === null && expandedProperty !== '@value') { + continue; + } -/** - * @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; -}; + // 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}; + } -/** - * @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]); - } + // 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; + } - var port = new ns.Port(); - jsObj = jsObj.port; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return port; - } + // 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}); + } - 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; -}; + // get property count on expanded output + keys = Object.keys(rval); + var count = keys.length; -ns.Port = Port; -// ------- END PORT ------- + 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; + } -// ------- 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; + // 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; + } + } - this.start = params.start; - this.end = params.end; - this.nexts = params.nexts || []; - this.glyphs = params.glyphs || []; + return rval; }; -Arc.prototype = Object.create(ns.SBGNBase.prototype); -Arc.prototype.constructor = ns.Arc; - /** - * @param {StartType} start + * 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. */ -Arc.prototype.setStart = function (start) { - this.start = start; -}; +Processor.prototype.createNodeMap = function(input, options) { + options = options || {}; -/** - * @param {EndType} end - */ -Arc.prototype.setEnd = function (end) { - this.end = 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); -/** - * @param {NextType} next - */ -Arc.prototype.addNext = function (next) { - this.nexts.push(next); + // add all non-default graphs to default graph + return _mergeNodeMaps(graphs); }; /** - * @param {Glyph} glyph + * Performs JSON-LD flattening. + * + * @param input the expanded JSON-LD to flatten. + * + * @return the flattened output. */ -Arc.prototype.addGlyph = function (glyph) { - this.glyphs.push(glyph); +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. */ -Arc.prototype.buildJsObj = function () { - var arcObj = {}; +Processor.prototype.frame = function(input, frame, options) { + // create framing state + var state = { + options: options, + graphs: {'@default': {}, '@merged': {}}, + subjectStack: [], + link: {} + }; - // 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); + // 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']; - // 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; + // frame the subjects + var framed = []; + _frame(state, Object.keys(state.subjects).sort(), frame, framed, null); + return framed; }; /** - * @return {string} + * 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. */ -Arc.prototype.toXML = function () { - return utils.buildString({arc: this.buildJsObj()}) +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 {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} + * 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. */ -Arc.fromObj = function (jsObj) { - if (typeof jsObj.arc == 'undefined') { - throw new Error("Bad XML provided, expected tagName arc, got: " + Object.keys(jsObj)[0]); - } +Processor.prototype.fromRDF = function(dataset, options, callback) { + var defaultGraph = {}; + var graphMap = {'@default': defaultGraph}; + var referencedOnce = {}; - var arc = new ns.Arc(); - jsObj = jsObj.arc; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return arc; - } + 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]; - 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; - } + // get subject, predicate, object + var s = triple.subject.value; + var p = triple.predicate.value; + var o = triple.object; - // 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); - } - } + if(!(s in nodeMap)) { + nodeMap[s] = {'@id': s}; + } + var node = nodeMap[s]; - arc.baseFromObj(jsObj); - return arc; -}; + var objectIsId = (o.type === 'IRI' || o.type === 'blank node'); + if(objectIsId && !(o.value in nodeMap)) { + nodeMap[o.value] = {'@id': o.value}; + } -ns.Arc = Arc; -// ------- END ARC ------- + if(p === RDF_TYPE && !options.useRdfType && objectIsId) { + jsonld.addValue(node, '@type', o.value, {propertyIsArray: true}); + continue; + } -// ------- 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); -}; + var value = _RDFToObject(o, options.useNativeTypes); + jsonld.addValue(node, p, value, {propertyIsArray: true}); -/** - * @return {Object} - xml2js formatted object - */ -StartType.prototype.buildJsObj = function () { - var startObj = {}; + // 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 + }; + } + } + } + } - // 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; -}; + // convert linked lists to @list arrays + for(var name in graphMap) { + var graphObject = graphMap[name]; -/** - * @return {string} - */ -StartType.prototype.toXML = function () { - return utils.buildString({start: this.buildJsObj()}) -}; + // no @lists to be converted, continue + if(!(RDF_NIL in graphObject)) { + 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; -}; + // 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 = []; -/** - * @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]); - } + // 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']); - var start = new ns.StartType(); - jsObj = jsObj.start; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return start; - } + // 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; - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - start.x = parseFloat(attributes.x); - start.y = parseFloat(attributes.y); - } - return start; -}; + // if node is not a blank node, then list head found + if(node['@id'].indexOf('_:') !== 0) { + break; + } + } -ns.StartType = StartType; -// ------- END STARTTYPE ------- + // 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; + } -// ------- 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); -}; + // preserve list head + head = graphObject[head['@id']][RDF_REST][0]; + list.pop(); + listNodes.pop(); + } -/** - * @return {Object} - xml2js formatted object - */ -EndType.prototype.buildJsObj = function () { - var endObj = {}; + // transform list into @list object + delete head['@id']; + head['@list'] = list.reverse(); + for(var j = 0; j < listNodes.length; ++j) { + delete graphObject[listNodes[j]]; + } + } - // 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; -}; + delete nil.usages; + } -/** - * @return {string} - */ -EndType.prototype.toXML = function () { - return utils.buildString({end: this.buildJsObj()}) -}; + 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); + } + } -/** - * @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; + callback(null, result); }; /** - * @param {Object} jsObj - xml2js formatted object - * @return {EndType} + * 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. */ -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 ------- +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); -// ------- 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); + 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; }; /** - * @return {Object} - xml2js formatted object + * 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. */ -NextType.prototype.buildJsObj = function () { - var nextObj = {}; +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]; - // 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; -}; + // no contexts in array, clone existing context + if(ctxs.length === 0) { + return activeCtx.clone(); + } -/** - * @return {string} - */ -NextType.prototype.toXML = function () { - return utils.buildString({next: this.buildJsObj()}) -}; + // 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]; -/** - * @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; -}; + // reset to initial context + if(ctx === null) { + rval = activeCtx = _getInitialContext(options); + continue; + } -/** - * @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]); - } + // dereference @context key if present + if(_isObject(ctx) && '@context' in ctx) { + ctx = ctx['@context']; + } - var next = new ns.NextType(); - jsObj = jsObj.next; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return next; - } + // 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}); + } - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - next.x = parseFloat(attributes.x); - next.y = parseFloat(attributes.y); - } - return next; -}; + // get context from cache if available + if(jsonld.cache.activeCtx) { + var cached = jsonld.cache.activeCtx.get(activeCtx, ctx); + if(cached) { + rval = activeCtx = cached; + continue; + } + } -ns.NextType = NextType; -// ------- END NEXTTYPE ------- + // update active context and clone new one before updating + activeCtx = rval; + rval = rval.clone(); -// ------- 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; + // define context mappings for keys in local context + var defined = {}; -/** - * @return {Object} - xml2js formatted object - */ -Point.prototype.buildJsObj = function () { - var pointJsObj = {}; + // handle @base + if('@base' in ctx) { + var base = ctx['@base']; - // 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; -}; + // 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}); + } -/** - * @return {string} - */ -Point.prototype.toXML = function () { - return utils.buildString({point: this.buildJsObj()}) -}; + if(base !== null) { + base = jsonld.url.parse(base || ''); + } + rval['@base'] = base; + defined['@base'] = true; + } -/** - * @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]); - } + // 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; + } - var point = new ns.Point(); - jsObj = jsObj.point; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return point; - } + // 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; + } - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - point.x = parseFloat(attributes.x); - point.y = parseFloat(attributes.y); - } - point.baseFromObj(jsObj); - return point; -}; + // process all other keys + for(var key in ctx) { + _createTermDefinition(rval, ctx, key, defined); + } -ns.Point = Point; -// ------- END POINT ------- + // cache result + if(jsonld.cache.activeCtx) { + jsonld.cache.activeCtx.set(activeCtx, ctx, rval); + } + } -// ------- 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; + return rval; }; /** - * @param {Point} point + * Expands a language map. + * + * @param languageMap the language map to expand. + * + * @return the expanded language map. */ -Callout.prototype.setPoint = function(point) { - this.point = point; -}; +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() + }); + } + } + return rval; +} /** - * @return {Object} - xml2js formatted object + * 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. */ -Callout.prototype.buildJsObj = function () { - var calloutObj = {}; +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']); + } - // attributes - var attributes = {}; - if(this.target != null) { - attributes.target = this.target; - } - utils.addAttributes(calloutObj, attributes); + // 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]); + } + } + } - // children - if(this.point != null) { - calloutObj.point = this.point.buildJsObj(); - } - return calloutObj; -}; + return element; +} /** - * @return {string} + * 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. */ -Callout.prototype.toXML = function () { - return utils.buildString({callout: this.buildJsObj()}) -}; +function _expandValue(activeCtx, activeProperty, value) { + // nothing to expand + if(value === null || value === undefined) { + return null; + } -/** - * @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; -}; + // 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}); + } -/** - * @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]); - } + // get type definition from context + var type = jsonld.getContextValue(activeCtx, activeProperty, '@type'); - var callout = new ns.Callout(); - jsObj = jsObj.callout; - if(typeof jsObj != 'object') { // nothing inside, empty xml - return callout; - } + // 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})}; + } - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - callout.target = attributes.target || null; - } + // do not expand keyword values + if(_isKeyword(expandedProperty)) { + return value; + } - // children - if(jsObj.point) { - var point = ns.Point.fromObj({point: jsObj.point[0]}); - callout.setPoint(point); - } - return callout; -}; + var rval = {}; -ns.Callout = Callout; -// ------- END CALLOUT ------- + 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; + + return rval; +} -// ------- ARCGROUP ------- /** - * Represents the <arcgroup> element. - * @class - * @extends SBGNBase - * @param {Object} params - * @param {string=} params.class_ - * @param {Glyph[]=} params.glyphs - * @param {Arc[]=} params.arcs + * 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. */ -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 || []; -}; +function _graphToRDF(graph, issuer, options) { + var rval = []; -Arcgroup.prototype = Object.create(ns.SBGNBase.prototype); -Arcgroup.prototype.constructor = Arcgroup; + 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; + } -/** - * @param {Glyph} glyph - */ -Arcgroup.prototype.addGlyph = function (glyph) { - this.glyphs.push(glyph); -}; + for(var ii = 0; ii < items.length; ++ii) { + var item = items[ii]; -/** - * @param {Arc} arc - */ -Arcgroup.prototype.addArc = function (arc) { - this.arcs.push(arc); -}; + // RDF subject + var subject = {}; + subject.type = (id.indexOf('_:') === 0) ? 'blank node' : 'IRI'; + subject.value = id; -/** - * @return {Object} - xml2js formatted object - */ -Arcgroup.prototype.buildJsObj = function () { - var arcgroupObj = {}; + // skip relative IRI subjects + if(!_isAbsoluteIri(id)) { + continue; + } - // attributes - var attributes = {}; - if(this.class_ != null) { - attributes.class = this.class_; - } - utils.addAttributes(arcgroupObj, attributes); + // RDF predicate + var predicate = {}; + predicate.type = (property.indexOf('_:') === 0) ? 'blank node' : 'IRI'; + predicate.value = property; - // 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; -}; + // skip relative IRI predicates + if(!_isAbsoluteIri(property)) { + continue; + } -/** - * @return {string} - */ -Arcgroup.prototype.toXML = function () { - return utils.buildString({arcgroup: this.buildJsObj()}); -}; + // skip blank node predicates unless producing generalized RDF + if(predicate.type === 'blank node' && !options.produceGeneralizedRdf) { + continue; + } -/** - * @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; -}; + // 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}); + } + } + } + } + } + + return rval; +} /** - * @param {Object} jsObj - xml2js formatted object - * @return {Arcgroup} + * 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. */ -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; - } +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}; - if(jsObj.$) { // we have some attributes - var attributes = jsObj.$; - arcgroup.class_ = attributes.class || null; - } + for(var i = 0; i < list.length; ++i) { + var item = list[i]; - 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); - } - } + var blankNode = {type: 'blank node', value: issuer.getId()}; + triples.push({subject: subject, predicate: predicate, object: blankNode}); - arcgroup.baseFromObj(jsObj); - return arcgroup; -}; + subject = blankNode; + predicate = first; + var object = _objectToRDF(item); -ns.Arcgroup = Arcgroup; -// ------- END ARCGROUP ------- + // skip null objects (they are relative IRIs) + if(object) { + triples.push({subject: subject, predicate: predicate, object: object}); + } -ns.render = renderExt; -ns.annot = annotExt; -module.exports = ns; -},{"./libsbgn-annotations":27,"./libsbgn-render":28,"./utilities":30,"xml2js":25}],30:[function(_dereq_,module,exports){ -var ns = {}; -var xml2js = _dereq_('xml2js'); + predicate = rest; + } -/* - 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; + triples.push({subject: subject, predicate: predicate, object: nil}); } -ns.getFirstLevelByName = function (xmlObj, localName) { - var result = []; - for(var i=0; i\\"\{\}\|\^\`]/; +var POSITIONS = {'subject': 's', 'object': 'o', 'name': 'g'}; -// ## Constructor -function N3Lexer(options) { - if (!(this instanceof N3Lexer)) - return new N3Lexer(options); +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; + } +}; - // 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)); - }); - }; +// do some work in a time slice, but in serial +Normalize.prototype.doWork = function(fn, callback) { + var schedule = this.schedule; + + if(schedule.totalDepth >= schedule.MAX_TOTAL_DEPTH) { + return callback(new Error( + 'Maximum total call stack depth exceeded; normalization aborting.')); } - // 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 + (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); + } - _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]*)?$/, + // 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; + } - // ## Private methods + // 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); + }); + } - // ### `_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); + // not enough time left in this slice, run after letting browser + // do some other things + schedule.depth = 0; + schedule.running = false; + jsonld.setImmediate(work); + })(); +}; - // 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; +// 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; + }; + } - // 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; + (function iterate(err, result) { + if(err) { + return callback(err); + } + if(iterator()) { + return self.doWork(function() { + fn(iterator.value, iterator.key, iterate); + }); + } + callback(); + })(); +}; - 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; +// asynchronous waterfall +Normalize.prototype.waterfall = function(fns, callback) { + var self = this; + self.forEach(fns, function(fn, idx, callback) { + self.doWork(fn, callback); + }, callback); +}; - 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; +// 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); + })(); +}; - case '?': - // Try to find a variable - if (this._n3Mode && (match = this._variable.exec(input))) - type = 'var', value = match[0]; - break; +// 4.4) Normalization Algorithm +Normalize.prototype.main = function(dataset, callback) { + var self = this; + self.schedule.start = new Date().getTime(); + var result; - 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; + // 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})); + } + } - 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) + // 1) Create the normalization state. - 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; + // Note: Optimize by generating non-normalized blank node map concurrently. + var nonNormalized = {}; - 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; + 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); - 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; + // 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. - 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; + // 4) Initialize simple, a boolean flag, to true. + var simple = true; - 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; + // 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; - case '!': - if (!this._n3Mode) - break; - case ',': - case ';': - case '[': - case ']': - case '(': - case ')': - case '{': - case '}': - // The next token is punctuation - matchLength = 1; - type = firstChar; - break; + // 5.2) Clear hash to blank nodes map. + self.hashToBlankNodes = {}; - default: - inconclusive = 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(); + } - // 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]); - } + // 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); - // 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 = ''; - } - } + // 5.4.3) Remove identifier from non-normalized identifiers. + delete nonNormalized[id]; - // 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; - } + // 5.4.4) Remove hash from the hash to blank nodes map. + delete self.hashToBlankNodes[hash]; - // 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); - } + // 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 = []; - // Signals the syntax error through the callback - function reportSyntaxError(self) { callback(self._syntaxError(/^\S*/.exec(input)[0])); } - }, + // 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(); + } - // ### `_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; } - }, + // 6.2.2) Create temporary issuer, an identifier issuer + // initialized with the prefix _:b. + var issuer = new IdentifierIssuer('_:b'); - // ### `_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; - }, + // 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); + // 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. */ - // ## Public methods + // 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(); - // ### `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; + // 8) Return the normalized dataset. + if(self.options.format === 'application/nquads') { + result = normalized.join(''); + return callback(); + } - // 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); + result = _parseNQuads(normalized.join('')); + callback(); } - }); - // Parses until the end - input.on('end', function () { - if (self._input !== null) - self._tokenizeToEnd(callback, true); - }); - input.on('error', callback); + ], callback); } - }, + ], function(err) { + callback(err, result); + }); }; -// ## Exports -module.exports = N3Lexer; - -},{}],33:[function(_dereq_,module,exports){ -// **N3Parser** parses N3 documents. -var N3Lexer = _dereq_('./N3Lexer'); +// 4.6) Hash First Degree Quads +Normalize.prototype.hashFirstDegreeQuads = function(id, callback) { + var self = this; -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'; + // return cached hash + var info = self.blankNodeInfo[id]; + if('hash' in info) { + return callback(null, info.hash); + } -var QUANTIFIERS_GRAPH = 'urn:n3:quantifiers'; + // 1) Initialize nquads to an empty list. It will be used to store quads in + // N-Quads format. + var nquads = []; -var absoluteIRI = /^[a-z][a-z0-9+.-]*:/i, - schemeAuthority = /^(?:([a-z][a-z0-9+.-]*:))?(?:\/\/[^\/]*)?/i, - dotSegments = /(?:^|\/)\.\.?(?:$|[\/#?])/; + // 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; -// The next ID for new blank nodes -var blankNodePrefix = 0, blankNodeCount = 0; + // 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: -// ## Constructor -function N3Parser(options) { - if (!(this instanceof N3Parser)) - return new N3Parser(options); - this._contextStack = []; - this._graph = null; + // 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(); - // Set the document IRI - options = options || {}; - this._setBase(options.documentIRI); + // 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); + }); +}; - // 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; - }; +// helper for modifying component during Hash First Degree Quads +Normalize.prototype.modifyFirstDegreeComponent = function(id, component) { + if(component.type !== 'blank node') { + return component; } - 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; + component = _clone(component); + component.value = (component.value === id ? '_:a' : '_:z'); + return component; }; -N3Parser.prototype = { - // ## Private methods +// 4.7) Hash Related Blank Node +Normalize.prototype.hashRelatedBlankNode = function( + related, quad, issuer, position, callback) { + var self = this; - // ### `_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); + // 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(); + }); } - }, - - // ### `_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; + ], function(err) { + if(err) { + return callback(err); } - }, - // ### `_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); - } - }, + // 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); - // ### `_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); + // 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)); } - // 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); - } + // 4) Append identifier to input. + md.update(id); - // The next token must be a predicate, - // or, if the subject was actually a graph IRI, a named graph - return this._readPredicateOrNamedGraph; - }, + // 5) Return the hash that results from passing input through the hash + // algorithm. + return callback(null, md.digest()); + }); +}; - // ### `_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; - }, +// helper for getting a related predicate +Normalize.prototype.getRelatedPredicate = function(quad) { + return '<' + quad.predicate.value + '>'; +}; - // ### `_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(); - }, +// 4.8) Hash N-Degree Quads +Normalize.prototype.hashNDegreeQuads = function(id, issuer, callback) { + var self = this; - // ### `_readPredicateOrNamedGraph` reads a triple's predicate, or a named graph - _readPredicateOrNamedGraph: function (token) { - return token.type === '{' ? this._readGraph(token) : this._readPredicate(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(); + }); + }, + function(callback) { + // 4) Create an empty string, data to hash. + // Note: We created a hash object `md` above instead. - // ### `_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; - }, + // 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); - // ### `_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); - } - }, + // 5.2) Create a string chosen path. + var chosenPath = ''; - // ### `_readBlankNodeTail` reads the end of a blank node - _readBlankNodeTail: function (token) { - if (token.type !== ']') - return this._readBlankNodePunctuation(token); + // 5.3) Create an unset chosen issuer variable. + var chosenIssuer; - // Store blank node triple - if (this._subject !== null) - this._triple(this._subject, this._predicate, this._object, this._graph); + // 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(); - // 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(); - }, + // 5.4.1) Create a copy of issuer, issuer copy. + var issuerCopy = issuer.clone(); - // ### `_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); - }, + // 5.4.2) Create a string path. + var path = ''; - // ### `_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 + // 5.4.3) Create a recursion list, to store blank node identifiers + // that must be recursively processed by this algorithm. + var recursionList = []; - 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; - } + 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); + } - // Create a new blank node if no item head was assigned yet - if (list === null) - this._subject = list = '_:b' + blankNodeCount++; + // 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); + } - // 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.4.5.2) Use the Issue Identifier algorithm, passing issuer + // copy and related and append the result to path. + path += issuerCopy.getId(related); - // ### `_readDataTypeOrLang` reads an _optional_ data type or language - _readDataTypeOrLang: function (token) { - return this._completeLiteral(token, false); - }, + // 5.4.5.3) Append <, the hash in result, and > to path. + path += '<' + result.hash + '>'; - // ### `_readListItemDataTypeOrLang` reads an _optional_ data type or language in a list - _readListItemDataTypeOrLang: function (token) { - return this._completeLiteral(token, true); - }, + // 5.4.5.4) Set issuer copy to the identifier issuer in + // result. + issuerCopy = result.issuer; - // ### `_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.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); + } + + // 5.5) Append chosen path to data to hash. + md.update(chosenPath); + + // 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}); + }); +}; - // ### `_readFormulaTail` reads the end of a formula - _readFormulaTail: function (token) { - if (token.type !== '}') - return this._readPunctuation(token); +// helper for creating hash to related blank nodes map +Normalize.prototype.createHashToRelated = function(id, issuer, callback) { + var self = this; - // Store the last triple of the formula - if (this._subject !== null) - this._triple(this._subject, this._predicate, this._object, this._graph); + // 1) Create a hash to related blank nodes map for storing hashes that + // identify related blank nodes. + var hashToRelated = {}; - // 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(); - }, + // 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; - // ### `_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; + // 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(); } - 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; - }, + // 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); + }); +}; - // ### `_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); +// 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; } - // A triple has been completed now, so return it - this._triple(this._subject, this._predicate, this._object, this._graph); - return next; - }, + op(quad[key], key, quad); + } +}; - // ### `_readQuadPunctuation` reads punctuation after a quad - _readQuadPunctuation: function (token) { - if (token.type !== '.') - return this._error('Expected dot to follow quad', token); - return this._readInTopContext; - }, +return Normalize; - // ### `_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; - }, +})(); // end of define URDNA2015 - // ### `_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; - }, +/////////////////////////////// DEFINE URGNA2012 ////////////////////////////// - // ### `_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; - }, +var URGNA2012 = (function() { - // ### `_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); - } - }, +var Normalize = function(options) { + URDNA2015.call(this, options); + this.name = 'URGNA2012'; +}; +Normalize.prototype = new URDNA2015(); - // ### `_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; - }, +// 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; +}; - // ### `_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); +// helper for getting a related predicate +Normalize.prototype.getRelatedPredicate = function(quad) { + return quad.predicate.value; +}; + +// helper for creating hash to related blank nodes map +Normalize.prototype.createHashToRelated = function(id, issuer, callback) { + var self = this; + + // 1) Create a hash to related blank nodes map for storing hashes that + // identify related blank nodes. + var hashToRelated = {}; + + // 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; + + // 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); + }); +}; - if (token.type !== '.') - return this._error('Expected declaration to end with a dot', token); - return this._readInTopContext; - }, +return Normalize; - // 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); +})(); // end of define URGNA2012 + +/** + * 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); } - // 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; + } + + // add non-object to list + if(!_isObject(input)) { + if(list) { + list.push(input); } - return this._readQuantifierPunctuation; - }, + return; + } - // 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; + // 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); } - // Read a dot - this._readCallback = this._getContextEndReader(); - return this._readCallback(token); } - }, + if(list) { + list.push(input); + } + return; + } - // ### `_getPathReader` reads a potential path and then resumes with the given function - _getPathReader: function (afterPath) { - this._afterPath = afterPath; - return this._readPath; - }, + // Note: At this point, input must be a subject. - // ### `_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); + // 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); } - 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; - }, + // get name for subject + if(_isUndefined(name)) { + name = _isBlankNode(input) ? issuer.getId(input['@id']) : input['@id']; + } - // ### `_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; - }, + // add subject reference to list + if(list) { + list.push({'@id': name}); + } - // ### `_getContextEndReader` gets the next reader function at the end of a context - _getContextEndReader: function () { - var contextStack = this._contextStack; - if (!contextStack.length) - return this._readPunctuation; + // 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]; - switch (contextStack[contextStack.length - 1].type) { - case 'blank': - return this._readBlankNodeTail; - case 'list': - return this._readListItem; - case 'formula': - return this._readFormulaTail; + // skip @id + if(property === '@id') { + continue; } - }, - - // ### `_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); + // 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; } - }, - // ### `_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 = '/'; + // 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; + } - 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; - } - } - } + // 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}); } - next = iri[++i]; + subject[property] = input[property]; + continue; } - return result + iri.substring(segmentStart); - }, - // ## Public methods + // iterate over objects + var objects = input[property]; - // ### `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); + // if property is a bnode, assign it a new id + if(property.indexOf('_:') === 0) { + property = issuer.getId(property); + } - // 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; + // 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]; - // 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); - }); - }, -}; + if(property === '@type') { + // rename @type blank nodes + o = (o.indexOf('_:') === 0) ? issuer.getId(o) : o; + } -// The empty function -function noop() {} + // 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']; -// ## Exports -module.exports = N3Parser; + // 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}); + } + } + } +} -},{"./N3Lexer":32}],34:[function(_dereq_,module,exports){ -// **N3Store** objects store N3 triples by graph in memory. +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; +} -var expandPrefixedName = _dereq_('./N3Util').expandPrefixedName; +/** + * 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]; -// ## Constructor -function N3Store(triples, options) { - if (!(this instanceof N3Store)) - return new N3Store(triples, options); + // 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') + }; - // 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; + // filter out subjects that match the frame + var matches = _filterSubjects(state, subjects, frame, flags); - // Shift parameters if `triples` is not given - if (!options && triples && !triples[0]) - options = triples, triples = null; - options = options || {}; + // 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]; - // Add triples and prefixes if passed - this._prefixes = Object.create(null); - if (options.prefixes) - this.addPrefixes(options.prefixes); - if (triples) - this.addTriples(triples); -} + 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 -N3Store.prototype = { - // ## Public properties + // add existing linked subject + _addFrameOutput(parent, property, state.link[id]); + continue; + } - // ### `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; + /* 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 = {}; + } - // 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; - }, + // start output for subject + var output = {}; + output['@id'] = id; + state.link[id] = output; - // ## Private methods + // 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; + } - // ### `_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; - }, + // 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}; + } - // ### `_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]; + // push matching subject onto stack to enable circular embed checks + state.subjectStack.push(subject); - // Remove intermediary index layers if they are empty - for (key in index2) return; - delete index1[key1]; - for (key in index1) return; - delete index0[key0]; - }, + // iterate over subject properties + var props = Object.keys(subject).sort(); + for(var i = 0; i < props.length; i++) { + var prop = props[i]; - // ### `_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; + // copy keywords to output + if(_isKeyword(prop)) { + output[prop] = _clone(subject[prop]); + continue; + } - // 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]; + // explicit is on and property isn't in the frame, skip processing + if(flags.explicit && !(prop in frame)) { + continue; + } - 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]; + // add objects + var objects = subject[prop]; + for(var oi = 0; oi < objects.length; ++oi) { + var o = objects[oi]; - 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; + // recurse into list + if(_isList(o)) { + // add empty list + var list = {'@list': []}; + _addFrameOutput(output, prop, list); + + // 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; + } + + 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)); } } } - return array; - }, - // ### `_loop` executes the callback on all keys of index 0 - _loop: function (index0, callback) { - for (var key0 in index0) - callback(key0); - }, + // handle defaults + var props = Object.keys(frame).sort(); + for(var i = 0; i < props.length; ++i) { + var prop = props[i]; - // ### `_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); - } - }, + // skip keywords + if(_isKeyword(prop)) { + continue; + } - // ### `_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); + // 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}]; + } } - }, - // ### `_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); - } - }, + // add output to parent + _addFrameOutput(parent, property, output); - // ### `_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; + // pop matching subject from circular ref-checking stack + state.subjectStack.pop(); + } +} - // 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; - } - } - } +/** + * 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 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 + } + return [frame]; +} - // ### `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; +/** + * 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; +} - // 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); +/** + * 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; +} - // 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); +/** + * 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 changed = this._addToIndex(graphItem.subjects, subject, predicate, object); - this._addToIndex(graphItem.predicates, predicate, object, subject); - this._addToIndex(graphItem.objects, object, subject, predicate); +/** + * 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; +} - // The cached triple count is now invalid - this._size = null; - return changed; - }, +/** + * 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; + } - // ### `addTriples` adds multiple N3 triples to the store - addTriples: function (triples) { - for (var i = triples.length - 1; i >= 0; i--) - this.addTriple(triples[i]); - }, + // 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; - // ### `addPrefix` adds support for querying with the given prefix - addPrefix: function (prefix, iri) { - this._prefixes[prefix] = iri; - }, + // check @id for a specific @id value + if(key === '@id' && _isString(frame[key])) { + if(subject[key] !== frame[key]) { + return false; + } + matchesSome = true; + continue; + } + } - // ### `addPrefixes` adds support for querying with the given prefixes - addPrefixes: function (prefixes) { - for (var prefix in prefixes) - this.addPrefix(prefix, prefixes[prefix]); - }, + wildcard = false; - // ### `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 || ''; + 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; + } - // 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)) + // 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; + } + } - // 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--; + // return true if wildcard or subject matches some properties + return wildcard || matchesSome; +} - // Remove the graph if it is empty - for (subject in graphItem.subjects) return true; - delete graphs[graph]; - return true; - }, +/** + * 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; - // ### `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 reference to replace embed + var subject = {'@id': id}; - // ### `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) - ); - }, + // 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}); + } - // ### `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; + // 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); +} - // Translate IRIs to internal index keys. - if (isString(subject) && !(subjectId = ids[subject]) || - isString(predicate) && !(predicateId = ids[predicate]) || - isString(object) && !(objectId = ids[object])) - return quads; +/** + * 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); + } +} - 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); +/** + * 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); } } - 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) - ); - }, + input = output; + } else if(_isObject(input)) { + // remove @preserve + if('@preserve' in input) { + if(input['@preserve'] === '@null') { + return null; + } + return input['@preserve']; + } - // ### `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; + // skip @values + if(_isValue(input)) { + return input; + } - // Translate IRIs to internal index keys. - if (isString(subject) && !(subjectId = ids[subject]) || - isString(predicate) && !(predicateId = ids[predicate]) || - isString(object) && !(objectId = ids[object])) - return 0; + // recurse through @lists + if(_isList(input)) { + input['@list'] = _removePreserve(ctx, input['@list'], options); + return input; + } - 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); + // 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]; } } - 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) - ); - }, + // 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; + } + } + return input; +} - // ### `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) - ); - }, +/** + * 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; +} - // ### `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; - }, +/** + * 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'; + } - // ### `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) - ); - }, + // preferences for the value of @type or @language + var prefs = []; - // ### `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; + // 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'); - // Translate IRIs to internal index keys. - if (isString(subject) && !(subjectId = ids[subject]) || - isString(predicate) && !(predicateId = ids[predicate]) || - isString(object) && !(objectId = ids[object])) - return false; + 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; + } - 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; - } + 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; } - } - 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) - ); - }, + // select term + return typeOrLanguageValueMap[pref]; + } + } - // ### `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; - }, + return null; +} - // ### `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) - ); - }, +/** + * 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; + } - // ### `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); + // default value and parent to null + if(_isUndefined(value)) { + value = null; + } + // default reverse to false + if(_isUndefined(reverse)) { + reverse = false; + } + relativeTo = relativeTo || {}; - // Translate IRIs to internal index keys. - if (isString(predicate) && !(predicateId = ids[predicate]) || - isString(object) && !(objectId = ids[object])) - return; + var inverseCtx = activeCtx.getInverse(); - 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); - } + // 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; + } - // ### `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) - ); - }, + // use inverse context to pick a term if iri is relative to vocab + if(relativeTo.vocab && iri in inverseCtx) { + var defaultLanguage = activeCtx['@language'] || '@none'; - // ### `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; - }, + // prefer @index if available in value + var containers = []; + if(_isObject(value) && '@index' in value) { + containers.push('@index'); + } - // ### `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) - ); - }, + // defaults for term selection based on type/language + var typeOrLanguage = '@language'; + var typeOrLanguageValue = '@null'; - // ### `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); + 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']; + } + } else { + typeOrLanguage = '@type'; + typeOrLanguageValue = '@id'; + } + containers.push('@set'); + } - // Translate IRIs to internal index keys. - if (isString(subject) && !(subjectId = ids[subject]) || - isString(object) && !(objectId = ids[object])) - return; + // do term selection + containers.push('@none'); + var term = _selectTerm( + activeCtx, iri, value, containers, typeOrLanguage, typeOrLanguageValue); + if(term !== null) { + return term; + } + } - 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); + // 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; } - 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) - ); - }, + // 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)); - // ### `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; - }, + // 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; + } + } + } - // ### `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) - ); - }, + // return chosen curie + if(choice !== null) { + return choice; + } - // ### `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); + // compact IRI relative to base + if(!relativeTo.vocab) { + return _removeBase(activeCtx['@base'], iri); + } - // Translate IRIs to internal index keys. - if (isString(subject) && !(subjectId = ids[subject]) || - isString(predicate) && !(predicateId = ids[predicate])) - return; + // return IRI as is + return iri; +} - 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; - }, +/** + * 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'); - // ### `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) - ); - }, + // whether or not the value has an @index that must be preserved + var preserveIndex = (('@index' in value) && + container !== '@index'); - // ### `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); + // 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']; + } } - }, - // ### `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]); + // 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']; } - // 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":37}],35:[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); }); + var rval = {}; - // 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); + // preserve @index + if(preserveIndex) { + rval[_compactIri(activeCtx, '@index')] = value['@index']; + } -// ## Exports -module.exports = N3StreamParser; + 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']; + } -},{"./N3Parser.js":33,"stream":107,"util":118}],36:[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'); + // alias @value + rval[_compactIri(activeCtx, '@value')] = value['@value']; -// ## Constructor -function N3StreamWriter(options) { - if (!(this instanceof N3StreamWriter)) - return new N3StreamWriter(options); + return rval; + } - // Initialize Transform base class - Transform.call(this, { encoding: 'utf8' }); - this._writableState.objectMode = true; + // 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'}); - // 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); + // compact to scalar + if(type === '@id' || type === '@vocab' || expandedProperty === '@graph') { + return compacted; + } - // Implement Transform methods on top of writer - this._transform = function (triple, encoding, done) { writer.addTriple(triple, done); }; - this._flush = function (done) { writer.end(done); }; + var rval = {}; + rval[_compactIri(activeCtx, '@id')] = compacted; + return rval; } -util.inherits(N3StreamWriter, Transform); - -// ## Exports -module.exports = N3StreamWriter; - -},{"./N3Writer.js":38,"stream":107,"util":118}],37:[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 !== '_'; +/** + * 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; } - }, - - // Tests whether the given entity (triple object) represents a literal in the N3 library - isLiteral: function (entity) { - return typeof entity === 'string' && entity[0] === '"'; - }, + // cycle detected + throw new JsonLdError( + 'Cyclical context definition detected.', + 'jsonld.CyclicalContext', + {code: 'cyclic IRI mapping', context: localCtx, term: term}); + } - // 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) === '_:'; - }, + // now defining term + defined[term] = false; - // Tests whether the given entity represents the default graph - isDefaultGraph: function (entity) { - return !entity; - }, + if(_isKeyword(term)) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; keywords cannot be overridden.', + 'jsonld.SyntaxError', + {code: 'keyword redefinition', context: localCtx, term: term}); + } - // Tests whether the given triple is in the default graph - inDefaultGraph: function (triple) { - return !triple.graph; - }, + if(term === '') { + throw new JsonLdError( + 'Invalid JSON-LD syntax; a term cannot be an empty string.', + 'jsonld.SyntaxError', + {code: 'invalid term definition', context: localCtx}); + } - // 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]; - }, + // remove old mapping + if(activeCtx.mappings[term]) { + delete activeCtx.mappings[term]; + } - // 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); - }, + // get context term value + var value = localCtx[term]; - // 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() : ''; - }, + // clear context entry + if(value === null || (_isObject(value) && value['@id'] === null)) { + activeCtx.mappings[term] = null; + defined[term] = true; + return; + } - // Tests whether the given entity (triple object) represents a prefixed name - isPrefixedName: function (entity) { - return typeof entity === 'string' && /^[^:\/"']*:[^:\/"']+$/.test(entity); - }, + // convert short-hand value to object w/@id + if(_isString(value)) { + value = {'@id': value}; + } - // 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; + 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}); + } - // 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); - }, + // create new mapping + var mapping = activeCtx.mappings[term] = {}; + mapping.reverse = false; - // Creates an IRI in N3.js representation - createIRI: function (iri) { - return iri && iri[0] === '"' ? N3Util.getLiteralValue(iri) : iri; - }, + 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}); + } - // 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 + '"'; + // 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; } - 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 })(''); - }, + // always compute whether term has a colon as an optimization for + // _compactIri + var colon = term.indexOf(':'); + mapping._termHasColon = (colon !== -1); - // 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]); + 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); + } - // 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); - }; + 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; } - return prefixes[prefix]; + } 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}); + } + // prepend vocab to term + mapping['@id'] = activeCtx['@vocab'] + term; } - return processPrefix; - }, -}; + } -// ## Exports -module.exports = N3Util; + // IRI mapping now defined + defined[term] = true; -},{}],38:[function(_dereq_,module,exports){ -// **N3Writer** writes N3 documents. + 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}); + } -// Matches a literal as represented in memory by the N3 library -var N3LiteralMatcher = /^"([^]*)"(?:\^\^(.+)|@([\-a-z]+))?$/i; + 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}); + } + } -// rdf:type predicate (for 'a' abbreviation) -var RDF_PREFIX = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', - RDF_TYPE = RDF_PREFIX + 'type'; + // add @type to mapping + mapping['@type'] = 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', - }; + 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}); + } -// ## Constructor -function N3Writer(outputStream, options) { - if (!(this instanceof N3Writer)) - return new N3Writer(outputStream, options); + // add @container to mapping + mapping['@container'] = container; + } - // Shift arguments if the first argument is not a stream - if (outputStream && typeof outputStream.write !== 'function') - options = outputStream, outputStream = null; - options = options || {}; + 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}); + } - // 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; + // add @language to mapping + if(language !== null) { + language = language.toLowerCase(); + } + mapping['@language'] = language; } - else { - this._outputStream = outputStream; - this._endStream = options.end === undefined ? true : !!options.end; + + // 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}); } +} - // 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); +/** + * 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; } - else { - this._writeTriple = this._writeTripleLine; + + // ensure value is interpreted as a string + value = String(value); + + // define term dependency if not defined + if(localCtx && value in localCtx && defined[value] !== true) { + _createTermDefinition(activeCtx, localCtx, value, defined); } -} -N3Writer.prototype = { - // ## Private methods + relativeTo = relativeTo || {}; + if(relativeTo.vocab) { + var mapping = activeCtx.mappings[value]; - // ### `_write` writes the argument to the output stream - _write: function (string, callback) { - this._outputStream.write(string, 'utf8', callback); - }, + // value is explicitly ignored with a null mapping + if(mapping === null) { + return null; + } - // ### `_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); - } - // 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); + if(mapping) { + // value is a term + return mapping['@id']; } - 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); } - }, + // split value into prefix:suffix + var colon = value.indexOf(':'); + if(colon !== -1) { + var prefix = value.substr(0, colon); + var suffix = value.substr(colon + 1); - // ### `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'); - }, + // do not expand blank nodes (prefix of '_') or already-absolute + // IRIs (suffix of '//') + if(prefix === '_' || suffix.indexOf('//') === 0) { + return value; + } - // ### `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(''); - }, + // prefix dependency not defined, define it + if(localCtx && prefix in localCtx) { + _createTermDefinition(activeCtx, localCtx, prefix, defined); + } - // ### `_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]); - }, + // use mapping if prefix is defined + var mapping = activeCtx.mappings[prefix]; + if(mapping) { + return mapping['@id'] + suffix; + } - // ### `_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 + '"'; - }, + // already absolute IRI + 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); - }, + // prepend vocab + if(relativeTo.vocab && '@vocab' in activeCtx) { + return activeCtx['@vocab'] + value; + } - // ### `_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); - }, + // prepend base + var rval = value; + if(relativeTo.base) { + rval = jsonld.prependBase(activeCtx['@base'], rval); + } - // ### `_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]); - }, + return rval; +} - // ### `_blockedWrite` replaces `_write` after the writer has been closed - _blockedWrite: function () { - throw new Error('Cannot write because the writer has been closed.'); - }, +function _prependBase(base, iri) { + // skip IRI processing + if(base === null) { + return iri; + } + // already an absolute IRI + if(iri.indexOf(':') !== -1) { + 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); - }, + // parse base if it is a string + if(_isString(base)) { + base = jsonld.url.parse(base || ''); + } - // ### `addTriples` adds the triples to the output stream - addTriples: function (triples) { - for (var i = 0; i < triples.length; i++) - this.addTriple(triples[i]); - }, + // parse given IRI + var rel = jsonld.url.parse(iri); - // ### `addPrefix` adds the prefix to the output stream - addPrefix: function (prefix, iri, done) { - var prefixes = {}; - prefixes[prefix] = iri; - this.addPrefixes(prefixes, done); - }, + // per RFC3986 5.2.2 + var transform = { + protocol: base.protocol || '' + }; - // ### `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'); - } - } - // 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); - }, + if(rel.authority !== null) { + transform.authority = rel.authority; + transform.path = rel.path; + transform.query = rel.query; + } else { + transform.authority = base.authority; - // ### `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]; + 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; - 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; + // 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; } - return contents + '\n]'; + transform.query = rel.query; } - }, + } - // ### `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(' ') + ')'; - }, + // remove slashes and dots in path + transform.path = _removeDotSegments(transform.path, !!transform.authority); - // ### `_prefixRegex` matches a prefixed name or IRI that begins with one of the added prefixes - _prefixRegex: /$0^/, + // 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; + } - // ### `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; + // handle empty base + if(rval === '') { + rval = './'; + } - // 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(); - }, -}; + return rval; +} -// 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; - } +/** + * 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; } - return result; -} -// ## Exports -module.exports = N3Writer; + if(_isString(base)) { + base = jsonld.url.parse(base || ''); + } -},{}],39:[function(_dereq_,module,exports){ -'use strict'; + // 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 += '//'; + } -// 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; - } -}; - -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 = []; + // IRI not relative to base + if(iri.indexOf(root) !== 0) { + return iri; + } - if (!isObject && !isFunction && !isArguments) { - throw new TypeError('Object.keys called on a non-object'); - } + // remove root from IRI and parse remainder + var rel = jsonld.url.parse(iri.substr(root.length)); - 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)); - } - } + // 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; + } + baseSegments.shift(); + iriSegments.shift(); + } - 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)); - } - } - } + // 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 += '../'; + } + } - if (hasDontEnumBug) { - var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); + // prepend remaining segments + rval += iriSegments.join('/'); - for (var k = 0; k < dontEnums.length; ++k) { - if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { - theKeys.push(dontEnums[k]); - } - } - } - return theKeys; -}; + // add query and hash + if(rel.query !== null) { + rval += '?' + rel.query; + } + if(rel.fragment !== null) { + rval += '#' + rel.fragment; + } -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; -}; + // handle empty base + if(rval === '') { + rval = './'; + } -module.exports = keysShim; + return rval; +} -},{"./isArguments":40}],40:[function(_dereq_,module,exports){ -'use strict'; +/** + * 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 + }; -var toStr = Object.prototype.toString; + /** + * 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; -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; -}; + // lazily create inverse + if(activeCtx.inverse) { + return activeCtx.inverse; + } + var inverse = activeCtx.inverse = {}; -},{}],41:[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 -*/ + // variables for building fast CURIE map + var fastCurieMap = activeCtx.fastCurieMap = {}; + var irisToTerms = {}; + // handle default language + var defaultLanguage = activeCtx['@language'] || '@none'; -function pp() { - this.shift = ['\n']; // array of shifts - this.step = ' ', // 2 spaces - maxdeep = 100, // nesting level - ix = 0; + // 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; + } - // 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; -} + // add new entry + if(!entry[container]) { + entry[container] = { + '@language': {}, + '@type': {} + }; + } + entry = entry[container]; -// ----------------------- JSON section ---------------------------------------------------- + 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); -pp.prototype.json = function(text) { + // add entries for no type and no language + _addPreferredTerm(mapping, term, entry['@type'], '@none'); + _addPreferredTerm(mapping, term, entry['@language'], '@none'); + } + } + } - 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; -} + // build fast CURIE map + for(var key in fastCurieMap) { + _buildIriMap(fastCurieMap, key, 1); + } -// ----------------------- CSS section ---------------------------------------------------- + return inverse; + } -pp.prototype.css = function(text) { + /** + * 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] = {}; - 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= iri.length) { + letter = ''; + } else { + letter = iri[idx]; + } + if(letter in next) { + next[letter].push(entries[i]); + } else { + next[letter] = [entries[i]]; + } + } - if( /\{/.exec(ar[ix])) { - str += this.shift[deep++]+ar[ix]; - } else - if( /\}/.exec(ar[ix])) { - str += this.shift[--deep]+ar[ix]; - } else - if( /\*\\/.exec(ar[ix])) { - str += this.shift[deep]+ar[ix]; - } - else { - str += this.shift[deep]+ar[ix]; - } - } - return str.replace(/^\n{1,}/,''); -} + for(var key in next) { + if(key === '') { + continue; + } + _buildIriMap(next, key, idx + 1); + } + } -// ----------------------- SQL section ---------------------------------------------------- + /** + * 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; + } + } -function isSubquery(str, parenthesisLevel) { - return parenthesisLevel - (str.replace(/\(/g,'').length - str.replace(/\)/g,'').length ) + /** + * 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; + } } -function split_sql(str, tab) { - - return str.replace(/\s{1,}/g," ") +/** + * 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; +} - .replace(/ AND /ig,"~::~"+tab+tab+"AND ") - .replace(/ BETWEEN /ig,"~::~"+tab+"BETWEEN ") - .replace(/ CASE /ig,"~::~"+tab+"CASE ") - .replace(/ ELSE /ig,"~::~"+tab+"ELSE ") - .replace(/ END /ig,"~::~"+tab+"END ") - .replace(/ FROM /ig,"~::~FROM ") - .replace(/ GROUP\s{1,}BY/ig,"~::~GROUP BY ") - .replace(/ HAVING /ig,"~::~HAVING ") - //.replace(/ IN /ig,"~::~"+tab+"IN ") - .replace(/ IN /ig," IN ") - .replace(/ JOIN /ig,"~::~JOIN ") - .replace(/ CROSS~::~{1,}JOIN /ig,"~::~CROSS JOIN ") - .replace(/ INNER~::~{1,}JOIN /ig,"~::~INNER JOIN ") - .replace(/ LEFT~::~{1,}JOIN /ig,"~::~LEFT JOIN ") - .replace(/ RIGHT~::~{1,}JOIN /ig,"~::~RIGHT JOIN ") - .replace(/ ON /ig,"~::~"+tab+"ON ") - .replace(/ OR /ig,"~::~"+tab+tab+"OR ") - .replace(/ ORDER\s{1,}BY/ig,"~::~ORDER BY ") - .replace(/ OVER /ig,"~::~"+tab+"OVER ") - .replace(/\(\s{0,}SELECT /ig,"~::~(SELECT ") - .replace(/\)\s{0,}SELECT /ig,")~::~SELECT ") - .replace(/ THEN /ig," THEN~::~"+tab+"") - .replace(/ UNION /ig,"~::~UNION~::~") - .replace(/ USING /ig,"~::~USING ") - .replace(/ WHEN /ig,"~::~"+tab+"WHEN ") - .replace(/ WHERE /ig,"~::~WHERE ") - .replace(/ WITH /ig,"~::~WITH ") - //.replace(/\,\s{0,}\(/ig,",~::~( ") - //.replace(/\,/ig,",~::~"+tab+tab+"") - .replace(/ ALL /ig," ALL ") - .replace(/ AS /ig," AS ") - .replace(/ ASC /ig," ASC ") - .replace(/ DESC /ig," DESC ") - .replace(/ DISTINCT /ig," DISTINCT ") - .replace(/ EXISTS /ig," EXISTS ") - .replace(/ NOT /ig," NOT ") - .replace(/ NULL /ig," NULL ") - .replace(/ LIKE /ig," LIKE ") - .replace(/\s{0,}SELECT /ig,"SELECT ") - .replace(/~::~{1,}/g,"~::~") - .split('~::~'); +/** + * 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]'); } -pp.prototype.sql = function(text) { +/** + * 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; +} - var ar_by_quote = text.replace(/\s{1,}/g," ") - .replace(/\'/ig,"~::~\'") - .split('~::~'), - len = ar_by_quote.length, - ar = [], - deep = 0, - tab = this.step,//+this.step, - inComment = true, - inQuote = false, - parenthesisLevel = 0, - str = '', - ix = 0; +/** + * 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); +} - for(ix=0;ix/g,""); - return str.replace(/>\s{0,}<"); +/** + * 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'); } -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,'],['); +/** + * 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; } -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,"*/"); -} +/** + * 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)); +} -pp.prototype.sqlmin = function(text) { - return text.replace(/\s{1,}/g," ").replace(/\s{1,}\(/,"(").replace(/\s{1,}\)/,")"); +/** + * 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); } -// -------------------------------------------------------------------------------------------- +/** + * 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); +} -exports.pd= new pp; +/** + * 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; +} +/** + * 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; +} +/** + * 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; +} +/** + * 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; + } + // get @context + var ctx = input[key]; + // 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; +} +/** + * 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; + // 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); + } + // for tracking the URLs to retrieve + var urls = {}; + // 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); + }; + // find all URLs in the given input + if(!_findContextUrls(input, urls, false, base)) { + // no new URLs in input + return finished(); + } -},{}],42:[function(_dereq_,module,exports){ -(function (process){ -'use strict'; + // queue all unretrieved URLs + var queue = []; + for(var url in urls) { + if(urls[url] === false) { + queue.push(url); + } + } -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; -} + // 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; + } -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); - }); - } -} + var ctx = remoteDoc ? remoteDoc.document : null; -}).call(this,_dereq_('_process')) + // parse string context as JSON + if(!err && _isString(ctx)) { + try { + ctx = JSON.parse(ctx); + } catch(ex) { + err = ex; + } + } -},{"_process":43}],43:[function(_dereq_,module,exports){ -// shim for using process in browser -var process = module.exports = {}; + // 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); + } -// 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. + // use empty context if no @context key is present + if(!('@context' in ctx)) { + ctx = {'@context': {}}; + } else { + ctx = {'@context': ctx['@context']}; + } -var cachedSetTimeout; -var cachedClearTimeout; + // append context URL to context if given + if(remoteDoc.contextUrl) { + if(!_isArray(ctx['@context'])) { + ctx['@context'] = [ctx['@context']]; + } + ctx['@context'].push(remoteDoc.contextUrl); + } -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 { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; + // 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); } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); + }(queue[i])); } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); + }; + retrieve(input, {}, documentLoader, options.base, callback); +} + +// 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'); } - 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); - } + var rval = []; + for(var p in o) { + if(Object.prototype.hasOwnProperty.call(o, p)) { + rval.push(p); + } } + return rval; + }; +} +/** + * 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 + '$'); -} -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); - } - } + // define quad part regexes + var subject = '(?:' + iri + '|' + bnode + ')' + ws; + var property = iri + ws; + var object = '(?:' + iri + '|' + bnode + '|' + literal + ')' + wso; + var graphName = '(?:\\.|(?:(?:' + iri + '|' + bnode + ')' + wso + '\\.))'; + // full quad regex + var quad = new RegExp( + '^' + wso + subject + property + object + graphName + wso + comment + '$'); + // build RDF dataset + var dataset = {}; -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; + // 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 cleanUpNextTick() { - if (!draining || !currentQueue) { - return; + // skip empty lines + if(empty.test(line)) { + continue; } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -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}); } - if (queue.length) { - drainQueue(); + + // 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]}; } -} -function drainQueue() { - if (draining) { - return; + // get predicate + triple.predicate = {type: 'IRI', value: match[3]}; + + // 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; } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; + // 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]; } - 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]; + // 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); + } } - 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; + return dataset; } -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 = {}; -function noop() {} - -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; +// register the N-Quads RDF parser +jsonld.registerRDFParser('application/nquads', _parseNQuads); -process.listeners = function (name) { return [] } +/** + * 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(''); +} -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; +/** + * 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; + } -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; + var quad = ''; -},{}],44:[function(_dereq_,module,exports){ -(function (global){ -/*! https://mths.be/punycode v1.4.1 by @mathias */ -;(function(root) { + // subject is an IRI + if(s.type === 'IRI') { + quad += '<' + s.value + '>'; + } else { + quad += s.value; + } + quad += ' '; - /** 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; - } + // predicate is an IRI + if(p.type === 'IRI') { + quad += '<' + p.value + '>'; + } else { + quad += p.value; + } + quad += ' '; - /** - * The `punycode` object. - * @name punycode - * @type Object - */ - var punycode, + // 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 + '>'; + } + } - /** Highest positive signed 32-bit float value */ - maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 + // graph + if(g !== null && g !== undefined) { + if(g.indexOf('_:') !== 0) { + quad += ' <' + g + '>'; + } else { + quad += ' ' + g; + } + } - /** Bootstring parameters */ - base = 36, - tMin = 1, - tMax = 26, - skew = 38, - damp = 700, - initialBias = 72, - initialN = 128, // 0x80 - delimiter = '-', // '\x2D' + quad += ' .\n'; + return quad; +} - /** Regular expressions */ - regexPunycode = /^xn--/, - regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars - regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators - - /** 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' - }, - - /** Convenience shortcuts */ - baseMinusTMin = base - tMin, - floor = Math.floor, - stringFromCharCode = String.fromCharCode, - - /** Temporary variable */ - key; - - /*--------------------------------------------------------------------------*/ +/** + * 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'] = []; - /** - * 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]); - } + var subjects = data.getSubjects(); + for(var si = 0; si < subjects.length; ++si) { + var subject = subjects[si]; + if(subject === null) { + continue; + } - /** - * 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; - } + // 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]; - /** - * 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; - } + // create RDF triple + var triple = {}; - /** - * 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; - } + // add subject + if(subject.indexOf('_:') === 0) { + triple.subject = {type: 'blank node', value: subject}; + } else { + triple.subject = {type: 'IRI', value: subject}; + } - /** - * 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(''); - } + // add predicate + if(predicate.indexOf('_:') === 0) { + triple.predicate = {type: 'blank node', value: predicate}; + } else { + triple.predicate = {type: 'IRI', value: predicate}; + } - /** - * 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; - } + // 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; + } + } + } - /** - * 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); - } + // add object + triple.object = {}; - /** - * 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)); - } + // 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; - /** - * 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; + // add triple to dataset in default graph + dataset['@default'].push(triple); + } + } + } - // 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. + return dataset; +} - basic = input.lastIndexOf(delimiter); - if (basic < 0) { - basic = 0; - } +// register the RDFa API RDF parser +jsonld.registerRDFParser('rdfa-api', _parseRdfaApiData); - 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)); - } +/** + * 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; - // Main decoding loop: start just after the last delimiter if any basic code - // points were copied; start at the beginning otherwise. +/** + * 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; +}; - for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { +/** + * 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]; + } - // `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) { + // get next identifier + var identifier = this.prefix + this.counter; + this.counter += 1; - if (index >= inputLength) { - error('invalid-input'); - } + // save mapping + if(old) { + this.existing[old] = identifier; + } - digit = basicToDigit(input.charCodeAt(index++)); + return identifier; +}; +// alias +IdentifierIssuer.prototype.getName = IdentifierIssuer.prototype.getName; - if (digit >= base || digit > floor((maxInt - i) / w)) { - error('overflow'); - } +/** + * 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; - i += digit * w; - t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); +/** + * 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; + } +}; - if (digit < t) { - break; - } +/** + * Returns true if there is another permutation. + * + * @return true if there is another permutation, false if not. + */ +Permutator.prototype.hasNext = function() { + return !this.done; +}; - baseMinusT = base - t; - if (w > floor(maxInt / baseMinusT)) { - error('overflow'); - } +/** + * 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(); - w *= baseMinusT; + /* Calculate the next permutation using the Steinhaus-Johnson-Trotter + permutation algorithm. */ - } + // 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; + } + } - out = output.length + 1; - bias = adapt(i - oldi, out, oldi == 0); + // 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; - // `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'); - } + // 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]]; + } + } + } - n += floor(i / out); - i %= out; + return rval; +}; - // Insert `n` at position `i` of the output - output.splice(i++, 0, n); +//////////////////////// DEFINE NORMALIZATION HASH API //////////////////////// - } +/** + * 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(); +}; - return ucs2encode(output); - } +// switch definition of NormalizeHash based on environment +(function(_nodejs) { - /** - * 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(_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; +} - // Convert the input in UCS-2 to Unicode - input = ucs2decode(input); +// 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(); +}; - // Cache the length - inputLength = input.length; +/////////////////////////// DEFINE MESSAGE DIGEST API ///////////////////////// - // Initialize the state - n = initialN; - delta = 0; - bias = initialBias; +/** + * Creates a new MessageDigest. + * + * @param algorithm the algorithm to use. + */ +var MessageDigest = function(algorithm) { + if(!(this instanceof MessageDigest)) { + return new MessageDigest(algorithm); + } - // Handle the basic code points - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; - if (currentValue < 0x80) { - output.push(stringFromCharCode(currentValue)); - } - } + this._algorithm = algorithm; - handledCPCount = basicLength = output.length; + // 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; + } + } + } - // `handledCPCount` is the number of code points that have been handled; - // `basicLength` is the number of basic code points. + // start digest automatically for first time + this.start(); +}; - // Finish the basic string - if it is not empty - with a delimiter - if (basicLength) { - output.push(delimiter); - } +/** + * Starts the digest. + * + * @return this digest object. + */ +MessageDigest.prototype.start = function() { + // up to 56-bit message length for convenience + this.messageLength = 0; - // Main encoding loop: - while (handledCPCount < inputLength) { + // full message length + this.fullMessageLength = []; + var int32s = this._algorithm.messageLengthSize / 4; + for(var i = 0; i < int32s; ++i) { + this.fullMessageLength.push(0); + } - // 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; - } - } + // input buffer + this._input = new MessageDigest.ByteBuffer(); - // 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'); - } + // get starting state + this.state = this._algorithm.start(); - delta += (m - n) * handledCPCountPlusOne; - n = m; + return this; +}; - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; +/** + * 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))); - if (currentValue < n && ++delta > maxInt) { - error('overflow'); - } + // 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); + } - 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); - } + // add bytes to input buffer + this._input.putBytes(msg.bytes()); - output.push(stringFromCharCode(digitToBasic(q, 0))); - bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); - delta = 0; - ++handledCPCount; - } - } + // digest blocks + while(this._input.length() >= this._algorithm.blockSize) { + this.state = this._algorithm.digest(this.state, this._input); + } - ++delta; - ++n; + // compact input buffer every 2K or if empty + if(this._input.read > 2048 || this._input.length() === 0) { + this._input.compact(); + } - } - return output.join(''); - } + return this; +}; - /** - * 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; - }); - } +/** + * 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. */ - /** - * 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; - }); - } + /* 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. - /*--------------------------------------------------------------------------*/ + 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). - /** 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 - }; + 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. */ - /** 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; - } + // create final block + var finalBlock = new MessageDigest.ByteBuffer(); + finalBlock.putBytes(this._input.bytes()); -}(this)); + // compute remaining size to be digested (include message length size) + var remaining = ( + this.fullMessageLength[this.fullMessageLength.length - 1] + + this._algorithm.messageLengthSize); -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) + // 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)); -},{}],45:[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. + // 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)); + } -'use strict'; + // write the length of the message (algorithm-specific) + this._algorithm.writeMessageLength(finalBlock, messageLength); -// 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); -} + // digest final block + var state = this._algorithm.digest(this.state.copy(), finalBlock); -module.exports = function(qs, sep, eq, options) { - sep = sep || '&'; - eq = eq || '='; - var obj = {}; + // write state to buffer + var rval = new MessageDigest.ByteBuffer(); + state.write(rval); + return rval; +}; - if (typeof qs !== 'string' || qs.length === 0) { - return obj; +/** + * 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; +}; - var regexp = /\+/g; - qs = qs.split(sep); +/** + * 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)); +}; - var maxKeys = 1000; - if (options && typeof options.maxKeys === 'number') { - maxKeys = options.maxKeys; - } +/** + * 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 len = qs.length; - // maxKeys <= 0 means that we should not limit keys count - if (maxKeys > 0 && len > maxKeys) { - len = maxKeys; - } +/** + * 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; +}; - for (var i = 0; i < len; ++i) { - var x = qs[i].replace(regexp, '%20'), - idx = x.indexOf(eq), - kstr, vstr, k, v; +/** + * 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); +}; - if (idx >= 0) { - kstr = x.substr(0, idx); - vstr = x.substr(idx + 1); - } else { - kstr = x; - vstr = ''; - } +/** + * 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; +}; - k = decodeURIComponent(kstr); - v = decodeURIComponent(vstr); +/** + * Compacts this buffer. + */ +MessageDigest.ByteBuffer.prototype.compact = function() { + this.data = this.data.slice(this.read); + this.read = 0; +}; - if (!hasOwnProperty(obj, k)) { - obj[k] = v; - } else if (isArray(obj[k])) { - obj[k].push(v); - } else { - obj[k] = [obj[k], v]; +/** + * 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 obj; + return rval; }; -var isArray = Array.isArray || function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; +///////////////////////////// DEFINE SHA-1 ALGORITHM ////////////////////////// + +var sha1 = { + // used for word storage + _w: null }; -},{}],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. - -'use strict'; - -var stringifyPrimitive = function(v) { - switch (typeof v) { - case 'string': - return v; - - case 'boolean': - return v ? 'true' : 'false'; - - case 'number': - return isFinite(v) ? v : ''; - - default: - return ''; - } +sha1.Algorithm = function() { + this.name = 'sha1', + this.blockSize = 64; + this.digestLength = 20; + this.messageLengthSize = 8; }; -module.exports = function(obj, sep, eq, name) { - sep = sep || '&'; - eq = eq || '='; - if (obj === null) { - obj = undefined; - } - - 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); - +sha1.Algorithm.prototype.start = function() { + if(!sha1._w) { + sha1._w = new Array(80); } - - if (!name) return ''; - return encodeURIComponent(stringifyPrimitive(name)) + eq + - encodeURIComponent(stringifyPrimitive(obj)); -}; - -var isArray = Array.isArray || function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; + return sha1._createState(); }; -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; -} - -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; +sha1.Algorithm.prototype.writeMessageLength = function( + finalBlock, messageLength) { + // message length is in bits and in big-endian order; simply append + finalBlock.putBytes(messageLength.bytes()); }; -},{}],47:[function(_dereq_,module,exports){ -'use strict'; - -exports.decode = exports.parse = _dereq_('./decode'); -exports.encode = exports.stringify = _dereq_('./encode'); +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; -},{"./decode":45,"./encode":46}],48:[function(_dereq_,module,exports){ -'use strict'; + // 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 -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; }; }(); + // 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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + // 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; -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; } + len -= 64; + } -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 s; +}; -var ClassOrder = _dereq_('./class-order'); -var Node = _dereq_('./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; +}; -var BlankNode = function (_Node) { - _inherits(BlankNode, _Node); +//////////////////////////// DEFINE SHA-256 ALGORITHM ///////////////////////// - function BlankNode(id) { - _classCallCheck(this, BlankNode); +var sha256 = { + // shared state + _k: null, + _w: null +}; - var _this = _possibleConstructorReturn(this, (BlankNode.__proto__ || Object.getPrototypeOf(BlankNode)).call(this)); +sha256.Algorithm = function() { + this.name = 'sha256', + this.blockSize = 64; + this.digestLength = 32; + this.messageLengthSize = 8; +}; - _this.termType = BlankNode.termType; - _this.id = BlankNode.nextId++; - _this.value = id || _this.id.toString(); - return _this; +sha256.Algorithm.prototype.start = function() { + if(!sha256._k) { + sha256._init(); } + return sha256._createState(); +}; - _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; - } - if (this.id > other.id) { - return +1; - } - 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; +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(); } - }, { - key: 'toString', - value: function toString() { - return BlankNode.NTAnonymousNodePrefix + this.id; + 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 BlankNode; -}(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; -BlankNode.nextId = 0; -BlankNode.termType = 'BlankNode'; -BlankNode.NTAnonymousNodePrefix = '_:n'; -BlankNode.prototype.classOrder = ClassOrder['BlankNode']; -BlankNode.prototype.isBlank = 1; -BlankNode.prototype.isVar = 1; + // 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 = BlankNode; -},{"./class-order":49,"./node":65}],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 ClassOrder = { - 'Literal': 1, - 'Collection': 3, - 'Graph': 4, - 'NamedNode': 5, - 'BlankNode': 6, - 'Variable': 7 + // 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; }; -module.exports = ClassOrder; -},{}],50:[function(_dereq_,module,exports){ -'use strict'; +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 _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; }; }(); +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]; -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + // used for word storage + sha256._w = new Array(64); +}; -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; } +})(_nodejs); // end definition of NormalizeHash -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; } +if(!XMLSerializer) { -var BlankNode = _dereq_('./blank-node'); -var ClassOrder = _dereq_('./class-order'); -var Node = _dereq_('./node'); +var _defineXMLSerializer = function() { + XMLSerializer = _dereq_('xmldom').XMLSerializer; +}; -var Collection = function (_Node) { - _inherits(Collection, _Node); +} // end _defineXMLSerializer - function Collection(initial) { - _classCallCheck(this, Collection); +// 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; +}; - var _this = _possibleConstructorReturn(this, (Collection.__proto__ || Object.getPrototypeOf(Collection)).call(this)); +/** + * 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 = ''; - _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; + 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()); + } + + 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}); + } + }; + + // 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; + } + + if(_browser) { + // export simple browser API + if(typeof jsonld === 'undefined') { + jsonld = jsonldjs = factory; + } else { + jsonldjs = factory; + } + } +} + +return factory; + +})(); + +}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},"/node_modules/jsonld/js") + +},{"_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'); + +module.exports = pkg; + +},{"./src/libsbgn":130}],57:[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.classOrder > other.classOrder) { + return +1; + } + if (this.id < other.id) { + return -1; + } + if (this.id > other.id) { + return +1; + } + 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":58,"./node":74}],58:[function(_dereq_,module,exports){ +'use strict'; + +var ClassOrder = { + 'Literal': 1, + 'Collection': 3, + 'Graph': 4, + 'NamedNode': 5, + 'BlankNode': 6, + 'Variable': 7 +}; + +module.exports = ClassOrder; +},{}],59:[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)); + }); + } + return _this; } _createClass(Collection, [{ @@ -21192,7 +18933,7 @@ Collection.prototype.compareTerm = BlankNode.prototype.compareTerm; Collection.prototype.isVar = 0; module.exports = Collection; -},{"./blank-node":48,"./class-order":49,"./node":65}],51:[function(_dereq_,module,exports){ +},{"./blank-node":57,"./class-order":58,"./node":74}],60:[function(_dereq_,module,exports){ 'use strict'; module.exports.convertToJson = convertToJson; @@ -21255,7 +18996,7 @@ function convertToNQuads(n3String, nquadCallback) { nquadCallback(err, nquadString); }); } -},{"async":1,"jsonld":18,"n3":82}],52:[function(_dereq_,module,exports){ +},{"async":1,"jsonld":55,"n3":91}],61:[function(_dereq_,module,exports){ 'use strict'; var _indexedFormula = _dereq_('./indexed-formula'); @@ -21335,7 +19076,7 @@ module.exports.collection = collection; module.exports.fetcher = fetcher; module.exports.lit = lit; module.exports.st = st; -},{"./blank-node":48,"./collection":50,"./default-graph":53,"./fetcher":55,"./indexed-formula":58,"./literal":60,"./named-node":63,"./statement":75,"./variable":80}],53:[function(_dereq_,module,exports){ +},{"./blank-node":57,"./collection":59,"./default-graph":62,"./fetcher":64,"./indexed-formula":67,"./literal":69,"./named-node":72,"./statement":84,"./variable":89}],62:[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; }; }(); @@ -21372,7 +19113,7 @@ var DefaultGraph = function (_Node) { }(Node); module.exports = DefaultGraph; -},{"./node":65}],54:[function(_dereq_,module,exports){ +},{"./node":74}],63:[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; }; }(); @@ -21414,7 +19155,7 @@ var Empty = function (_Node) { Empty.termType = 'empty'; module.exports = Empty; -},{"./node":65}],55:[function(_dereq_,module,exports){ +},{"./node":74}],64:[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; }; @@ -23024,7 +20765,7 @@ var Fetcher = function Fetcher(store, timeout, async) { }; // End of fetcher module.exports = Fetcher; -},{"./log":61,"./n3parser":62,"./named-node":63,"./namespace":64,"./parse":66,"./rdfaparser":70,"./rdfxmlparser":71,"./serialize":72,"./uri":78,"./util":79}],56:[function(_dereq_,module,exports){ +},{"./log":70,"./n3parser":71,"./named-node":72,"./namespace":73,"./parse":75,"./rdfaparser":79,"./rdfxmlparser":80,"./serialize":81,"./uri":87,"./util":88}],65:[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; }; }(); @@ -23650,7 +21391,7 @@ Formula.prototype.variable = function (name) { }; module.exports = Formula; -},{"./blank-node":48,"./class-order":49,"./collection":50,"./literal":60,"./log":61,"./named-node":63,"./namespace":64,"./node":65,"./serialize":72,"./statement":75,"./variable":80}],57:[function(_dereq_,module,exports){ +},{"./blank-node":57,"./class-order":58,"./collection":59,"./literal":69,"./log":70,"./named-node":72,"./namespace":73,"./node":74,"./serialize":81,"./statement":84,"./variable":89}],66:[function(_dereq_,module,exports){ 'use strict'; var _indexedFormula = _dereq_('./indexed-formula'); @@ -23713,7 +21454,7 @@ $rdf.quad = $rdf.DataFactory.quad; $rdf.triple = $rdf.DataFactory.triple; module.exports = $rdf; -},{"./blank-node":48,"./collection":50,"./convert":51,"./data-factory":52,"./empty":54,"./fetcher":55,"./formula":56,"./indexed-formula":58,"./jsonparser":59,"./literal":60,"./log":61,"./n3parser":62,"./named-node":63,"./namespace":64,"./node":65,"./parse":66,"./patch-parser":67,"./query":69,"./query-to-sparql":68,"./rdfaparser":70,"./rdfxmlparser":71,"./serialize":72,"./serializer":73,"./sparql-to-query":74,"./statement":75,"./update-manager":76,"./updates-via":77,"./uri":78,"./util":79,"./variable":80}],58:[function(_dereq_,module,exports){ +},{"./blank-node":57,"./collection":59,"./convert":60,"./data-factory":61,"./empty":63,"./fetcher":64,"./formula":65,"./indexed-formula":67,"./jsonparser":68,"./literal":69,"./log":70,"./n3parser":71,"./named-node":72,"./namespace":73,"./node":74,"./parse":75,"./patch-parser":76,"./query":78,"./query-to-sparql":77,"./rdfaparser":79,"./rdfxmlparser":80,"./serialize":81,"./serializer":82,"./sparql-to-query":83,"./statement":84,"./update-manager":85,"./updates-via":86,"./uri":87,"./util":88,"./variable":89}],67:[function(_dereq_,module,exports){ 'use strict'; Object.defineProperty(exports, "__esModule", { @@ -24621,7 +22362,7 @@ exports.default = IndexedFormula; IndexedFormula.handleRDFType = handleRDFType; -},{"./formula":56,"./node":65,"./query":69,"./statement":75,"./util":79,"./variable":80}],59:[function(_dereq_,module,exports){ +},{"./formula":65,"./node":74,"./query":78,"./statement":84,"./util":88,"./variable":89}],68:[function(_dereq_,module,exports){ 'use strict'; var jsonParser = function () { @@ -24679,7 +22420,7 @@ var jsonParser = function () { }(); module.exports = jsonParser; -},{}],60:[function(_dereq_,module,exports){ +},{}],69:[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; }; @@ -24862,7 +22603,7 @@ Literal.prototype.lang = ''; Literal.prototype.isVar = 0; module.exports = Literal; -},{"./class-order":49,"./named-node":63,"./node":65,"./xsd":81}],61:[function(_dereq_,module,exports){ +},{"./class-order":58,"./named-node":72,"./node":74,"./xsd":90}],70:[function(_dereq_,module,exports){ "use strict"; /** @@ -24889,7 +22630,7 @@ module.exports = { return; } }; -},{}],62:[function(_dereq_,module,exports){ +},{}],71:[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; }; @@ -26383,7 +24124,7 @@ var N3Parser = function () { }(); module.exports = N3Parser; -},{"./uri":78,"./util":79}],63:[function(_dereq_,module,exports){ +},{"./uri":87,"./util":88}],72:[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; }; }(); @@ -26503,7 +24244,7 @@ NamedNode.prototype.classOrder = ClassOrder['NamedNode']; NamedNode.prototype.isVar = 0; module.exports = NamedNode; -},{"./class-order":49,"./node":65}],64:[function(_dereq_,module,exports){ +},{"./class-order":58,"./node":74}],73:[function(_dereq_,module,exports){ 'use strict'; var NamedNode = _dereq_('./named-node'); @@ -26515,7 +24256,7 @@ function Namespace(nsuri) { } module.exports = Namespace; -},{"./named-node":63}],65:[function(_dereq_,module,exports){ +},{"./named-node":72}],74:[function(_dereq_,module,exports){ 'use strict'; /** * The superclass of all RDF Statement objects, that is @@ -26620,7 +24361,7 @@ Node.fromValue = function fromValue(value) { } return Literal.fromValue(value); }; -},{"./collection":50,"./literal":60,"./named-node":63}],66:[function(_dereq_,module,exports){ +},{"./collection":59,"./literal":69,"./named-node":72}],75:[function(_dereq_,module,exports){ 'use strict'; module.exports = parse; @@ -26765,7 +24506,7 @@ function parse(str, kb, base, contentType, callback) { } } } -},{"./blank-node":48,"./literal":60,"./n3parser":62,"./named-node":63,"./patch-parser":67,"./rdfaparser":70,"./rdfxmlparser":71,"./util":79,"jsonld":18,"n3":82}],67:[function(_dereq_,module,exports){ +},{"./blank-node":57,"./literal":69,"./n3parser":71,"./named-node":72,"./patch-parser":76,"./rdfaparser":79,"./rdfxmlparser":80,"./util":88,"jsonld":55,"n3":91}],76:[function(_dereq_,module,exports){ 'use strict'; // Parse a simple SPARL-Update subset syntax for patches. @@ -26861,7 +24602,7 @@ function sparqlUpdateParser(str, kb, base) { } // while // return clauses } -},{"./n3parser":62,"./namespace":64}],68:[function(_dereq_,module,exports){ +},{"./n3parser":71,"./namespace":73}],77:[function(_dereq_,module,exports){ 'use strict'; var log = _dereq_('./log'); @@ -26939,7 +24680,7 @@ function queryToSPARQL(query) { } module.exports = queryToSPARQL; -},{"./log":61}],69:[function(_dereq_,module,exports){ +},{"./log":70}],78:[function(_dereq_,module,exports){ 'use strict'; var _indexedFormula = _dereq_('./indexed-formula'); @@ -27509,7 +25250,7 @@ function indexedFormulaQuery(myQuery, callback, fetcher, onDone) { module.exports.Query = Query; module.exports.indexedFormulaQuery = indexedFormulaQuery; -},{"./indexed-formula":58,"./log":61,"./uri":78}],70:[function(_dereq_,module,exports){ +},{"./indexed-formula":67,"./log":70,"./uri":87}],79:[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; }; }(); @@ -28463,7 +26204,7 @@ RDFaProcessor.dateTimeTypes = [{ pattern: /-?P(?:[0-9]+Y)?(?:[0-9]+M)?(?:[0-9]+D type: 'http://www.w3.org/2001/XMLSchema#gYear' }]; module.exports = RDFaProcessor; -},{"./blank-node":48,"./data-factory":52,"./literal":60,"./named-node":63,"./uri":78,"./util":79}],71:[function(_dereq_,module,exports){ +},{"./blank-node":57,"./data-factory":61,"./literal":69,"./named-node":72,"./uri":87,"./util":88}],80:[function(_dereq_,module,exports){ 'use strict'; /** @@ -28912,7 +26653,7 @@ var RDFParser = function RDFParser(store) { }; module.exports = RDFParser; -},{"./uri":78}],72:[function(_dereq_,module,exports){ +},{"./uri":87}],81:[function(_dereq_,module,exports){ 'use strict'; module.exports = serialize; @@ -28990,7 +26731,7 @@ function serialize(target, kb, base, contentType, callback, options) { } } } -},{"./convert":51,"./serializer":73}],73:[function(_dereq_,module,exports){ +},{"./convert":60,"./serializer":82}],82:[function(_dereq_,module,exports){ 'use strict'; /* Serialization of RDF Graphs @@ -29945,7 +27686,7 @@ var Serializer = function () { }(); module.exports = Serializer; -},{"./blank-node":48,"./named-node":63,"./uri":78,"./util":79,"./xsd":81}],74:[function(_dereq_,module,exports){ +},{"./blank-node":57,"./named-node":72,"./uri":87,"./util":88,"./xsd":90}],83:[function(_dereq_,module,exports){ 'use strict'; // Converting between SPARQL queries and the $rdf query API @@ -30445,7 +28186,7 @@ function SPARQLToQuery(SPARQL, testMode, kb) { } module.exports = SPARQLToQuery; -},{"./log":61,"./query":69}],75:[function(_dereq_,module,exports){ +},{"./log":70,"./query":78}],84:[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; }; }(); @@ -30509,7 +28250,7 @@ var Statement = function () { }(); module.exports = Statement; -},{"./node":65}],76:[function(_dereq_,module,exports){ +},{"./node":74}],85:[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; }; @@ -31469,7 +29210,7 @@ var UpdateManager = function () { }(); module.exports = UpdateManager; -},{"./data-factory":52,"./fetcher":55,"./indexed-formula":58,"./namespace":64,"./serializer":73,"./uri":78,"./util":79}],77:[function(_dereq_,module,exports){ +},{"./data-factory":61,"./fetcher":64,"./indexed-formula":67,"./namespace":73,"./serializer":82,"./uri":87,"./util":88}],86:[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; }; }(); @@ -31655,7 +29396,7 @@ var UpdatesVia = function () { module.exports.UpdatesSocket = UpdatesSocket; module.exports.UpdatesVia = UpdatesVia; -},{"./data-factory":52}],78:[function(_dereq_,module,exports){ +},{"./data-factory":61}],87:[function(_dereq_,module,exports){ 'use strict'; /* @@ -31842,7 +29583,7 @@ function refTo(base, uri) { } return s + uri.slice(i); } -},{"./named-node":63}],79:[function(_dereq_,module,exports){ +},{"./named-node":72}],88:[function(_dereq_,module,exports){ 'use strict'; /** @@ -32324,7 +30065,7 @@ function xhr() { return false; } } -},{"./log":61,"./named-node":63,"./uri":78,"xmldom":147,"xmlhttprequest":150}],80:[function(_dereq_,module,exports){ +},{"./log":70,"./named-node":72,"./uri":87,"xmldom":302,"xmlhttprequest":305}],89:[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; }; }(); @@ -32402,7 +30143,7 @@ Variable.prototype.classOrder = ClassOrder['Variable']; Variable.prototype.isVar = 1; module.exports = Variable; -},{"./class-order":49,"./node":65,"./uri":78}],81:[function(_dereq_,module,exports){ +},{"./class-order":58,"./node":74,"./uri":87}],90:[function(_dereq_,module,exports){ 'use strict'; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -32422,9 +30163,35 @@ XSD.langString = new NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#langS XSD.string = new NamedNode('http://www.w3.org/2001/XMLSchema#string'); module.exports = XSD; -},{"./named-node":63}],82:[function(_dereq_,module,exports){ -arguments[4][31][0].apply(exports,arguments) -},{"./lib/N3Lexer":83,"./lib/N3Parser":84,"./lib/N3Store":85,"./lib/N3StreamParser":86,"./lib/N3StreamWriter":87,"./lib/N3Util":88,"./lib/N3Writer":89,"dup":31}],83:[function(_dereq_,module,exports){ +},{"./named-node":72}],91:[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":92,"./lib/N3Parser":93,"./lib/N3Store":94,"./lib/N3StreamParser":95,"./lib/N3StreamWriter":96,"./lib/N3Util":97,"./lib/N3Writer":98}],92:[function(_dereq_,module,exports){ // **N3Lexer** tokenizes N3 documents. var fromCharCode = String.fromCharCode; var immediately = typeof setImmediate === 'function' ? setImmediate : @@ -32785,7 +30552,7 @@ N3Lexer.prototype = { // Export the `N3Lexer` class as a whole. module.exports = N3Lexer; -},{}],84:[function(_dereq_,module,exports){ +},{}],93:[function(_dereq_,module,exports){ // **N3Parser** parses N3 documents. var N3Lexer = _dereq_('./N3Lexer'); @@ -33487,7 +31254,7 @@ function noop() {} // Export the `N3Parser` class as a whole. module.exports = N3Parser; -},{"./N3Lexer":83}],85:[function(_dereq_,module,exports){ +},{"./N3Lexer":92}],94:[function(_dereq_,module,exports){ // **N3Store** objects store N3 triples by graph in memory. var expandPrefixedName = _dereq_('./N3Util').expandPrefixedName; @@ -33846,7 +31613,7 @@ N3Store.prototype = { // Export the `N3Store` class as a whole. module.exports = N3Store; -},{"./N3Util":88}],86:[function(_dereq_,module,exports){ +},{"./N3Util":97}],95:[function(_dereq_,module,exports){ // **N3StreamParser** parses an N3 stream into a triple stream var Transform = _dereq_('stream').Transform, util = _dereq_('util'), @@ -33882,7 +31649,7 @@ util.inherits(N3StreamParser, Transform); // Export the `N3StreamParser` class as a whole. module.exports = N3StreamParser; -},{"./N3Parser.js":84,"stream":107,"util":118}],87:[function(_dereq_,module,exports){ +},{"./N3Parser.js":93,"stream":36,"util":51}],96:[function(_dereq_,module,exports){ // **N3StreamWriter** serializes a triple stream into an N3 stream var Transform = _dereq_('stream').Transform, util = _dereq_('util'), @@ -33914,7 +31681,7 @@ util.inherits(N3StreamWriter, Transform); // Export the `N3StreamWriter` class as a whole. module.exports = N3StreamWriter; -},{"./N3Writer.js":89,"stream":107,"util":118}],88:[function(_dereq_,module,exports){ +},{"./N3Writer.js":98,"stream":36,"util":51}],97:[function(_dereq_,module,exports){ // **N3Util** provides N3 utility functions var Xsd = 'http://www.w3.org/2001/XMLSchema#'; @@ -34032,7 +31799,7 @@ function applyToThis(f) { // Expose N3Util, attaching all functions to it module.exports = addN3Util(addN3Util); -},{}],89:[function(_dereq_,module,exports){ +},{}],98:[function(_dereq_,module,exports){ // **N3Writer** writes N3 documents. // Matches a literal as represented in memory by the N3 library @@ -34362,6584 +32129,15938 @@ function characterReplacer(character) { // Export the `N3Writer` class as a whole. module.exports = N3Writer; -},{}],90:[function(_dereq_,module,exports){ -module.exports = _dereq_('./lib/_stream_duplex.js'); - -},{"./lib/_stream_duplex.js":91}],91:[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. +},{}],99:[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; + } + }; -'use strict'; +}).call(this); -/**/ +},{}],100:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(function() { + "use strict"; + var builder, defaults, escapeCDATA, requiresCDATA, wrapCDATA, + hasProp = {}.hasOwnProperty; -var processNextTick = _dereq_('process-nextick-args'); -/**/ + builder = _dereq_('xmlbuilder'); -/**/ -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) { - keys.push(key); - }return keys; -}; -/**/ + defaults = _dereq_('./defaults').defaults; -module.exports = Duplex; + requiresCDATA = function(entry) { + return typeof entry === "string" && (entry.indexOf('&') >= 0 || entry.indexOf('>') >= 0 || entry.indexOf('<') >= 0); + }; -/**/ -var util = _dereq_('core-util-is'); -util.inherits = _dereq_('inherits'); -/**/ + wrapCDATA = function(entry) { + return ""; + }; -var Readable = _dereq_('./_stream_readable'); -var Writable = _dereq_('./_stream_writable'); + escapeCDATA = function(entry) { + return entry.replace(']]>', ']]]]>'); + }; -util.inherits(Duplex, Readable); + 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; + } + } -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]; -} + 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); + }; -function Duplex(options) { - if (!(this instanceof Duplex)) return new Duplex(options); + return Builder; - Readable.call(this, options); - Writable.call(this, options); + })(); - if (options && options.readable === false) this.readable = false; +}).call(this); - if (options && options.writable === false) this.writable = false; +},{"./defaults":101,"xmlbuilder":126}],101:[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 + } + }; - this.allowHalfOpen = true; - if (options && options.allowHalfOpen === false) this.allowHalfOpen = false; +}).call(this); - this.once('end', onend); -} +},{}],102:[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; -// 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; + sax = _dereq_('sax'); - // no more data can be written. - // But allow more writes to happen in this tick. - processNextTick(onEndNT, this); -} + events = _dereq_('events'); -function onEndNT(self) { - self.end(); -} + bom = _dereq_('./bom'); -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; - } + processors = _dereq_('./processors'); - // backward compatibility, the user is explicitly - // managing destroyed - this._readableState.destroyed = value; - this._writableState.destroyed = value; - } -}); + setImmediate = _dereq_('timers').setImmediate; -Duplex.prototype._destroy = function (err, cb) { - this.push(null); - this.end(); + defaults = _dereq_('./defaults').defaults; - processNextTick(cb, err); -}; + isEmpty = function(thing) { + return typeof thing === "object" && (thing != null) && Object.keys(thing).length === 0; + }; -function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } -} -},{"./_stream_readable":93,"./_stream_writable":95,"core-util-is":8,"inherits":15,"process-nextick-args":42}],92:[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. + 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; + }; -// a passthrough stream. -// basically just the most minimal sort of Transform stream. -// Every written chunk gets output as-is. + exports.Parser = (function(superClass) { + extend(Parser, superClass); -'use strict'; + 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(); + } -module.exports = PassThrough; + 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); + } + } + }; -var Transform = _dereq_('./_stream_transform'); + 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); + } + }; -/**/ -var util = _dereq_('core-util-is'); -util.inherits = _dereq_('inherits'); -/**/ + 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); + } + }; + })(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 { + 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]; + } + } + 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); + }; -util.inherits(PassThrough, Transform); + 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); + }); + 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; + } + } + }; -function PassThrough(options) { - if (!(this instanceof PassThrough)) return new PassThrough(options); + return Parser; - Transform.call(this, options); -} + })(events.EventEmitter); -PassThrough.prototype._transform = function (chunk, encoding, cb) { - cb(null, chunk); -}; -},{"./_stream_transform":94,"core-util-is":8,"inherits":15}],93:[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. + 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 = {}; + } + parser = new exports.Parser(options); + return parser.parseString(str, cb); + }; -'use strict'; +}).call(this); -/**/ +},{"./bom":99,"./defaults":101,"./processors":103,"events":8,"sax":281,"timers":47}],103:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(function() { + "use strict"; + var prefixMatch; -var processNextTick = _dereq_('process-nextick-args'); -/**/ + prefixMatch = new RegExp(/(?!xmlns)^.*:/); -module.exports = Readable; + exports.normalize = function(str) { + return str.toLowerCase(); + }; -/**/ -var isArray = _dereq_('isarray'); -/**/ + exports.firstCharLowerCase = function(str) { + return str.charAt(0).toLowerCase() + str.slice(1); + }; -/**/ -var Duplex; -/**/ + exports.stripPrefix = function(str) { + return str.replace(prefixMatch, ''); + }; -Readable.ReadableState = ReadableState; + exports.parseNumbers = function(str) { + if (!isNaN(str)) { + str = str % 1 === 0 ? parseInt(str, 10) : parseFloat(str); + } + return str; + }; -/**/ -var EE = _dereq_('events').EventEmitter; + exports.parseBooleans = function(str) { + if (/^(?:true|false)$/i.test(str)) { + str = str.toLowerCase() === 'true'; + } + return str; + }; -var EElistenerCount = function (emitter, type) { - return emitter.listeners(type).length; -}; -/**/ +}).call(this); -/**/ -var Stream = _dereq_('./internal/streams/stream'); -/**/ +},{}],104:[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; -// 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; -} -/**/ + defaults = _dereq_('./defaults'); -/**/ -var util = _dereq_('core-util-is'); -util.inherits = _dereq_('inherits'); -/**/ + builder = _dereq_('./builder'); -/**/ -var debugUtil = _dereq_('util'); -var debug = void 0; -if (debugUtil && debugUtil.debuglog) { - debug = debugUtil.debuglog('stream'); -} else { - debug = function () {}; -} -/**/ + parser = _dereq_('./parser'); -var BufferList = _dereq_('./internal/streams/BufferList'); -var destroyImpl = _dereq_('./internal/streams/destroy'); -var StringDecoder; + processors = _dereq_('./processors'); -util.inherits(Readable, Stream); + exports.defaults = defaults.defaults; -var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; + exports.processors = processors; -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]]; - } -} + exports.ValidationError = (function(superClass) { + extend(ValidationError, superClass); -function ReadableState(options, stream) { - Duplex = Duplex || _dereq_('./_stream_duplex'); + function ValidationError(message) { + this.message = message; + } - options = options || {}; + return ValidationError; - // 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; + })(Error); - if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.readableObjectMode; + exports.Builder = builder.Builder; - // 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; + exports.Parser = parser.Parser; - // cast to ints. - this.highWaterMark = Math.floor(this.highWaterMark); + exports.parseString = parser.parseString; - // 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; +}).call(this); - // 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; +},{"./builder":100,"./defaults":101,"./parser":102,"./processors":103}],105:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(function() { + var assign, isArray, isEmpty, isFunction, isObject, isPlainObject, + slice = [].slice, + hasProp = {}.hasOwnProperty; - // 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; + 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 target; + }; - // has it been destroyed - this.destroyed = false; + isFunction = function(val) { + return !!val && Object.prototype.toString.call(val) === '[object Function]'; + }; - // 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'; + isObject = function(val) { + var ref; + return !!val && ((ref = typeof val) === 'function' || ref === 'object'); + }; - // the number of writers that are awaiting a drain event in .pipe()s - this.awaitDrain = 0; + isArray = function(val) { + if (isFunction(Array.isArray)) { + return Array.isArray(val); + } else { + return Object.prototype.toString.call(val) === '[object Array]'; + } + }; - // if true, a maybeReadMore has been scheduled - this.readingMore = false; + isEmpty = function(val) { + var key; + if (isArray(val)) { + return !val.length; + } else { + for (key in val) { + if (!hasProp.call(val, key)) continue; + return false; + } + return true; + } + }; - 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; - } -} + 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)); + }; -function Readable(options) { - Duplex = Duplex || _dereq_('./_stream_duplex'); + module.exports.assign = assign; - if (!(this instanceof Readable)) return new Readable(options); + module.exports.isFunction = isFunction; - this._readableState = new ReadableState(options, this); + module.exports.isObject = isObject; - // legacy - this.readable = true; + module.exports.isArray = isArray; - if (options) { - if (typeof options.read === 'function') this._read = options.read; + module.exports.isEmpty = isEmpty; - if (typeof options.destroy === 'function') this._destroy = options.destroy; - } + module.exports.isPlainObject = isPlainObject; - Stream.call(this); -} +}).call(this); -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; +},{}],106:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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 (value == null) { + throw new Error("Missing attribute value for attribute " + name + " of element " + parent.name); + } + this.name = this.stringify.attName(name); + this.value = this.stringify.attValue(value); } - // backward compatibility, the user is explicitly - // managing destroyed - this._readableState.destroyed = value; - } -}); + XMLAttribute.prototype.clone = function() { + return Object.create(this); + }; -Readable.prototype.destroy = destroyImpl.destroy; -Readable.prototype._undestroy = destroyImpl.undestroy; -Readable.prototype._destroy = function (err, cb) { - this.push(null); - cb(err); -}; + XMLAttribute.prototype.toString = function(options) { + return this.options.writer.set(options).attribute(this); + }; -// 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; + return XMLAttribute; - 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; - } + })(); - return readableAddChunk(this, chunk, encoding, false, skipChunkCheck); -}; +}).call(this); -// Unshift should *always* be something directly out of read() -Readable.prototype.unshift = function (chunk) { - return readableAddChunk(this, chunk, null, true, false); -}; +},{}],107:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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; -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); - } + XMLNode = _dereq_('./XMLNode'); - 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); - } + 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"); } - } else if (!addToFront) { - state.reading = false; + this.text = this.stringify.cdata(text); } - } - return needMoreData(state); -} + XMLCData.prototype.clone = function() { + return Object.create(this); + }; -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); + XMLCData.prototype.toString = function(options) { + return this.options.writer.set(options).cdata(this); + }; - if (state.needReadable) emitReadable(stream); - } - maybeReadMore(stream, state); -} + return XMLCData; -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; -} + })(XMLNode); -// 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); -} +}).call(this); -Readable.prototype.isPaused = function () { - return this._readableState.flowing === false; -}; +},{"./XMLNode":118}],108:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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; -// 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; -}; + XMLNode = _dereq_('./XMLNode'); -// 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; -} + module.exports = XMLComment = (function(superClass) { + extend(XMLComment, superClass); -// 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; -} + 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); + } -// 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; + XMLComment.prototype.clone = function() { + return Object.create(this); + }; - if (n !== 0) state.emittedReadable = false; + XMLComment.prototype.toString = function(options) { + return this.options.writer.set(options).comment(this); + }; - // 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; - } + return XMLComment; - n = howMuchToRead(n, state); + })(XMLNode); - // 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; - } +}).call(this); - // 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. +},{"./XMLNode":118}],109:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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; - // if we need a readable event, then we need to do some reading. - var doRead = state.needReadable; - debug('need readable', doRead); + XMLNode = _dereq_('./XMLNode'); - // 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); - } + module.exports = XMLDTDAttList = (function(superClass) { + extend(XMLDTDAttList, superClass); - // 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); - } + 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 ret; - if (n > 0) ret = fromList(n, state);else ret = null; + XMLDTDAttList.prototype.toString = function(options) { + return this.options.writer.set(options).dtdAttList(this); + }; - if (ret === null) { - state.needReadable = true; - n = 0; - } else { - state.length -= n; - } + return XMLDTDAttList; - 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); - } + })(XMLNode); - if (ret !== null) this.emit('data', ret); +}).call(this); - return ret; -}; +},{"./XMLNode":118}],110:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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; -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; + XMLNode = _dereq_('./XMLNode'); - // emit 'readable' now to make sure it gets picked up. - emitReadable(stream); -} + module.exports = XMLDTDElement = (function(superClass) { + extend(XMLDTDElement, superClass); -// 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 XMLDTDElement(parent, name, value) { + XMLDTDElement.__super__.constructor.call(this, parent); + if (name == null) { + throw new Error("Missing DTD element name"); + } + if (!value) { + value = '(#PCDATA)'; + } + if (Array.isArray(value)) { + value = '(' + value.join(',') + ')'; + } + this.name = this.stringify.eleName(name); + this.value = this.stringify.dtdElementValue(value); + } -function emitReadable_(stream) { - debug('emit readable'); - stream.emit('readable'); - flow(stream); -} + XMLDTDElement.prototype.toString = function(options) { + return this.options.writer.set(options).dtdElement(this); + }; -// 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); - } -} + return XMLDTDElement; -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; -} + })(XMLNode); -// 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')); -}; +}).call(this); -Readable.prototype.pipe = function (dest, pipeOpts) { - var src = this; - var state = this._readableState; +},{"./XMLNode":118}],111:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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; - 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); + isObject = _dereq_('./Utility').isObject; - var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; + XMLNode = _dereq_('./XMLNode'); - var endFn = doEnd ? onend : unpipe; - if (state.endEmitted) processNextTick(endFn);else src.once('end', endFn); + module.exports = XMLDTDEntity = (function(superClass) { + extend(XMLDTDEntity, superClass); - dest.on('unpipe', onunpipe); - function onunpipe(readable, unpipeInfo) { - debug('onunpipe'); - if (readable === src) { - if (unpipeInfo && unpipeInfo.hasUnpiped === false) { - unpipeInfo.hasUnpiped = true; - cleanup(); + 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"); + } } } - } - function onend() { - debug('onend'); - dest.end(); - } + XMLDTDEntity.prototype.toString = function(options) { + return this.options.writer.set(options).dtdEntity(this); + }; - // 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); + return XMLDTDEntity; - 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); + })(XMLNode); - cleanedUp = true; +}).call(this); - // 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(); - } +},{"./Utility":105,"./XMLNode":118}],112:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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 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; + XMLNode = _dereq_('./XMLNode'); + + module.exports = XMLDTDNotation = (function(superClass) { + extend(XMLDTDNotation, superClass); + + 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); } - 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); - } + XMLDTDNotation.prototype.toString = function(options) { + return this.options.writer.set(options).dtdNotation(this); + }; - // Make sure our error handler is attached before userland ones. - prependListener(dest, 'error', onerror); + return XMLDTDNotation; - // 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); + })(XMLNode); - function unpipe() { - debug('unpipe'); - src.unpipe(dest); - } +}).call(this); - // tell the dest that it's being piped to - dest.emit('pipe', src); +},{"./XMLNode":118}],113:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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; - // start the flow if it hasn't been started already. - if (!state.flowing) { - debug('pipe resume'); - src.resume(); - } + isObject = _dereq_('./Utility').isObject; - return dest; -}; + XMLNode = _dereq_('./XMLNode'); -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); - } - }; -} + module.exports = XMLDeclaration = (function(superClass) { + extend(XMLDeclaration, superClass); -Readable.prototype.unpipe = function (dest) { - var state = this._readableState; - var unpipeInfo = { hasUnpiped: false }; + 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); + } + } - // if we're not piping anywhere, then do nothing. - if (state.pipesCount === 0) return this; + XMLDeclaration.prototype.toString = function(options) { + return this.options.writer.set(options).declaration(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; + return XMLDeclaration; - if (!dest) dest = state.pipes; + })(XMLNode); - // got a match. - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - if (dest) dest.emit('unpipe', this, unpipeInfo); - return this; - } +}).call(this); - // slow case. multiple pipe destinations. +},{"./Utility":105,"./XMLNode":118}],114:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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; - if (!dest) { - // remove all. - var dests = state.pipes; - var len = state.pipesCount; - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; + isObject = _dereq_('./Utility').isObject; - for (var i = 0; i < len; i++) { - dests[i].emit('unpipe', this, unpipeInfo); - }return this; - } + XMLNode = _dereq_('./XMLNode'); - // try to find the right one. - var index = indexOf(state.pipes, dest); - if (index === -1) return this; + XMLDTDAttList = _dereq_('./XMLDTDAttList'); - state.pipes.splice(index, 1); - state.pipesCount -= 1; - if (state.pipesCount === 1) state.pipes = state.pipes[0]; + XMLDTDEntity = _dereq_('./XMLDTDEntity'); - dest.emit('unpipe', this, unpipeInfo); + XMLDTDElement = _dereq_('./XMLDTDElement'); - return this; -}; + XMLDTDNotation = _dereq_('./XMLDTDNotation'); -// 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); + module.exports = XMLDocType = (function(superClass) { + extend(XMLDocType, superClass); - 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); + 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); } } - } - return res; -}; -Readable.prototype.addListener = Readable.prototype.on; - -function nReadingNextTick(self) { - debug('readable nexttick read 0'); - self.read(0); -} + XMLDocType.prototype.element = function(name, value) { + var child; + child = new XMLDTDElement(this, name, value); + this.children.push(child); + return this; + }; -// 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; -}; + 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; + }; -function resume(stream, state) { - if (!state.resumeScheduled) { - state.resumeScheduled = true; - processNextTick(resume_, stream, state); - } -} + XMLDocType.prototype.entity = function(name, value) { + var child; + child = new XMLDTDEntity(this, false, name, value); + this.children.push(child); + return this; + }; -function resume_(stream, state) { - if (!state.reading) { - debug('resume read 0'); - stream.read(0); - } + XMLDocType.prototype.pEntity = function(name, value) { + var child; + child = new XMLDTDEntity(this, true, name, value); + this.children.push(child); + return this; + }; - state.resumeScheduled = false; - state.awaitDrain = 0; - stream.emit('resume'); - flow(stream); - if (state.flowing && !state.reading) stream.read(0); -} + XMLDocType.prototype.notation = function(name, value) { + var child; + child = new XMLDTDNotation(this, name, value); + this.children.push(child); + return this; + }; -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; -}; + XMLDocType.prototype.toString = function(options) { + return this.options.writer.set(options).docType(this); + }; -function flow(stream) { - var state = stream._readableState; - debug('flow', state.flowing); - while (state.flowing && stream.read() !== null) {} -} + XMLDocType.prototype.ele = function(name, value) { + return this.element(name, value); + }; -// 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; + XMLDocType.prototype.att = function(elementName, attributeName, attributeType, defaultValueType, defaultValue) { + return this.attList(elementName, attributeName, attributeType, defaultValueType, defaultValue); + }; - 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); - } - - self.push(null); - }); + XMLDocType.prototype.ent = function(name, value) { + return this.entity(name, value); + }; - stream.on('data', function (chunk) { - debug('wrapped data'); - if (state.decoder) chunk = state.decoder.write(chunk); + XMLDocType.prototype.pent = function(name, value) { + return this.pEntity(name, value); + }; - // don't skip over falsy values in objectMode - if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return; + XMLDocType.prototype.not = function(name, value) { + return this.notation(name, value); + }; - var ret = self.push(chunk); - if (!ret) { - paused = true; - stream.pause(); - } - }); + XMLDocType.prototype.up = function() { + return this.root() || this.documentObject; + }; - // 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); - } - } + return XMLDocType; - // proxy certain important events. - for (var n = 0; n < kProxyEvents.length; n++) { - stream.on(kProxyEvents[n], self.emit.bind(self, kProxyEvents[n])); - } + })(XMLNode); - // 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(); - } - }; +}).call(this); - return self; -}; +},{"./Utility":105,"./XMLDTDAttList":109,"./XMLDTDElement":110,"./XMLDTDEntity":111,"./XMLDTDNotation":112,"./XMLNode":118}],115:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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; -// exposed for testing purposes only. -Readable._fromList = fromList; + isPlainObject = _dereq_('./Utility').isPlainObject; -// 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; + XMLNode = _dereq_('./XMLNode'); - 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); - } + XMLStringifier = _dereq_('./XMLStringifier'); - return ret; -} + XMLStringWriter = _dereq_('./XMLStringWriter'); -// 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; -} + module.exports = XMLDocument = (function(superClass) { + extend(XMLDocument, superClass); -// 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); + function XMLDocument(options) { + XMLDocument.__super__.constructor.call(this, null); + options || (options = {}); + if (!options.writer) { + options.writer = new XMLStringWriter(); } - break; + this.options = options; + this.stringify = new XMLStringifier(options); + this.isDocument = true; } - ++c; - } - list.length -= c; - return ret; -} -// 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); + 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); } - break; - } - ++c; - } - list.length -= c; - return ret; -} - -function endReadable(stream) { - var state = stream._readableState; + return writer.document(this); + }; - // 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'); + XMLDocument.prototype.toString = function(options) { + return this.options.writer.set(options).document(this); + }; - if (!state.endEmitted) { - state.ended = true; - processNextTick(endReadableNT, state, stream); - } -} + return XMLDocument; -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'); - } -} + })(XMLNode); -function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } -} +}).call(this); -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 : {}) +},{"./Utility":105,"./XMLNode":118,"./XMLStringWriter":122,"./XMLStringifier":123}],116:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(function() { + var XMLAttribute, XMLCData, XMLComment, XMLDTDAttList, XMLDTDElement, XMLDTDEntity, XMLDTDNotation, XMLDeclaration, XMLDocType, XMLDocumentCB, XMLElement, XMLProcessingInstruction, XMLRaw, XMLStringWriter, XMLStringifier, XMLText, isFunction, isObject, isPlainObject, ref, + hasProp = {}.hasOwnProperty; -},{"./_stream_duplex":91,"./internal/streams/BufferList":96,"./internal/streams/destroy":97,"./internal/streams/stream":98,"_process":43,"core-util-is":8,"events":10,"inherits":15,"isarray":99,"process-nextick-args":42,"safe-buffer":105,"string_decoder/":100,"util":3}],94:[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. + ref = _dereq_('./Utility'), isObject = ref.isObject, isFunction = ref.isFunction, isPlainObject = ref.isPlainObject; -// 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. + XMLElement = _dereq_('./XMLElement'); -'use strict'; + XMLCData = _dereq_('./XMLCData'); -module.exports = Transform; + XMLComment = _dereq_('./XMLComment'); -var Duplex = _dereq_('./_stream_duplex'); + XMLRaw = _dereq_('./XMLRaw'); -/**/ -var util = _dereq_('core-util-is'); -util.inherits = _dereq_('inherits'); -/**/ + XMLText = _dereq_('./XMLText'); -util.inherits(Transform, Duplex); + XMLProcessingInstruction = _dereq_('./XMLProcessingInstruction'); -function TransformState(stream) { - this.afterTransform = function (er, data) { - return afterTransform(stream, er, data); - }; + XMLDeclaration = _dereq_('./XMLDeclaration'); - this.needTransform = false; - this.transforming = false; - this.writecb = null; - this.writechunk = null; - this.writeencoding = null; -} + XMLDocType = _dereq_('./XMLDocType'); -function afterTransform(stream, er, data) { - var ts = stream._transformState; - ts.transforming = false; + XMLDTDAttList = _dereq_('./XMLDTDAttList'); - var cb = ts.writecb; + XMLDTDEntity = _dereq_('./XMLDTDEntity'); - if (!cb) { - return stream.emit('error', new Error('write callback called multiple times')); - } + XMLDTDElement = _dereq_('./XMLDTDElement'); - ts.writechunk = null; - ts.writecb = null; + XMLDTDNotation = _dereq_('./XMLDTDNotation'); - if (data !== null && data !== undefined) stream.push(data); + XMLAttribute = _dereq_('./XMLAttribute'); - cb(er); + XMLStringifier = _dereq_('./XMLStringifier'); - var rs = stream._readableState; - rs.reading = false; - if (rs.needReadable || rs.length < rs.highWaterMark) { - stream._read(rs.highWaterMark); - } -} + XMLStringWriter = _dereq_('./XMLStringWriter'); -function Transform(options) { - if (!(this instanceof Transform)) return new Transform(options); + 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); + } + 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; + } - Duplex.call(this, options); + XMLDocumentCB.prototype.node = function(name, attributes, text) { + var ref1; + if (name == null) { + throw new Error("Missing node name"); + } + if (this.root && this.currentLevel === -1) { + throw new Error("Document can only have one root node"); + } + 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; + }; - this._transformState = new TransformState(this); + 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); + } + }; - var stream = this; + 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); + } + } else { + if (isFunction(value)) { + value = value.apply(); + } + if (!this.options.skipNullAttributes || (value != null)) { + this.currentNode.attributes[name] = new XMLAttribute(this, name, value); + } + } + return this; + }; - // start out asking for a readable event once data is transformed. - this._readableState.needReadable = true; + 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; + }; - // 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; + 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; + }; - if (options) { - if (typeof options.transform === 'function') this._transform = options.transform; + 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; + }; - if (typeof options.flush === 'function') this._flush = options.flush; - } + 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; + }; - // 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); - }); -} + XMLDocumentCB.prototype.instruction = function(target, value) { + var i, insTarget, insValue, len, node; + this.openCurrent(); + if (target != null) { + target = target.valueOf(); + } + 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; + }; -Transform.prototype.push = function (chunk, encoding) { - this._transformState.needTransform = false; - return Duplex.prototype.push.call(this, chunk, encoding); -}; + XMLDocumentCB.prototype.declaration = function(version, encoding, standalone) { + var node; + this.openCurrent(); + if (this.documentStarted) { + throw new Error("declaration() must be the first node"); + } + node = new XMLDeclaration(this, version, encoding, standalone); + this.onData(this.writer.declaration(node, this.currentLevel + 1)); + return 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'); -}; + XMLDocumentCB.prototype.doctype = function(root, pubID, sysID) { + this.openCurrent(); + if (root == null) { + throw new Error("Missing root node name"); + } + 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; + }; -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); - } -}; + 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; + }; -// 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; + 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; + }; - 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; - } -}; + 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; + }; -Transform.prototype._destroy = function (err, cb) { - var _this = 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; + }; - Duplex.prototype._destroy.call(this, err, function (err2) { - cb(err2); - _this.emit('close'); - }); -}; + 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; + }; -function done(stream, er, data) { - if (er) return stream.emit('error', er); + XMLDocumentCB.prototype.up = function() { + if (this.currentLevel < 0) { + throw new Error("The document node has no parent"); + } + if (this.currentNode) { + if (this.currentNode.children) { + this.closeNode(this.currentNode); + } else { + this.openNode(this.currentNode); + } + this.currentNode = null; + } else { + this.closeNode(this.openTags[this.currentLevel]); + } + delete this.openTags[this.currentLevel]; + this.currentLevel--; + return this; + }; - if (data !== null && data !== undefined) stream.push(data); + XMLDocumentCB.prototype.end = function() { + while (this.currentLevel >= 0) { + this.up(); + } + return this.onEnd(); + }; - // 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; + XMLDocumentCB.prototype.openCurrent = function() { + if (this.currentNode) { + this.currentNode.children = true; + return this.openNode(this.currentNode); + } + }; - if (ws.length) throw new Error('Calling transform done when ws.length != 0'); + 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 (ts.transforming) throw new Error('Calling transform done when still transforming'); + XMLDocumentCB.prototype.closeNode = function(node) { + if (!node.isClosed) { + this.onData(this.writer.closeNode(node, this.currentLevel)); + return node.isClosed = true; + } + }; - return stream.push(null); -} -},{"./_stream_duplex":91,"core-util-is":8,"inherits":15}],95:[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. + XMLDocumentCB.prototype.onData = function(chunk) { + this.documentStarted = true; + return this.onDataCallback(chunk); + }; -// A bit simpler than readable streams. -// Implement an async ._write(chunk, encoding, cb), and it'll handle all -// the drain event emission and buffering. + XMLDocumentCB.prototype.onEnd = function() { + this.documentCompleted = true; + return this.onEndCallback(); + }; -'use strict'; + XMLDocumentCB.prototype.ele = function() { + return this.element.apply(this, arguments); + }; -/**/ + XMLDocumentCB.prototype.nod = function(name, attributes, text) { + return this.node(name, attributes, text); + }; -var processNextTick = _dereq_('process-nextick-args'); -/**/ + XMLDocumentCB.prototype.txt = function(value) { + return this.text(value); + }; -module.exports = Writable; + XMLDocumentCB.prototype.dat = function(value) { + return this.cdata(value); + }; -/* */ -function WriteReq(chunk, encoding, cb) { - this.chunk = chunk; - this.encoding = encoding; - this.callback = cb; - this.next = null; -} + XMLDocumentCB.prototype.com = function(value) { + return this.comment(value); + }; -// 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; + XMLDocumentCB.prototype.ins = function(target, value) { + return this.instruction(target, value); + }; - this.next = null; - this.entry = null; - this.finish = function () { - onCorkedFinish(_this, state); - }; -} -/* */ + XMLDocumentCB.prototype.dec = function(version, encoding, standalone) { + return this.declaration(version, encoding, standalone); + }; -/**/ -var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick; -/**/ + XMLDocumentCB.prototype.dtd = function(root, pubID, sysID) { + return this.doctype(root, pubID, sysID); + }; -/**/ -var Duplex; -/**/ + XMLDocumentCB.prototype.e = function(name, attributes, text) { + return this.element(name, attributes, text); + }; -Writable.WritableState = WritableState; + XMLDocumentCB.prototype.n = function(name, attributes, text) { + return this.node(name, attributes, text); + }; -/**/ -var util = _dereq_('core-util-is'); -util.inherits = _dereq_('inherits'); -/**/ + XMLDocumentCB.prototype.t = function(value) { + return this.text(value); + }; -/**/ -var internalUtil = { - deprecate: _dereq_('util-deprecate') -}; -/**/ + XMLDocumentCB.prototype.d = function(value) { + return this.cdata(value); + }; -/**/ -var Stream = _dereq_('./internal/streams/stream'); -/**/ + XMLDocumentCB.prototype.c = function(value) { + return this.comment(value); + }; -/**/ -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; -} -/**/ + XMLDocumentCB.prototype.r = function(value) { + return this.raw(value); + }; -var destroyImpl = _dereq_('./internal/streams/destroy'); + XMLDocumentCB.prototype.i = function(target, value) { + return this.instruction(target, value); + }; -util.inherits(Writable, Stream); + XMLDocumentCB.prototype.att = function() { + if (this.currentNode && this.currentNode instanceof XMLDocType) { + return this.attList.apply(this, arguments); + } else { + return this.attribute.apply(this, arguments); + } + }; -function nop() {} + 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 WritableState(options, stream) { - Duplex = Duplex || _dereq_('./_stream_duplex'); + XMLDocumentCB.prototype.ent = function(name, value) { + return this.entity(name, value); + }; - options = options || {}; + XMLDocumentCB.prototype.pent = function(name, value) { + return this.pEntity(name, value); + }; - // object stream flag to indicate whether or not this stream - // contains buffers or objects. - this.objectMode = !!options.objectMode; + XMLDocumentCB.prototype.not = function(name, value) { + return this.notation(name, value); + }; - if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode; + return XMLDocumentCB; - // 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; + })(); - // cast to ints. - this.highWaterMark = Math.floor(this.highWaterMark); +}).call(this); - // if _final has been called - this.finalCalled = false; +},{"./Utility":105,"./XMLAttribute":106,"./XMLCData":107,"./XMLComment":108,"./XMLDTDAttList":109,"./XMLDTDElement":110,"./XMLDTDEntity":111,"./XMLDTDNotation":112,"./XMLDeclaration":113,"./XMLDocType":114,"./XMLElement":117,"./XMLProcessingInstruction":119,"./XMLRaw":120,"./XMLStringWriter":122,"./XMLStringifier":123,"./XMLText":124}],117:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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; - // 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; + ref = _dereq_('./Utility'), isObject = ref.isObject, isFunction = ref.isFunction; - // has it been destroyed - this.destroyed = false; + XMLNode = _dereq_('./XMLNode'); - // 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; + XMLAttribute = _dereq_('./XMLAttribute'); - // 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'; + module.exports = XMLElement = (function(superClass) { + extend(XMLElement, superClass); - // 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; + function XMLElement(parent, name, attributes) { + XMLElement.__super__.constructor.call(this, parent); + if (name == null) { + throw new Error("Missing element name"); + } + this.name = this.stringify.eleName(name); + this.attributes = {}; + if (attributes != null) { + this.attribute(attributes); + } + if (parent.isDocument) { + this.isRoot = true; + this.documentObject = parent; + parent.rootObject = this; + } + } - // a flag to see when we're in the middle of a write. - this.writing = false; + XMLElement.prototype.clone = function() { + var att, attName, clonedSelf, ref1; + clonedSelf = Object.create(this); + if (clonedSelf.isRoot) { + clonedSelf.documentObject = null; + } + clonedSelf.attributes = {}; + ref1 = this.attributes; + for (attName in ref1) { + if (!hasProp.call(ref1, attName)) continue; + att = ref1[attName]; + clonedSelf.attributes[attName] = att.clone(); + } + clonedSelf.children = []; + this.children.forEach(function(child) { + var clonedChild; + clonedChild = child.clone(); + clonedChild.parent = clonedSelf; + return clonedSelf.children.push(clonedChild); + }); + return clonedSelf; + }; - // when true all writes will be buffered until .uncork() call - this.corked = 0; + XMLElement.prototype.attribute = function(name, value) { + var attName, attValue; + 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); + } + } else { + if (isFunction(value)) { + value = value.apply(); + } + if (!this.options.skipNullAttributes || (value != null)) { + this.attributes[name] = new XMLAttribute(this, name, value); + } + } + return this; + }; - // 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; + XMLElement.prototype.removeAttribute = function(name) { + var attName, i, len; + if (name == null) { + throw new Error("Missing attribute name"); + } + name = name.valueOf(); + if (Array.isArray(name)) { + for (i = 0, len = name.length; i < len; i++) { + attName = name[i]; + delete this.attributes[attName]; + } + } else { + delete this.attributes[name]; + } + return 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; + XMLElement.prototype.toString = function(options) { + return this.options.writer.set(options).element(this); + }; - // the callback that's passed to _write(chunk,cb) - this.onwrite = function (er) { - onwrite(stream, er); - }; + XMLElement.prototype.att = function(name, value) { + return this.attribute(name, value); + }; - // the callback that the user supplies to write(chunk,encoding,cb) - this.writecb = null; + XMLElement.prototype.a = function(name, value) { + return this.attribute(name, value); + }; - // the amount that is being written when _write is called. - this.writelen = 0; + return XMLElement; - this.bufferedRequest = null; - this.lastBufferedRequest = null; + })(XMLNode); - // number of pending user-supplied write callbacks - // this must be 0 before 'finish' can be emitted - this.pendingcb = 0; +}).call(this); - // emit prefinish if the only thing we're waiting for is _write cbs - // This is relevant for synchronous Transform streams - this.prefinished = false; +},{"./Utility":105,"./XMLAttribute":106,"./XMLNode":118}],118:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(function() { + var XMLCData, XMLComment, XMLDeclaration, XMLDocType, XMLElement, XMLNode, XMLProcessingInstruction, XMLRaw, XMLText, isEmpty, isFunction, isObject, ref, + hasProp = {}.hasOwnProperty; - // True if the error was already emitted and should not be thrown again - this.errorEmitted = false; + ref = _dereq_('./Utility'), isObject = ref.isObject, isFunction = ref.isFunction, isEmpty = ref.isEmpty; - // count buffered requests - this.bufferedRequestCount = 0; + XMLElement = null; - // allocate the first CorkedRequest, there is always - // one allocated and free to use, and we maintain at most two - this.corkedRequestsFree = new CorkedRequest(this); -} + XMLCData = null; -WritableState.prototype.getBuffer = function getBuffer() { - var current = this.bufferedRequest; - var out = []; - while (current) { - out.push(current); - current = current.next; - } - return out; -}; + XMLComment = null; -(function () { - try { - Object.defineProperty(WritableState.prototype, 'buffer', { - get: internalUtil.deprecate(function () { - return this.getBuffer(); - }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003') - }); - } catch (_) {} -})(); + XMLDeclaration = null; -// 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; + XMLDocType = null; - return object && object._writableState instanceof WritableState; - } - }); -} else { - realHasInstance = function (object) { - return object instanceof this; - }; -} + XMLRaw = null; -function Writable(options) { - Duplex = Duplex || _dereq_('./_stream_duplex'); + XMLText = null; - // Writable ctor is applied to Duplexes, too. - // `realHasInstance` is necessary because using plain `instanceof` - // would return false, as no `_writableState` property is attached. + XMLProcessingInstruction = null; - // 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); - } + module.exports = XMLNode = (function() { + function XMLNode(parent) { + this.parent = parent; + if (this.parent) { + this.options = this.parent.options; + this.stringify = this.parent.stringify; + } + 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'); + } + } - this._writableState = new WritableState(options, this); + 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; + }; - // legacy. - this.writable = true; + 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; + }; - if (options) { - if (typeof options.write === 'function') this._write = options.write; + XMLNode.prototype.insertAfter = 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 + 1); + child = this.parent.element(name, attributes, text); + Array.prototype.push.apply(this.parent.children, removed); + return child; + }; - if (typeof options.writev === 'function') this._writev = options.writev; + 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; + }; - if (typeof options.destroy === 'function') this._destroy = options.destroy; + XMLNode.prototype.node = function(name, attributes, text) { + var child, ref1; + if (name != null) { + name = name.valueOf(); + } + attributes || (attributes = {}); + attributes = attributes.valueOf(); + if (!isObject(attributes)) { + ref1 = [attributes, text], text = ref1[0], attributes = ref1[1]; + } + child = new XMLElement(this, name, attributes); + if (text != null) { + child.text(text); + } + this.children.push(child); + return child; + }; - if (typeof options.final === 'function') this._final = options.final; - } + XMLNode.prototype.text = function(value) { + var child; + child = new XMLText(this, value); + this.children.push(child); + return this; + }; - Stream.call(this); -} + XMLNode.prototype.cdata = function(value) { + var child; + child = new XMLCData(this, value); + this.children.push(child); + 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')); -}; + XMLNode.prototype.comment = function(value) { + var child; + child = new XMLComment(this, value); + this.children.push(child); + return this; + }; -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); -} + 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; + }; -// 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; + 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; + }; - 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; -} + XMLNode.prototype.raw = function(value) { + var child; + child = new XMLRaw(this, value); + this.children.push(child); + return this; + }; -Writable.prototype.write = function (chunk, encoding, cb) { - var state = this._writableState; - var ret = false; - var isBuf = _isUint8Array(chunk) && !state.objectMode; + XMLNode.prototype.instruction = function(target, value) { + var insTarget, insValue, instruction, j, len; + if (target != null) { + target = target.valueOf(); + } + if (value != null) { + value = value.valueOf(); + } + if (Array.isArray(target)) { + for (j = 0, len = target.length; j < len; j++) { + insTarget = target[j]; + 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(); + } + instruction = new XMLProcessingInstruction(this, target, value); + this.children.push(instruction); + } + return this; + }; - if (isBuf && !Buffer.isBuffer(chunk)) { - chunk = _uint8ArrayToBuffer(chunk); - } + 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; + }; - if (typeof encoding === 'function') { - cb = encoding; - encoding = null; - } + 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; + }; - if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; + 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; + }; - if (typeof cb !== 'function') cb = nop; + 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; + } + } + 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; + } + } + doc.children.push(doctype); + return doctype; + }; - if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { - state.pendingcb++; - ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); - } + 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; + }; - return ret; -}; + XMLNode.prototype.root = function() { + var node; + node = this; + while (node) { + if (node.isDocument) { + return node.rootObject; + } else if (node.isRoot) { + return node; + } else { + node = node.parent; + } + } + }; -Writable.prototype.cork = function () { - var state = this._writableState; + XMLNode.prototype.document = function() { + var node; + node = this; + while (node) { + if (node.isDocument) { + return node; + } else { + node = node.parent; + } + } + }; - state.corked++; -}; + XMLNode.prototype.end = function(options) { + return this.document().end(options); + }; -Writable.prototype.uncork = function () { - var state = this._writableState; + XMLNode.prototype.prev = function() { + var i; + i = this.parent.children.indexOf(this); + if (i < 1) { + throw new Error("Already at the first node"); + } + return this.parent.children[i - 1]; + }; - if (state.corked) { - state.corked--; + 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 this.parent.children[i + 1]; + }; - if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); - } -}; + XMLNode.prototype.importDocument = function(doc) { + var clonedRoot; + clonedRoot = doc.root().clone(); + clonedRoot.parent = this; + clonedRoot.isRoot = false; + this.children.push(clonedRoot); + return 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; -}; + XMLNode.prototype.ele = function(name, attributes, text) { + return this.element(name, attributes, text); + }; -function decodeChunk(state, chunk, encoding) { - if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { - chunk = Buffer.from(chunk, encoding); - } - return chunk; -} + XMLNode.prototype.nod = function(name, attributes, text) { + return this.node(name, attributes, text); + }; -// 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; - } - } - var len = state.objectMode ? 1 : chunk.length; + XMLNode.prototype.txt = function(value) { + return this.text(value); + }; - state.length += len; + XMLNode.prototype.dat = function(value) { + return this.cdata(value); + }; - var ret = state.length < state.highWaterMark; - // we must ensure that previous needDrain will not be reset to false. - if (!ret) state.needDrain = true; + XMLNode.prototype.com = function(value) { + return this.comment(value); + }; - if (state.writing || state.corked) { - var last = state.lastBufferedRequest; - state.lastBufferedRequest = { - chunk: chunk, - encoding: encoding, - isBuf: isBuf, - callback: cb, - next: null + XMLNode.prototype.ins = function(target, value) { + return this.instruction(target, value); }; - if (last) { - last.next = state.lastBufferedRequest; - } else { - state.bufferedRequest = state.lastBufferedRequest; - } - state.bufferedRequestCount += 1; - } else { - doWrite(stream, state, false, len, chunk, encoding, cb); - } - return ret; -} + XMLNode.prototype.doc = function() { + return this.document(); + }; -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; -} + XMLNode.prototype.dec = function(version, encoding, standalone) { + return this.declaration(version, encoding, standalone); + }; -function onwriteError(stream, state, sync, er, cb) { - --state.pendingcb; + XMLNode.prototype.dtd = function(pubID, sysID) { + return this.doctype(pubID, sysID); + }; - 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); - } -} + XMLNode.prototype.e = function(name, attributes, text) { + return this.element(name, attributes, text); + }; -function onwriteStateUpdate(state) { - state.writing = false; - state.writecb = null; - state.length -= state.writelen; - state.writelen = 0; -} + XMLNode.prototype.n = function(name, attributes, text) { + return this.node(name, attributes, text); + }; -function onwrite(stream, er) { - var state = stream._writableState; - var sync = state.sync; - var cb = state.writecb; + XMLNode.prototype.t = function(value) { + return this.text(value); + }; - onwriteStateUpdate(state); + XMLNode.prototype.d = function(value) { + return this.cdata(value); + }; - 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); + XMLNode.prototype.c = function(value) { + return this.comment(value); + }; - if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) { - clearBuffer(stream, state); - } + XMLNode.prototype.r = function(value) { + return this.raw(value); + }; - if (sync) { - /**/ - asyncWrite(afterWrite, stream, state, finished, cb); - /**/ - } else { - afterWrite(stream, state, finished, cb); - } - } -} + XMLNode.prototype.i = function(target, value) { + return this.instruction(target, value); + }; -function afterWrite(stream, state, finished, cb) { - if (!finished) onwriteDrain(stream, state); - state.pendingcb--; - cb(); - finishMaybe(stream, state); -} + XMLNode.prototype.u = function() { + return this.up(); + }; -// 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'); - } -} + XMLNode.prototype.importXMLBuilder = function(doc) { + return this.importDocument(doc); + }; -// if there's something in the buffer waiting, then process it -function clearBuffer(stream, state) { - state.bufferProcessing = true; - var entry = state.bufferedRequest; + return XMLNode; - 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; +}).call(this); - doWrite(stream, state, true, state.length, buffer, '', holder.finish); +},{"./Utility":105,"./XMLCData":107,"./XMLComment":108,"./XMLDeclaration":113,"./XMLDocType":114,"./XMLElement":117,"./XMLProcessingInstruction":119,"./XMLRaw":120,"./XMLText":124}],119:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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; - // 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; + XMLNode = _dereq_('./XMLNode'); - 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; + 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); } } - 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')); -}; - -Writable.prototype._writev = null; - -Writable.prototype.end = function (chunk, encoding, cb) { - var state = this._writableState; - - if (typeof chunk === 'function') { - cb = chunk; - chunk = null; - encoding = null; - } else if (typeof encoding === 'function') { - cb = encoding; - encoding = null; - } + XMLProcessingInstruction.prototype.clone = function() { + return Object.create(this); + }; - if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); + XMLProcessingInstruction.prototype.toString = function(options) { + return this.options.writer.set(options).processingInstruction(this); + }; - // .end() fully uncorks - if (state.corked) { - state.corked = 1; - this.uncork(); - } + return XMLProcessingInstruction; - // ignore unnecessary end() calls. - if (!state.ending && !state.finished) endWritable(this, state, cb); -}; + })(XMLNode); -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); - } - 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'); - } - } -} +}).call(this); -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; -} +},{"./XMLNode":118}],120:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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; -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; -} + XMLNode = _dereq_('./XMLNode'); -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; - } -} + module.exports = XMLRaw = (function(superClass) { + extend(XMLRaw, superClass); -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; + function XMLRaw(parent, text) { + XMLRaw.__super__.constructor.call(this, parent); + if (text == null) { + throw new Error("Missing raw text"); + } + this.value = this.stringify.raw(text); } - // backward compatibility, the user is explicitly - // managing destroyed - this._writableState.destroyed = value; - } -}); + XMLRaw.prototype.clone = function() { + return Object.create(this); + }; -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 : {}) + XMLRaw.prototype.toString = function(options) { + return this.options.writer.set(options).raw(this); + }; -},{"./_stream_duplex":91,"./internal/streams/destroy":97,"./internal/streams/stream":98,"_process":43,"core-util-is":8,"inherits":15,"process-nextick-args":42,"safe-buffer":105,"util-deprecate":115}],96:[function(_dereq_,module,exports){ -'use strict'; + return XMLRaw; -/**/ + })(XMLNode); -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +}).call(this); -var Buffer = _dereq_('safe-buffer').Buffer; -/**/ +},{"./XMLNode":118}],121:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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; -function copyBuffer(src, target, offset) { - src.copy(target, offset); -} + XMLDeclaration = _dereq_('./XMLDeclaration'); -module.exports = function () { - function BufferList() { - _classCallCheck(this, BufferList); + XMLDocType = _dereq_('./XMLDocType'); - this.head = null; - this.tail = null; - this.length = 0; - } + XMLCData = _dereq_('./XMLCData'); - 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; - }; + XMLComment = _dereq_('./XMLComment'); - 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; - }; + XMLElement = _dereq_('./XMLElement'); - 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; - }; + XMLRaw = _dereq_('./XMLRaw'); - BufferList.prototype.clear = function clear() { - this.head = this.tail = null; - this.length = 0; - }; + XMLText = _dereq_('./XMLText'); - 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; - }; + XMLProcessingInstruction = _dereq_('./XMLProcessingInstruction'); - 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; - }; + XMLDTDAttList = _dereq_('./XMLDTDAttList'); - return BufferList; -}(); -},{"safe-buffer":105}],97:[function(_dereq_,module,exports){ -'use strict'; + XMLDTDElement = _dereq_('./XMLDTDElement'); -/**/ + XMLDTDEntity = _dereq_('./XMLDTDEntity'); -var processNextTick = _dereq_('process-nextick-args'); -/**/ + XMLDTDNotation = _dereq_('./XMLDTDNotation'); -// undocumented cb() API, needed for core, not for public API -function destroy(err, cb) { - var _this = this; + XMLWriterBase = _dereq_('./XMLWriterBase'); - var readableDestroyed = this._readableState && this._readableState.destroyed; - var writableDestroyed = this._writableState && this._writableState.destroyed; + module.exports = XMLStreamWriter = (function(superClass) { + extend(XMLStreamWriter, superClass); - if (readableDestroyed || writableDestroyed) { - if (cb) { - cb(err); - } else if (err && (!this._writableState || !this._writableState.errorEmitted)) { - processNextTick(emitErrorNT, this, err); + function XMLStreamWriter(stream, options) { + XMLStreamWriter.__super__.constructor.call(this, options); + this.stream = stream; } - return; - } - - // we set destroyed to true before firing error callbacks in order - // to make it re-entrance safe in case destroy() is called within callbacks - - if (this._readableState) { - this._readableState.destroyed = true; - } - // 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; + 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; } - } 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); -} + 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; + }; -module.exports = { - destroy: destroy, - undestroy: undestroy -}; -},{"process-nextick-args":42}],98:[function(_dereq_,module,exports){ -module.exports = _dereq_('events').EventEmitter; + XMLStreamWriter.prototype.attribute = function(att) { + return this.stream.write(' ' + att.name + '="' + att.value + '"'); + }; -},{"events":10}],99:[function(_dereq_,module,exports){ -arguments[4][6][0].apply(exports,arguments) -},{"dup":6}],100:[function(_dereq_,module,exports){ -'use strict'; + XMLStreamWriter.prototype.cdata = function(node, level) { + return this.stream.write(this.space(level) + '' + this.endline(node)); + }; -var Buffer = _dereq_('safe-buffer').Buffer; + XMLStreamWriter.prototype.comment = function(node, level) { + return this.stream.write(this.space(level) + '' + this.endline(node)); + }; -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; - } -}; + XMLStreamWriter.prototype.declaration = function(node, level) { + this.stream.write(this.space(level)); + this.stream.write(''); + return this.stream.write(this.endline(node)); + }; -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; - } - } -}; + 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)); + }; -// 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; -} + 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)); + }; -// 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); -} + XMLStreamWriter.prototype.processingInstruction = function(node, level) { + this.stream.write(this.space(level) + '' + this.endline(node)); + }; -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 || ''; -}; + XMLStreamWriter.prototype.raw = function(node, level) { + return this.stream.write(this.space(level) + node.value + this.endline(node)); + }; -StringDecoder.prototype.end = utf8End; + XMLStreamWriter.prototype.text = function(node, level) { + return this.stream.write(this.space(level) + node.value + this.endline(node)); + }; -// Returns only complete characters in a Buffer -StringDecoder.prototype.text = utf8Text; + XMLStreamWriter.prototype.dtdAttList = function(node, level) { + this.stream.write(this.space(level) + '' + this.endline(node)); + }; -// 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; -}; + XMLStreamWriter.prototype.dtdElement = function(node, level) { + this.stream.write(this.space(level) + '' + this.endline(node)); + }; -// 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; -} + XMLStreamWriter.prototype.dtdEntity = function(node, level) { + this.stream.write(this.space(level) + '' + this.endline(node)); + }; -// 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; -} + XMLStreamWriter.prototype.dtdNotation = function(node, level) { + this.stream.write(this.space(level) + '' + this.endline(node)); + }; -// 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); + XMLStreamWriter.prototype.endline = function(node) { + if (!node.isLastRootNode) { + return this.newline; + } else { + return ''; } - } - } -} + }; -// 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 XMLStreamWriter; -// 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); -} + })(XMLWriterBase); -// 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; -} +}).call(this); -// 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); -} +},{"./XMLCData":107,"./XMLComment":108,"./XMLDTDAttList":109,"./XMLDTDElement":110,"./XMLDTDEntity":111,"./XMLDTDNotation":112,"./XMLDeclaration":113,"./XMLDocType":114,"./XMLElement":117,"./XMLProcessingInstruction":119,"./XMLRaw":120,"./XMLText":124,"./XMLWriterBase":125}],122:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(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; -// 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; -} + XMLDeclaration = _dereq_('./XMLDeclaration'); -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); -} + XMLDocType = _dereq_('./XMLDocType'); -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; -} + XMLCData = _dereq_('./XMLCData'); -// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex) -function simpleWrite(buf) { - return buf.toString(this.encoding); -} + XMLComment = _dereq_('./XMLComment'); -function simpleEnd(buf) { - return buf && buf.length ? this.write(buf) : ''; -} -},{"safe-buffer":105}],101:[function(_dereq_,module,exports){ -module.exports = _dereq_('./readable').PassThrough + XMLElement = _dereq_('./XMLElement'); -},{"./readable":102}],102:[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'); + XMLRaw = _dereq_('./XMLRaw'); -},{"./lib/_stream_duplex.js":91,"./lib/_stream_passthrough.js":92,"./lib/_stream_readable.js":93,"./lib/_stream_transform.js":94,"./lib/_stream_writable.js":95}],103:[function(_dereq_,module,exports){ -module.exports = _dereq_('./readable').Transform + XMLText = _dereq_('./XMLText'); -},{"./readable":102}],104:[function(_dereq_,module,exports){ -module.exports = _dereq_('./lib/_stream_writable.js'); + XMLProcessingInstruction = _dereq_('./XMLProcessingInstruction'); -},{"./lib/_stream_writable.js":95}],105:[function(_dereq_,module,exports){ -/* eslint-disable node/no-deprecated-api */ -var buffer = _dereq_('buffer') -var Buffer = buffer.Buffer + XMLDTDAttList = _dereq_('./XMLDTDAttList'); -// 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 -} + XMLDTDElement = _dereq_('./XMLDTDElement'); -function SafeBuffer (arg, encodingOrOffset, length) { - return Buffer(arg, encodingOrOffset, length) -} + XMLDTDEntity = _dereq_('./XMLDTDEntity'); -// Copy static methods from Buffer -copyProps(Buffer, SafeBuffer) + XMLDTDNotation = _dereq_('./XMLDTDNotation'); -SafeBuffer.from = function (arg, encodingOrOffset, length) { - if (typeof arg === 'number') { - throw new TypeError('Argument must not be a number') - } - return Buffer(arg, encodingOrOffset, length) -} + XMLWriterBase = _dereq_('./XMLWriterBase'); -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) + module.exports = XMLStringWriter = (function(superClass) { + extend(XMLStringWriter, superClass); + + function XMLStringWriter(options) { + XMLStringWriter.__super__.constructor.call(this, options); } - } else { - buf.fill(0) - } - return buf -} -SafeBuffer.allocUnsafe = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - return Buffer(size) -} + 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; + }; -SafeBuffer.allocUnsafeSlow = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - return buffer.SlowBuffer(size) -} + XMLStringWriter.prototype.attribute = function(att) { + return ' ' + att.name + '="' + att.value + '"'; + }; -},{"buffer":5}],106:[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 + XMLStringWriter.prototype.cdata = function(node, level) { + return this.space(level) + '' + this.newline; + }; - // 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 - - var buffers = [ - 'comment', 'sgmlDecl', 'textNode', 'tagName', 'doctype', - 'procInstName', 'procInstBody', 'entity', 'attribName', - 'attribValue', 'cdata', 'script' - ] + XMLStringWriter.prototype.comment = function(node, level) { + return this.space(level) + '' + this.newline; + }; - sax.EVENTS = [ - 'text', - 'processinginstruction', - 'sgmldeclaration', - 'doctype', - 'comment', - 'opentagstart', - 'attribute', - 'opentag', - 'closetag', - 'opencdata', - 'cdata', - 'closecdata', - 'error', - 'end', - 'ready', - 'script', - 'opennamespace', - 'closenamespace' - ] + XMLStringWriter.prototype.declaration = function(node, level) { + var r; + r = this.space(level); + r += ''; + r += this.newline; + return r; + }; - function SAXParser (strict, opt) { - if (!(this instanceof SAXParser)) { - return new SAXParser(strict, opt) - } + 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); + } + r += ']'; + } + r += this.spacebeforeslash + '>'; + r += this.newline; + return r; + }; - 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 = [] + 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; + } + } 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; + } + } + } + if (this.textispresent) { + this.newline = ''; + this.pretty = false; + space = this.space(level); + } + 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); + } + }).call(this); + } + if (textispresentwasset) { + this.textispresent--; + } + if (!this.textispresent) { + this.newline = this.newlinedefault; + this.pretty = this.prettydefault; + } + r += space + '' + this.newline; + } + return r; + }; - // 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) - } + XMLStringWriter.prototype.processingInstruction = function(node, level) { + var r; + r = this.space(level) + '' + this.newline; + return r; + }; - // mostly just for error reporting - parser.trackPosition = parser.opt.position !== false - if (parser.trackPosition) { - parser.position = parser.line = parser.column = 0 - } - emit(parser, 'onready') - } + XMLStringWriter.prototype.raw = function(node, level) { + return this.space(level) + node.value + this.newline; + }; - if (!Object.create) { - Object.create = function (o) { - function F () {} - F.prototype = o - var newf = new F() - return newf - } - } + XMLStringWriter.prototype.text = function(node, level) { + return this.space(level) + node.value + this.newline; + }; - if (!Object.keys) { - Object.keys = function (o) { - var a = [] - for (var i in o) if (o.hasOwnProperty(i)) a.push(i) - return a - } - } + XMLStringWriter.prototype.dtdAttList = function(node, level) { + var r; + r = this.space(level) + '' + this.newline; + return r; + }; - 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 + XMLStringWriter.prototype.dtdElement = function(node, level) { + return this.space(level) + '' + this.newline; + }; - case 'cdata': - emitNode(parser, 'oncdata', parser.cdata) - parser.cdata = '' - break + XMLStringWriter.prototype.dtdEntity = function(node, level) { + var r; + r = this.space(level) + '' + this.newline; + return r; + }; - case 'script': - emitNode(parser, 'onscript', parser.script) - parser.script = '' - break + XMLStringWriter.prototype.dtdNotation = function(node, level) { + var r; + r = this.space(level) + '' + this.newline; + return r; + }; - default: - error(parser, 'Max buffer length exceeded: ' + buffers[i]) + 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); + } + r += (node.children ? '>' : '/>') + this.newline; + return r; + } else { + r = this.space(level) + '') + this.newline; + return r; } - 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 - } - - function clearBuffers (parser) { - for (var i = 0, l = buffers.length; i < l; i++) { - parser[buffers[i]] = '' - } - } + }; - 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 = '' - } - } + 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; + } + }; - 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) } - } + return XMLStringWriter; - var Stream - try { - Stream = _dereq_('stream').Stream - } catch (ex) { - Stream = function () {} - } + })(XMLWriterBase); - var streamWraps = sax.EVENTS.filter(function (ev) { - return ev !== 'error' && ev !== 'end' - }) +}).call(this); - function createStream (strict, opt) { - return new SAXStream(strict, opt) - } +},{"./XMLCData":107,"./XMLComment":108,"./XMLDTDAttList":109,"./XMLDTDElement":110,"./XMLDTDEntity":111,"./XMLDTDNotation":112,"./XMLDeclaration":113,"./XMLDocType":114,"./XMLElement":117,"./XMLProcessingInstruction":119,"./XMLRaw":120,"./XMLText":124,"./XMLWriterBase":125}],123:[function(_dereq_,module,exports){ +// Generated by CoffeeScript 1.12.7 +(function() { + var XMLStringifier, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + hasProp = {}.hasOwnProperty; - function SAXStream (strict, opt) { - if (!(this instanceof SAXStream)) { - return new SAXStream(strict, opt) + 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; + } } - Stream.apply(this) + XMLStringifier.prototype.eleName = function(val) { + val = '' + val || ''; + return this.assertLegalChar(val); + }; - this._parser = new SAXParser(strict, opt) - this.writable = true - this.readable = true + XMLStringifier.prototype.eleText = function(val) { + val = '' + val || ''; + return this.assertLegalChar(this.elEscape(val)); + }; - var me = this + XMLStringifier.prototype.cdata = function(val) { + val = '' + val || ''; + val = val.replace(']]>', ']]]]>'); + return this.assertLegalChar(val); + }; - this._parser.onend = function () { - me.emit('end') - } + XMLStringifier.prototype.comment = function(val) { + val = '' + val || ''; + if (val.match(/--/)) { + throw new Error("Comment text cannot contain double-hypen: " + val); + } + return this.assertLegalChar(val); + }; - this._parser.onerror = function (er) { - me.emit('error', er) + XMLStringifier.prototype.raw = function(val) { + return '' + val || ''; + }; - // if didn't throw, then means error was handled. - // go ahead and clear error, so we can write again. - me._parser.error = null - } + XMLStringifier.prototype.attName = function(val) { + return val = '' + val || ''; + }; - this._decoder = null + XMLStringifier.prototype.attValue = function(val) { + val = '' + val || ''; + return this.attEscape(val); + }; - 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 - }) - }) - } + XMLStringifier.prototype.insTarget = function(val) { + return '' + val || ''; + }; - SAXStream.prototype = Object.create(Stream.prototype, { - constructor: { - value: SAXStream - } - }) + XMLStringifier.prototype.insValue = function(val) { + val = '' + val || ''; + if (val.match(/\?>/)) { + throw new Error("Invalid processing instruction value: " + val); + } + return val; + }; - 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') + XMLStringifier.prototype.xmlVersion = function(val) { + val = '' + val || ''; + if (!val.match(/1\.[0-9]+/)) { + throw new Error("Invalid version number: " + val); } - data = this._decoder.write(data) - } + return val; + }; - this._parser.write(data.toString()) - this.emit('data', data) - return true - } + 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; + }; - SAXStream.prototype.end = function (chunk) { - if (chunk && chunk.length) { - this.write(chunk) - } - 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) + XMLStringifier.prototype.xmlStandalone = function(val) { + if (val) { + return "yes"; + } else { + return "no"; } - } + }; - return Stream.prototype.on.call(me, ev, handler) - } + XMLStringifier.prototype.dtdPubID = function(val) { + return '' + val || ''; + }; - // 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 } + XMLStringifier.prototype.dtdSysID = function(val) { + return '' + val || ''; + }; - // 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]/ + XMLStringifier.prototype.dtdElementValue = function(val) { + return '' + val || ''; + }; - 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-]/ + XMLStringifier.prototype.dtdAttType = function(val) { + return '' + val || ''; + }; - 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-]/ + XMLStringifier.prototype.dtdAttDefault = function(val) { + if (val != null) { + return '' + val || ''; + } else { + return val; + } + }; - function isWhitespace (c) { - return c === ' ' || c === '\n' || c === '\r' || c === '\t' - } + XMLStringifier.prototype.dtdEntityValue = function(val) { + return '' + val || ''; + }; - function isQuote (c) { - return c === '"' || c === '\'' - } + XMLStringifier.prototype.dtdNData = function(val) { + return '' + val || ''; + }; - function isAttribEnd (c) { - return c === '>' || isWhitespace(c) - } + XMLStringifier.prototype.convertAttKey = '@'; - function isMatch (regex, c) { - return regex.test(c) - } + XMLStringifier.prototype.convertPIKey = '?'; - function notMatch (regex, c) { - return !isMatch(regex, c) - } + XMLStringifier.prototype.convertTextKey = '#text'; - 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++, //