(function() { /** * This file installs all of the polyfills that BrowserFS requires. */ // IE < 9 does not define this function. if (!Date.now) { Date.now = function now() { return new Date().getTime(); }; } // IE < 9 does not define this function. if (!Array.isArray) { Array.isArray = function (vArg) { return Object.prototype.toString.call(vArg) === "[object Array]"; }; } // IE < 9 does not define this function. // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys if (!Object.keys) { Object.keys = (function () { var hasOwnProperty = Object.prototype.hasOwnProperty, hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'), dontEnums = [ 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ], dontEnumsLength = dontEnums.length; return function (obj) { if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { throw new TypeError('Object.keys called on non-object'); } var result = [], prop, i; for (prop in obj) { if (hasOwnProperty.call(obj, prop)) { result.push(prop); } } if (hasDontEnumBug) { for (i = 0; i < dontEnumsLength; i++) { if (hasOwnProperty.call(obj, dontEnums[i])) { result.push(dontEnums[i]); } } } return result; }; }()); } // IE substr does not support negative indices if ('ab'.substr(-1) !== 'b') { String.prototype.substr = function (substr) { return function (start, length) { // did we get a negative start, calculate how much it is from the // beginning of the string if (start < 0) start = this.length + start; // call the original function return substr.call(this, start, length); }; }(String.prototype.substr); } // IE < 9 does not support forEach if (!Array.prototype.forEach) { Array.prototype.forEach = function (fn, scope) { for (var i = 0; i < this.length; ++i) { if (i in this) { fn.call(scope, this[i], i, this); } } }; } // Only IE10 has setImmediate. // @todo: Determine viability of switching to the 'proper' polyfill for this. if (typeof setImmediate === 'undefined') { // XXX avoid importing the global module. var gScope = typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : global; var timeouts = []; var messageName = "zero-timeout-message"; var canUsePostMessage = function () { if (typeof gScope.importScripts !== 'undefined' || !gScope.postMessage) { return false; } var postMessageIsAsync = true; var oldOnMessage = gScope.onmessage; gScope.onmessage = function () { postMessageIsAsync = false; }; gScope.postMessage('', '*'); gScope.onmessage = oldOnMessage; return postMessageIsAsync; }; if (canUsePostMessage()) { gScope.setImmediate = function (fn) { timeouts.push(fn); gScope.postMessage(messageName, "*"); }; var handleMessage = function (event) { if (event.source === self && event.data === messageName) { if (event.stopPropagation) { event.stopPropagation(); } else { event.cancelBubble = true; } if (timeouts.length > 0) { var fn = timeouts.shift(); return fn(); } } }; if (gScope.addEventListener) { gScope.addEventListener('message', handleMessage, true); } else { gScope.attachEvent('onmessage', handleMessage); } } else if (gScope.MessageChannel) { // WebWorker MessageChannel var channel = new gScope.MessageChannel(); channel.port1.onmessage = function (event) { if (timeouts.length > 0) { return timeouts.shift()(); } }; gScope.setImmediate = function (fn) { timeouts.push(fn); channel.port2.postMessage(''); }; } else { gScope.setImmediate = function (fn) { return setTimeout(fn, 0); var scriptEl = window.document.createElement("script"); scriptEl.onreadystatechange = function () { fn(); scriptEl.onreadystatechange = null; scriptEl.parentNode.removeChild(scriptEl); return scriptEl = null; }; gScope.document.documentElement.appendChild(scriptEl); }; } } // IE<9 does not define indexOf. // From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (searchElement, fromIndex) { if (typeof fromIndex === "undefined") { fromIndex = 0; } if (!this) { throw new TypeError(); } var length = this.length; if (length === 0 || pivot >= length) { return -1; } var pivot = fromIndex; if (pivot < 0) { pivot = length + pivot; } for (var i = pivot; i < length; i++) { if (this[i] === searchElement) { return i; } } return -1; }; } // IE<9 does not support forEach // From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach if (!Array.prototype.forEach) { Array.prototype.forEach = function (fn, scope) { var i, len; for (i = 0, len = this.length; i < len; ++i) { if (i in this) { fn.call(scope, this[i], i, this); } } }; } // IE<9 does not support map // From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map if (!Array.prototype.map) { Array.prototype.map = function (callback, thisArg) { var T, A, k; if (this == null) { throw new TypeError(" this is null or not defined"); } // 1. Let O be the result of calling ToObject passing the |this| value as the argument. var O = Object(this); // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". // 3. Let len be ToUint32(lenValue). var len = O.length >>> 0; // 4. If IsCallable(callback) is false, throw a TypeError exception. // See: http://es5.github.com/#x9.11 if (typeof callback !== "function") { throw new TypeError(callback + " is not a function"); } // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. if (thisArg) { T = thisArg; } // 6. Let A be a new array created as if by the expression new Array(len) where Array is // the standard built-in constructor with that name and len is the value of len. A = new Array(len); // 7. Let k be 0 k = 0; while (k < len) { var kValue, mappedValue; // a. Let Pk be ToString(k). // This is implicit for LHS operands of the in operator // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. // This step can be combined with c // c. If kPresent is true, then if (k in O) { // i. Let kValue be the result of calling the Get internal method of O with argument Pk. kValue = O[k]; // ii. Let mappedValue be the result of calling the Call internal method of callback // with T as the this value and argument list containing kValue, k, and O. mappedValue = callback.call(T, kValue, k, O); // iii. Call the DefineOwnProperty internal method of A with arguments // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, // and false. // In browsers that support Object.defineProperty, use the following: // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); // For best browser support, use the following: A[k] = mappedValue; } // d. Increase k by 1. k++; } // 9. return A return A; }; } /** * IE9 and below only: Injects a VBScript function that converts the * 'responseBody' attribute of an XMLHttpRequest into a bytestring. * From: http://miskun.com/javascript/internet-explorer-and-binary-files-data-access/#comment-17 * * This must be performed *before* the page finishes loading, otherwise * document.write will refresh the page. :( * * This is harmless to inject into non-IE browsers. */ if (typeof document !== 'undefined' && window['chrome'] === undefined) { document.write("\r\n" + "\r\n"); } //# sourceMappingURL=polyfills.js.map /** * @license almond 0.3.0 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/almond for details */ //Going sloppy to avoid 'use strict' string cost, but strict practices should //be followed. /*jslint sloppy: true */ /*global setTimeout: false */ var requirejs, require, define; (function (undef) { var main, req, makeMap, handlers, defined = {}, waiting = {}, config = {}, defining = {}, hasOwn = Object.prototype.hasOwnProperty, aps = [].slice, jsSuffixRegExp = /\.js$/; function hasProp(obj, prop) { return hasOwn.call(obj, prop); } /** * Given a relative module name, like ./something, normalize it to * a real name that can be mapped to a path. * @param {String} name the relative name * @param {String} baseName a real name that the name arg is relative * to. * @returns {String} normalized name */ function normalize(name, baseName) { var nameParts, nameSegment, mapValue, foundMap, lastIndex, foundI, foundStarMap, starI, i, j, part, baseParts = baseName && baseName.split("/"), map = config.map, starMap = (map && map['*']) || {}; //Adjust any relative paths. if (name && name.charAt(0) === ".") { //If have a base name, try to normalize against it, //otherwise, assume it is a top-level require that will //be relative to baseUrl in the end. if (baseName) { //Convert baseName to array, and lop off the last part, //so that . matches that "directory" and not name of the baseName's //module. For instance, baseName of "one/two/three", maps to //"one/two/three.js", but we want the directory, "one/two" for //this normalization. baseParts = baseParts.slice(0, baseParts.length - 1); name = name.split('/'); lastIndex = name.length - 1; // Node .js allowance: if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); } name = baseParts.concat(name); //start trimDots for (i = 0; i < name.length; i += 1) { part = name[i]; if (part === ".") { name.splice(i, 1); i -= 1; } else if (part === "..") { if (i === 1 && (name[2] === '..' || name[0] === '..')) { //End of the line. Keep at least one non-dot //path segment at the front so it can be mapped //correctly to disk. Otherwise, there is likely //no path mapping for a path starting with '..'. //This can still fail, but catches the most reasonable //uses of .. break; } else if (i > 0) { name.splice(i - 1, 2); i -= 2; } } } //end trimDots name = name.join("/"); } else if (name.indexOf('./') === 0) { // No baseName, so this is ID is resolved relative // to baseUrl, pull off the leading dot. name = name.substring(2); } } //Apply map config if available. if ((baseParts || starMap) && map) { nameParts = name.split('/'); for (i = nameParts.length; i > 0; i -= 1) { nameSegment = nameParts.slice(0, i).join("/"); if (baseParts) { //Find the longest baseName segment match in the config. //So, do joins on the biggest to smallest lengths of baseParts. for (j = baseParts.length; j > 0; j -= 1) { mapValue = map[baseParts.slice(0, j).join('/')]; //baseName segment has config, find if it has one for //this name. if (mapValue) { mapValue = mapValue[nameSegment]; if (mapValue) { //Match, update name to the new value. foundMap = mapValue; foundI = i; break; } } } } if (foundMap) { break; } //Check for a star map match, but just hold on to it, //if there is a shorter segment match later in a matching //config, then favor over this star map. if (!foundStarMap && starMap && starMap[nameSegment]) { foundStarMap = starMap[nameSegment]; starI = i; } } if (!foundMap && foundStarMap) { foundMap = foundStarMap; foundI = starI; } if (foundMap) { nameParts.splice(0, foundI, foundMap); name = nameParts.join('/'); } } return name; } function makeRequire(relName, forceSync) { return function () { //A version of a require function that passes a moduleName //value for items that may need to //look up paths relative to the moduleName var args = aps.call(arguments, 0); //If first arg is not require('string'), and there is only //one arg, it is the array form without a callback. Insert //a null so that the following concat is correct. if (typeof args[0] !== 'string' && args.length === 1) { args.push(null); } return req.apply(undef, args.concat([relName, forceSync])); }; } function makeNormalize(relName) { return function (name) { return normalize(name, relName); }; } function makeLoad(depName) { return function (value) { defined[depName] = value; }; } function callDep(name) { if (hasProp(waiting, name)) { var args = waiting[name]; delete waiting[name]; defining[name] = true; main.apply(undef, args); } if (!hasProp(defined, name) && !hasProp(defining, name)) { throw new Error('No ' + name); } return defined[name]; } //Turns a plugin!resource to [plugin, resource] //with the plugin being undefined if the name //did not have a plugin prefix. function splitPrefix(name) { var prefix, index = name ? name.indexOf('!') : -1; if (index > -1) { prefix = name.substring(0, index); name = name.substring(index + 1, name.length); } return [prefix, name]; } /** * Makes a name map, normalizing the name, and using a plugin * for normalization if necessary. Grabs a ref to plugin * too, as an optimization. */ makeMap = function (name, relName) { var plugin, parts = splitPrefix(name), prefix = parts[0]; name = parts[1]; if (prefix) { prefix = normalize(prefix, relName); plugin = callDep(prefix); } //Normalize according if (prefix) { if (plugin && plugin.normalize) { name = plugin.normalize(name, makeNormalize(relName)); } else { name = normalize(name, relName); } } else { name = normalize(name, relName); parts = splitPrefix(name); prefix = parts[0]; name = parts[1]; if (prefix) { plugin = callDep(prefix); } } //Using ridiculous property names for space reasons return { f: prefix ? prefix + '!' + name : name, //fullName n: name, pr: prefix, p: plugin }; }; function makeConfig(name) { return function () { return (config && config.config && config.config[name]) || {}; }; } handlers = { require: function (name) { return makeRequire(name); }, exports: function (name) { var e = defined[name]; if (typeof e !== 'undefined') { return e; } else { return (defined[name] = {}); } }, module: function (name) { return { id: name, uri: '', exports: defined[name], config: makeConfig(name) }; } }; main = function (name, deps, callback, relName) { var cjsModule, depName, ret, map, i, args = [], callbackType = typeof callback, usingExports; //Use name if no relName relName = relName || name; //Call the callback to define the module, if necessary. if (callbackType === 'undefined' || callbackType === 'function') { //Pull out the defined dependencies and pass the ordered //values to the callback. //Default to [require, exports, module] if no deps deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps; for (i = 0; i < deps.length; i += 1) { map = makeMap(deps[i], relName); depName = map.f; //Fast path CommonJS standard dependencies. if (depName === "require") { args[i] = handlers.require(name); } else if (depName === "exports") { //CommonJS module spec 1.1 args[i] = handlers.exports(name); usingExports = true; } else if (depName === "module") { //CommonJS module spec 1.1 cjsModule = args[i] = handlers.module(name); } else if (hasProp(defined, depName) || hasProp(waiting, depName) || hasProp(defining, depName)) { args[i] = callDep(depName); } else if (map.p) { map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {}); args[i] = defined[depName]; } else { throw new Error(name + ' missing ' + depName); } } ret = callback ? callback.apply(defined[name], args) : undefined; if (name) { //If setting exports via "module" is in play, //favor that over return value and exports. After that, //favor a non-undefined return value over exports use. if (cjsModule && cjsModule.exports !== undef && cjsModule.exports !== defined[name]) { defined[name] = cjsModule.exports; } else if (ret !== undef || !usingExports) { //Use the return value from the function. defined[name] = ret; } } } else if (name) { //May just be an object definition for the module. Only //worry about defining if have a module name. defined[name] = callback; } }; requirejs = require = req = function (deps, callback, relName, forceSync, alt) { if (typeof deps === "string") { if (handlers[deps]) { //callback in this case is really relName return handlers[deps](callback); } //Just return the module wanted. In this scenario, the //deps arg is the module name, and second arg (if passed) //is just the relName. //Normalize module name, if it contains . or .. return callDep(makeMap(deps, callback).f); } else if (!deps.splice) { //deps is a config object, not an array. config = deps; if (config.deps) { req(config.deps, config.callback); } if (!callback) { return; } if (callback.splice) { //callback is an array, which means it is a dependency list. //Adjust args if there are dependencies deps = callback; callback = relName; relName = null; } else { deps = undef; } } //Support require(['a']) callback = callback || function () {}; //If relName is a function, it is an errback handler, //so remove it. if (typeof relName === 'function') { relName = forceSync; forceSync = alt; } //Simulate async callback; if (forceSync) { main(undef, deps, callback, relName); } else { //Using a non-zero value because of concern for what old browsers //do, and latest browsers "upgrade" to 4 if lower value is used: //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout: //If want a value immediately, use require('id') instead -- something //that works in almond on the global level, but not guaranteed and //unlikely to work in other AMD implementations. setTimeout(function () { main(undef, deps, callback, relName); }, 4); } return req; }; /** * Just drops the config on the floor, but returns req in case * the config return value is used. */ req.config = function (cfg) { return req(cfg); }; /** * Expose module registry for debugging and tooling */ requirejs._defined = defined; define = function (name, deps, callback) { //This module may not have dependencies if (!deps.splice) { //deps is not an array, so probably means //an object literal or factory function for //the value. Adjust args. callback = deps; deps = []; } if (!hasProp(defined, name) && !hasProp(waiting, name)) { waiting[name] = [name, deps, callback]; } }; define.amd = { jQuery: true }; }()); define("../../vendor/almond/almond", function(){}); /** * @module core/api_error */ define('core/api_error',["require", "exports"], function(require, exports) { /** * Standard libc error codes. Add more to this enum and ErrorStrings as they are * needed. * @url http://www.gnu.org/software/libc/manual/html_node/Error-Codes.html */ (function (ErrorCode) { ErrorCode[ErrorCode["EPERM"] = 0] = "EPERM"; ErrorCode[ErrorCode["ENOENT"] = 1] = "ENOENT"; ErrorCode[ErrorCode["EIO"] = 2] = "EIO"; ErrorCode[ErrorCode["EBADF"] = 3] = "EBADF"; ErrorCode[ErrorCode["EACCES"] = 4] = "EACCES"; ErrorCode[ErrorCode["EBUSY"] = 5] = "EBUSY"; ErrorCode[ErrorCode["EEXIST"] = 6] = "EEXIST"; ErrorCode[ErrorCode["ENOTDIR"] = 7] = "ENOTDIR"; ErrorCode[ErrorCode["EISDIR"] = 8] = "EISDIR"; ErrorCode[ErrorCode["EINVAL"] = 9] = "EINVAL"; ErrorCode[ErrorCode["EFBIG"] = 10] = "EFBIG"; ErrorCode[ErrorCode["ENOSPC"] = 11] = "ENOSPC"; ErrorCode[ErrorCode["EROFS"] = 12] = "EROFS"; ErrorCode[ErrorCode["ENOTEMPTY"] = 13] = "ENOTEMPTY"; ErrorCode[ErrorCode["ENOTSUP"] = 14] = "ENOTSUP"; })(exports.ErrorCode || (exports.ErrorCode = {})); var ErrorCode = exports.ErrorCode; /** * Strings associated with each error code. */ var ErrorStrings = {}; ErrorStrings[0 /* EPERM */] = 'Operation not permitted.'; ErrorStrings[1 /* ENOENT */] = 'No such file or directory.'; ErrorStrings[2 /* EIO */] = 'Input/output error.'; ErrorStrings[3 /* EBADF */] = 'Bad file descriptor.'; ErrorStrings[4 /* EACCES */] = 'Permission denied.'; ErrorStrings[5 /* EBUSY */] = 'Resource busy or locked.'; ErrorStrings[6 /* EEXIST */] = 'File exists.'; ErrorStrings[7 /* ENOTDIR */] = 'File is not a directory.'; ErrorStrings[8 /* EISDIR */] = 'File is a directory.'; ErrorStrings[9 /* EINVAL */] = 'Invalid argument.'; ErrorStrings[10 /* EFBIG */] = 'File is too big.'; ErrorStrings[11 /* ENOSPC */] = 'No space left on disk.'; ErrorStrings[12 /* EROFS */] = 'Cannot modify a read-only file system.'; ErrorStrings[13 /* ENOTEMPTY */] = 'Directory is not empty.'; ErrorStrings[14 /* ENOTSUP */] = 'Operation is not supported.'; /** * Represents a BrowserFS error. Passed back to applications after a failed * call to the BrowserFS API. */ var ApiError = (function () { /** * Represents a BrowserFS error. Passed back to applications after a failed * call to the BrowserFS API. * * Error codes mirror those returned by regular Unix file operations, which is * what Node returns. * @constructor ApiError * @param type The type of the error. * @param [message] A descriptive error message. */ function ApiError(type, message) { this.type = type; this.code = ErrorCode[type]; if (message != null) { this.message = message; } else { this.message = ErrorStrings[type]; } } /** * @return A friendly error message. */ ApiError.prototype.toString = function () { return this.code + ": " + ErrorStrings[this.type] + " " + this.message; }; ApiError.FileError = function (code, p) { return new ApiError(code, p + ": " + ErrorStrings[code]); }; ApiError.ENOENT = function (path) { return this.FileError(1 /* ENOENT */, path); }; ApiError.EEXIST = function (path) { return this.FileError(6 /* EEXIST */, path); }; ApiError.EISDIR = function (path) { return this.FileError(8 /* EISDIR */, path); }; ApiError.ENOTDIR = function (path) { return this.FileError(7 /* ENOTDIR */, path); }; ApiError.EPERM = function (path) { return this.FileError(0 /* EPERM */, path); }; return ApiError; })(); exports.ApiError = ApiError; }); //# sourceMappingURL=api_error.js.map ; define('core/buffer_core',["require", "exports", './api_error'], function(require, exports, api_error) { var FLOAT_POS_INFINITY = Math.pow(2, 128); var FLOAT_NEG_INFINITY = -1 * FLOAT_POS_INFINITY; var FLOAT_POS_INFINITY_AS_INT = 0x7F800000; var FLOAT_NEG_INFINITY_AS_INT = -8388608; var FLOAT_NaN_AS_INT = 0x7fc00000; /** * Contains common definitions for most of the BufferCore classes. * Subclasses only need to implement write/readUInt8 for full functionality. */ var BufferCoreCommon = (function () { function BufferCoreCommon() { } BufferCoreCommon.prototype.getLength = function () { throw new api_error.ApiError(14 /* ENOTSUP */, 'BufferCore implementations should implement getLength.'); }; BufferCoreCommon.prototype.writeInt8 = function (i, data) { // Pack the sign bit as the highest bit. // Note that we keep the highest bit in the value byte as the sign bit if it // exists. this.writeUInt8(i, (data & 0xFF) | ((data & 0x80000000) >>> 24)); }; BufferCoreCommon.prototype.writeInt16LE = function (i, data) { this.writeUInt8(i, data & 0xFF); // Pack the sign bit as the highest bit. // Note that we keep the highest bit in the value byte as the sign bit if it // exists. this.writeUInt8(i + 1, ((data >>> 8) & 0xFF) | ((data & 0x80000000) >>> 24)); }; BufferCoreCommon.prototype.writeInt16BE = function (i, data) { this.writeUInt8(i + 1, data & 0xFF); // Pack the sign bit as the highest bit. // Note that we keep the highest bit in the value byte as the sign bit if it // exists. this.writeUInt8(i, ((data >>> 8) & 0xFF) | ((data & 0x80000000) >>> 24)); }; BufferCoreCommon.prototype.writeInt32LE = function (i, data) { this.writeUInt8(i, data & 0xFF); this.writeUInt8(i + 1, (data >>> 8) & 0xFF); this.writeUInt8(i + 2, (data >>> 16) & 0xFF); this.writeUInt8(i + 3, (data >>> 24) & 0xFF); }; BufferCoreCommon.prototype.writeInt32BE = function (i, data) { this.writeUInt8(i + 3, data & 0xFF); this.writeUInt8(i + 2, (data >>> 8) & 0xFF); this.writeUInt8(i + 1, (data >>> 16) & 0xFF); this.writeUInt8(i, (data >>> 24) & 0xFF); }; BufferCoreCommon.prototype.writeUInt8 = function (i, data) { throw new api_error.ApiError(14 /* ENOTSUP */, 'BufferCore implementations should implement writeUInt8.'); }; BufferCoreCommon.prototype.writeUInt16LE = function (i, data) { this.writeUInt8(i, data & 0xFF); this.writeUInt8(i + 1, (data >> 8) & 0xFF); }; BufferCoreCommon.prototype.writeUInt16BE = function (i, data) { this.writeUInt8(i + 1, data & 0xFF); this.writeUInt8(i, (data >> 8) & 0xFF); }; BufferCoreCommon.prototype.writeUInt32LE = function (i, data) { this.writeInt32LE(i, data | 0); }; BufferCoreCommon.prototype.writeUInt32BE = function (i, data) { this.writeInt32BE(i, data | 0); }; BufferCoreCommon.prototype.writeFloatLE = function (i, data) { this.writeInt32LE(i, this.float2intbits(data)); }; BufferCoreCommon.prototype.writeFloatBE = function (i, data) { this.writeInt32BE(i, this.float2intbits(data)); }; BufferCoreCommon.prototype.writeDoubleLE = function (i, data) { var doubleBits = this.double2longbits(data); this.writeInt32LE(i, doubleBits[0]); this.writeInt32LE(i + 4, doubleBits[1]); }; BufferCoreCommon.prototype.writeDoubleBE = function (i, data) { var doubleBits = this.double2longbits(data); this.writeInt32BE(i + 4, doubleBits[0]); this.writeInt32BE(i, doubleBits[1]); }; BufferCoreCommon.prototype.readInt8 = function (i) { var val = this.readUInt8(i); if (val & 0x80) { // Sign bit is set, so perform sign extension. return val | 0xFFFFFF80; } else { return val; } }; BufferCoreCommon.prototype.readInt16LE = function (i) { var val = this.readUInt16LE(i); if (val & 0x8000) { // Sign bit is set, so perform sign extension. return val | 0xFFFF8000; } else { return val; } }; BufferCoreCommon.prototype.readInt16BE = function (i) { var val = this.readUInt16BE(i); if (val & 0x8000) { // Sign bit is set, so perform sign extension. return val | 0xFFFF8000; } else { return val; } }; BufferCoreCommon.prototype.readInt32LE = function (i) { return this.readUInt32LE(i) | 0; }; BufferCoreCommon.prototype.readInt32BE = function (i) { return this.readUInt32BE(i) | 0; }; BufferCoreCommon.prototype.readUInt8 = function (i) { throw new api_error.ApiError(14 /* ENOTSUP */, 'BufferCore implementations should implement readUInt8.'); }; BufferCoreCommon.prototype.readUInt16LE = function (i) { return (this.readUInt8(i + 1) << 8) | this.readUInt8(i); }; BufferCoreCommon.prototype.readUInt16BE = function (i) { return (this.readUInt8(i) << 8) | this.readUInt8(i + 1); }; BufferCoreCommon.prototype.readUInt32LE = function (i) { return ((this.readUInt8(i + 3) << 24) | (this.readUInt8(i + 2) << 16) | (this.readUInt8(i + 1) << 8) | this.readUInt8(i)) >>> 0; }; BufferCoreCommon.prototype.readUInt32BE = function (i) { return ((this.readUInt8(i) << 24) | (this.readUInt8(i + 1) << 16) | (this.readUInt8(i + 2) << 8) | this.readUInt8(i + 3)) >>> 0; }; BufferCoreCommon.prototype.readFloatLE = function (i) { return this.intbits2float(this.readInt32LE(i)); }; BufferCoreCommon.prototype.readFloatBE = function (i) { return this.intbits2float(this.readInt32BE(i)); }; BufferCoreCommon.prototype.readDoubleLE = function (i) { return this.longbits2double(this.readInt32LE(i + 4), this.readInt32LE(i)); }; BufferCoreCommon.prototype.readDoubleBE = function (i) { return this.longbits2double(this.readInt32BE(i), this.readInt32BE(i + 4)); }; BufferCoreCommon.prototype.copy = function (start, end) { throw new api_error.ApiError(14 /* ENOTSUP */, 'BufferCore implementations should implement copy.'); }; BufferCoreCommon.prototype.fill = function (value, start, end) { for (var i = start; i < end; i++) { this.writeUInt8(i, value); } }; BufferCoreCommon.prototype.float2intbits = function (f_val) { var exp, f_view, i_view, sig, sign; // Special cases! if (f_val === 0) { return 0; } // We map the infinities to JavaScript infinities. Map them back. if (f_val === Number.POSITIVE_INFINITY) { return FLOAT_POS_INFINITY_AS_INT; } if (f_val === Number.NEGATIVE_INFINITY) { return FLOAT_NEG_INFINITY_AS_INT; } // Convert JavaScript NaN to Float NaN value. if (isNaN(f_val)) { return FLOAT_NaN_AS_INT; } // We have more bits of precision than a float, so below we round to // the nearest significand. This appears to be what the x86 // Java does for normal floating point operations. sign = f_val < 0 ? 1 : 0; f_val = Math.abs(f_val); // Subnormal zone! // (−1)^signbits×2^−126×0.significandbits // Largest subnormal magnitude: // 0000 0000 0111 1111 1111 1111 1111 1111 // Smallest subnormal magnitude: // 0000 0000 0000 0000 0000 0000 0000 0001 if (f_val <= 1.1754942106924411e-38 && f_val >= 1.4012984643248170e-45) { exp = 0; sig = Math.round((f_val / Math.pow(2, -126)) * Math.pow(2, 23)); return (sign << 31) | (exp << 23) | sig; } else { // Regular FP numbers exp = Math.floor(Math.log(f_val) / Math.LN2); sig = Math.round((f_val / Math.pow(2, exp) - 1) * Math.pow(2, 23)); return (sign << 31) | ((exp + 127) << 23) | sig; } }; BufferCoreCommon.prototype.double2longbits = function (d_val) { var d_view, exp, high_bits, i_view, sig, sign; // Special cases if (d_val === 0) { return [0, 0]; } if (d_val === Number.POSITIVE_INFINITY) { // High bits: 0111 1111 1111 0000 0000 0000 0000 0000 // Low bits: 0000 0000 0000 0000 0000 0000 0000 0000 return [0, 2146435072]; } else if (d_val === Number.NEGATIVE_INFINITY) { // High bits: 1111 1111 1111 0000 0000 0000 0000 0000 // Low bits: 0000 0000 0000 0000 0000 0000 0000 0000 return [0, -1048576]; } else if (isNaN(d_val)) { // High bits: 0111 1111 1111 1000 0000 0000 0000 0000 // Low bits: 0000 0000 0000 0000 0000 0000 0000 0000 return [0, 2146959360]; } sign = d_val < 0 ? 1 << 31 : 0; d_val = Math.abs(d_val); // Check if it is a subnormal number. // (-1)s × 0.f × 2-1022 // Largest subnormal magnitude: // 0000 0000 0000 1111 1111 1111 1111 1111 // 1111 1111 1111 1111 1111 1111 1111 1111 // Smallest subnormal magnitude: // 0000 0000 0000 0000 0000 0000 0000 0000 // 0000 0000 0000 0000 0000 0000 0000 0001 if (d_val <= 2.2250738585072010e-308 && d_val >= 5.0000000000000000e-324) { exp = 0; sig = (d_val / Math.pow(2, -1022)) * Math.pow(2, 52); } else { exp = Math.floor(Math.log(d_val) / Math.LN2); // If d_val is close to a power of two, there's a chance that exp // will be 1 greater than it should due to loss of accuracy in the // log result. if (d_val < Math.pow(2, exp)) { exp = exp - 1; } sig = (d_val / Math.pow(2, exp) - 1) * Math.pow(2, 52); exp = (exp + 1023) << 20; } // Simulate >> 32 high_bits = ((sig * Math.pow(2, -32)) | 0) | sign | exp; return [sig & 0xFFFF, high_bits]; }; BufferCoreCommon.prototype.intbits2float = function (int32) { // Map +/- infinity to JavaScript equivalents if (int32 === FLOAT_POS_INFINITY_AS_INT) { return Number.POSITIVE_INFINITY; } else if (int32 === FLOAT_NEG_INFINITY_AS_INT) { return Number.NEGATIVE_INFINITY; } var sign = (int32 & 0x80000000) >>> 31; var exponent = (int32 & 0x7F800000) >>> 23; var significand = int32 & 0x007FFFFF; var value; if (exponent === 0) { value = Math.pow(-1, sign) * significand * Math.pow(2, -149); } else { value = Math.pow(-1, sign) * (1 + significand * Math.pow(2, -23)) * Math.pow(2, exponent - 127); } // NaN check if (value < FLOAT_NEG_INFINITY || value > FLOAT_POS_INFINITY) { value = NaN; } return value; }; BufferCoreCommon.prototype.longbits2double = function (uint32_a, uint32_b) { var sign = (uint32_a & 0x80000000) >>> 31; var exponent = (uint32_a & 0x7FF00000) >>> 20; var significand = ((uint32_a & 0x000FFFFF) * Math.pow(2, 32)) + uint32_b; // Special values! if (exponent === 0 && significand === 0) { return 0; } if (exponent === 2047) { if (significand === 0) { if (sign === 1) { return Number.NEGATIVE_INFINITY; } return Number.POSITIVE_INFINITY; } else { return NaN; } } if (exponent === 0) return Math.pow(-1, sign) * significand * Math.pow(2, -1074); return Math.pow(-1, sign) * (1 + significand * Math.pow(2, -52)) * Math.pow(2, exponent - 1023); }; return BufferCoreCommon; })(); exports.BufferCoreCommon = BufferCoreCommon; }); //# sourceMappingURL=buffer_core.js.map ; var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; define('core/buffer_core_array',["require", "exports", './buffer_core'], function(require, exports, buffer_core) { // Used to clear segments of an array index. var clearMasks = [0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 0x00FFFFFF]; /** * Implementation of BufferCore that is backed by an array of 32-bit ints. * Data is stored little endian. * Example: Bytes 0 through 3 are present in the first int: * BYTE 3 BYTE 2 BYTE 1 BYTE 0 * 0000 0000 | 0000 0000 | 0000 0000 | 0000 0000 */ var BufferCoreArray = (function (_super) { __extends(BufferCoreArray, _super); function BufferCoreArray(length) { _super.call(this); this.length = length; this.buff = new Array(Math.ceil(length / 4)); // Zero-fill the array. var bufflen = this.buff.length; for (var i = 0; i < bufflen; i++) { this.buff[i] = 0; } } BufferCoreArray.isAvailable = function () { return true; }; BufferCoreArray.prototype.getLength = function () { return this.length; }; BufferCoreArray.prototype.writeUInt8 = function (i, data) { data &= 0xFF; // Which int? (Equivalent to (i/4)|0) var arrIdx = i >> 2; // Which offset? (Equivalent to i - arrIdx*4) var intIdx = i & 3; this.buff[arrIdx] = this.buff[arrIdx] & clearMasks[intIdx]; this.buff[arrIdx] = this.buff[arrIdx] | (data << (intIdx << 3)); }; BufferCoreArray.prototype.readUInt8 = function (i) { // Which int? var arrIdx = i >> 2; // Which offset? var intIdx = i & 3; // Bring the data we want into the lowest 8 bits, and truncate. return (this.buff[arrIdx] >> (intIdx << 3)) & 0xFF; }; BufferCoreArray.prototype.copy = function (start, end) { // Stupid unoptimized copy. Later, we could do optimizations when aligned. var newBC = new BufferCoreArray(end - start); for (var i = start; i < end; i++) { newBC.writeUInt8(i - start, this.readUInt8(i)); } return newBC; }; return BufferCoreArray; })(buffer_core.BufferCoreCommon); exports.BufferCoreArray = BufferCoreArray; // Type-check the class. var _ = BufferCoreArray; }); //# sourceMappingURL=buffer_core_array.js.map ; var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; define('core/buffer_core_arraybuffer',["require", "exports", './buffer_core'], function(require, exports, buffer_core) { /** * Represents data using an ArrayBuffer. */ var BufferCoreArrayBuffer = (function (_super) { __extends(BufferCoreArrayBuffer, _super); function BufferCoreArrayBuffer(arg1) { _super.call(this); if (typeof arg1 === 'number') { this.buff = new DataView(new ArrayBuffer(arg1)); } else if (arg1 instanceof DataView) { this.buff = arg1; } else { this.buff = new DataView(arg1); } this.length = this.buff.byteLength; } BufferCoreArrayBuffer.isAvailable = function () { return typeof DataView !== 'undefined'; }; BufferCoreArrayBuffer.prototype.getLength = function () { return this.length; }; BufferCoreArrayBuffer.prototype.writeInt8 = function (i, data) { this.buff.setInt8(i, data); }; BufferCoreArrayBuffer.prototype.writeInt16LE = function (i, data) { this.buff.setInt16(i, data, true); }; BufferCoreArrayBuffer.prototype.writeInt16BE = function (i, data) { this.buff.setInt16(i, data, false); }; BufferCoreArrayBuffer.prototype.writeInt32LE = function (i, data) { this.buff.setInt32(i, data, true); }; BufferCoreArrayBuffer.prototype.writeInt32BE = function (i, data) { this.buff.setInt32(i, data, false); }; BufferCoreArrayBuffer.prototype.writeUInt8 = function (i, data) { this.buff.setUint8(i, data); }; BufferCoreArrayBuffer.prototype.writeUInt16LE = function (i, data) { this.buff.setUint16(i, data, true); }; BufferCoreArrayBuffer.prototype.writeUInt16BE = function (i, data) { this.buff.setUint16(i, data, false); }; BufferCoreArrayBuffer.prototype.writeUInt32LE = function (i, data) { this.buff.setUint32(i, data, true); }; BufferCoreArrayBuffer.prototype.writeUInt32BE = function (i, data) { this.buff.setUint32(i, data, false); }; BufferCoreArrayBuffer.prototype.writeFloatLE = function (i, data) { this.buff.setFloat32(i, data, true); }; BufferCoreArrayBuffer.prototype.writeFloatBE = function (i, data) { this.buff.setFloat32(i, data, false); }; BufferCoreArrayBuffer.prototype.writeDoubleLE = function (i, data) { this.buff.setFloat64(i, data, true); }; BufferCoreArrayBuffer.prototype.writeDoubleBE = function (i, data) { this.buff.setFloat64(i, data, false); }; BufferCoreArrayBuffer.prototype.readInt8 = function (i) { return this.buff.getInt8(i); }; BufferCoreArrayBuffer.prototype.readInt16LE = function (i) { return this.buff.getInt16(i, true); }; BufferCoreArrayBuffer.prototype.readInt16BE = function (i) { return this.buff.getInt16(i, false); }; BufferCoreArrayBuffer.prototype.readInt32LE = function (i) { return this.buff.getInt32(i, true); }; BufferCoreArrayBuffer.prototype.readInt32BE = function (i) { return this.buff.getInt32(i, false); }; BufferCoreArrayBuffer.prototype.readUInt8 = function (i) { return this.buff.getUint8(i); }; BufferCoreArrayBuffer.prototype.readUInt16LE = function (i) { return this.buff.getUint16(i, true); }; BufferCoreArrayBuffer.prototype.readUInt16BE = function (i) { return this.buff.getUint16(i, false); }; BufferCoreArrayBuffer.prototype.readUInt32LE = function (i) { return this.buff.getUint32(i, true); }; BufferCoreArrayBuffer.prototype.readUInt32BE = function (i) { return this.buff.getUint32(i, false); }; BufferCoreArrayBuffer.prototype.readFloatLE = function (i) { return this.buff.getFloat32(i, true); }; BufferCoreArrayBuffer.prototype.readFloatBE = function (i) { return this.buff.getFloat32(i, false); }; BufferCoreArrayBuffer.prototype.readDoubleLE = function (i) { return this.buff.getFloat64(i, true); }; BufferCoreArrayBuffer.prototype.readDoubleBE = function (i) { return this.buff.getFloat64(i, false); }; BufferCoreArrayBuffer.prototype.copy = function (start, end) { var aBuff = this.buff.buffer; var newBuff; // Some ArrayBuffer implementations (IE10) do not have 'slice'. // XXX: Type hacks - the typings don't have slice either. if (ArrayBuffer.prototype.slice) { // ArrayBuffer.slice is copying; exactly what we want. newBuff = aBuff.slice(start, end); } else { var len = end - start; newBuff = new ArrayBuffer(len); // Copy the old contents in. var newUintArray = new Uint8Array(newBuff); var oldUintArray = new Uint8Array(aBuff); newUintArray.set(oldUintArray.subarray(start, end)); } return new BufferCoreArrayBuffer(newBuff); }; BufferCoreArrayBuffer.prototype.fill = function (value, start, end) { // Value must be a byte wide. value = value & 0xFF; var i; var len = end - start; var intBytes = (((len) / 4) | 0) * 4; // Optimization: Write 4 bytes at a time. // TODO: Could we copy 8 bytes at a time using Float64, or could we // lose precision? var intVal = (value << 24) | (value << 16) | (value << 8) | value; for (i = 0; i < intBytes; i += 4) { this.writeInt32LE(i + start, intVal); } for (i = intBytes; i < len; i++) { this.writeUInt8(i + start, value); } }; /** * Custom method for this buffer core. Get the backing object. */ BufferCoreArrayBuffer.prototype.getDataView = function () { return this.buff; }; return BufferCoreArrayBuffer; })(buffer_core.BufferCoreCommon); exports.BufferCoreArrayBuffer = BufferCoreArrayBuffer; // Type-check the class. var _ = BufferCoreArrayBuffer; }); //# sourceMappingURL=buffer_core_arraybuffer.js.map ; var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; define('core/buffer_core_imagedata',["require", "exports", './buffer_core'], function(require, exports, buffer_core) { /** * Implementation of BufferCore that is backed by an ImageData object. * Useful in browsers with HTML5 canvas support, but no TypedArray support * (IE9). */ var BufferCoreImageData = (function (_super) { __extends(BufferCoreImageData, _super); function BufferCoreImageData(length) { _super.call(this); this.length = length; this.buff = BufferCoreImageData.getCanvasPixelArray(length); } /** * Constructs a CanvasPixelArray that represents the given amount of bytes. */ BufferCoreImageData.getCanvasPixelArray = function (bytes) { var ctx = BufferCoreImageData.imageDataFactory; // Lazily initialize, otherwise every browser (even those that will never // use this code) will create a canvas on script load. if (ctx === undefined) { BufferCoreImageData.imageDataFactory = ctx = document.createElement('canvas').getContext('2d'); } // You cannot create image data with size 0, so up it to size 1. if (bytes === 0) bytes = 1; return ctx.createImageData(Math.ceil(bytes / 4), 1).data; }; BufferCoreImageData.isAvailable = function () { // Modern browsers have removed this deprecated API, so it is not always around. return typeof CanvasPixelArray !== 'undefined'; }; BufferCoreImageData.prototype.getLength = function () { return this.length; }; BufferCoreImageData.prototype.writeUInt8 = function (i, data) { this.buff[i] = data; }; BufferCoreImageData.prototype.readUInt8 = function (i) { return this.buff[i]; }; BufferCoreImageData.prototype.copy = function (start, end) { // AFAIK, there's no efficient way to clone ImageData. var newBC = new BufferCoreImageData(end - start); for (var i = start; i < end; i++) { newBC.writeUInt8(i - start, this.buff[i]); } return newBC; }; return BufferCoreImageData; })(buffer_core.BufferCoreCommon); exports.BufferCoreImageData = BufferCoreImageData; // Type-check the class. var _ = BufferCoreImageData; }); //# sourceMappingURL=buffer_core_imagedata.js.map ; define('core/string_util',["require", "exports"], function(require, exports) { /** * Find the 'utility' object for the given string encoding. Throws an exception * if the encoding is invalid. * @param [String] encoding a string encoding * @return [BrowserFS.StringUtil.*] The StringUtil object for the given encoding */ function FindUtil(encoding) { encoding = (function () { switch (typeof encoding) { case 'object': return "" + encoding; case 'string': return encoding; default: throw new Error('Invalid encoding argument specified'); } })(); encoding = encoding.toLowerCase(); switch (encoding) { case 'utf8': case 'utf-8': return UTF8; case 'ascii': return ASCII; case 'binary': return BINARY; case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return UCS2; case 'hex': return HEX; case 'base64': return BASE64; case 'binary_string': return BINSTR; case 'binary_string_ie': return BINSTRIE; case 'extended_ascii': return ExtendedASCII; default: throw new Error("Unknown encoding: " + encoding); } } exports.FindUtil = FindUtil; /** * String utility functions for UTF-8. Note that some UTF-8 strings *cannot* be * expressed in terms of JavaScript UTF-16 strings. * @see http://en.wikipedia.org/wiki/UTF-8 */ var UTF8 = (function () { function UTF8() { } UTF8.str2byte = function (str, buf) { var length = buf.length; var i = 0; var j = 0; var maxJ = length; var rv = []; var numChars = 0; while (i < str.length && j < maxJ) { var code = str.charCodeAt(i++); var next = str.charCodeAt(i); if (0xD800 <= code && code <= 0xDBFF && 0xDC00 <= next && next <= 0xDFFF) { // 4 bytes: Surrogate pairs! UTF-16 fun time. if (j + 3 >= maxJ) { break; } else { numChars++; } // First pair: 10 bits of data, with an implicitly set 11th bit // Second pair: 10 bits of data var codePoint = (((code & 0x3FF) | 0x400) << 10) | (next & 0x3FF); // Highest 3 bits in first byte buf.writeUInt8((codePoint >> 18) | 0xF0, j++); // Rest are all 6 bits buf.writeUInt8(((codePoint >> 12) & 0x3F) | 0x80, j++); buf.writeUInt8(((codePoint >> 6) & 0x3F) | 0x80, j++); buf.writeUInt8((codePoint & 0x3F) | 0x80, j++); i++; } else if (code < 0x80) { // One byte buf.writeUInt8(code, j++); numChars++; } else if (code < 0x800) { // Two bytes if (j + 1 >= maxJ) { break; } else { numChars++; } // Highest 5 bits in first byte buf.writeUInt8((code >> 6) | 0xC0, j++); // Lower 6 bits in second byte buf.writeUInt8((code & 0x3F) | 0x80, j++); } else if (code < 0x10000) { // Three bytes if (j + 2 >= maxJ) { break; } else { numChars++; } // Highest 4 bits in first byte buf.writeUInt8((code >> 12) | 0xE0, j++); // Middle 6 bits in second byte buf.writeUInt8(((code >> 6) & 0x3F) | 0x80, j++); // Lowest 6 bits in third byte buf.writeUInt8((code & 0x3F) | 0x80, j++); } } return j; }; UTF8.byte2str = function (buff) { var chars = []; var i = 0; while (i < buff.length) { var code = buff.readUInt8(i++); if (code < 0x80) { chars.push(String.fromCharCode(code)); } else if (code < 0xC0) { throw new Error('Found incomplete part of character in string.'); } else if (code < 0xE0) { // 2 bytes: 5 and 6 bits chars.push(String.fromCharCode(((code & 0x1F) << 6) | (buff.readUInt8(i++) & 0x3F))); } else if (code < 0xF0) { // 3 bytes: 4, 6, and 6 bits chars.push(String.fromCharCode(((code & 0xF) << 12) | ((buff.readUInt8(i++) & 0x3F) << 6) | (buff.readUInt8(i++) & 0x3F))); } else if (code < 0xF8) { // 4 bytes: 3, 6, 6, 6 bits; surrogate pairs time! // First 11 bits; remove 11th bit as per UTF-16 standard var byte3 = buff.readUInt8(i + 2); chars.push(String.fromCharCode(((((code & 0x7) << 8) | ((buff.readUInt8(i++) & 0x3F) << 2) | ((buff.readUInt8(i++) & 0x3F) >> 4)) & 0x3FF) | 0xD800)); // Final 10 bits chars.push(String.fromCharCode((((byte3 & 0xF) << 6) | (buff.readUInt8(i++) & 0x3F)) | 0xDC00)); } else { throw new Error('Unable to represent UTF-8 string as UTF-16 JavaScript string.'); } } return chars.join(''); }; UTF8.byteLength = function (str) { // Matches only the 10.. bytes that are non-initial characters in a // multi-byte sequence. // @todo This may be slower than iterating through the string in some cases. var m = encodeURIComponent(str).match(/%[89ABab]/g); return str.length + (m ? m.length : 0); }; return UTF8; })(); exports.UTF8 = UTF8; /** * String utility functions for 8-bit ASCII. Like Node, we mask the high bits of * characters in JavaScript UTF-16 strings. * @see http://en.wikipedia.org/wiki/ASCII */ var ASCII = (function () { function ASCII() { } ASCII.str2byte = function (str, buf) { var length = str.length > buf.length ? buf.length : str.length; for (var i = 0; i < length; i++) { buf.writeUInt8(str.charCodeAt(i) % 256, i); } return length; }; ASCII.byte2str = function (buff) { var chars = new Array(buff.length); for (var i = 0; i < buff.length; i++) { chars[i] = String.fromCharCode(buff.readUInt8(i) & 0x7F); } return chars.join(''); }; ASCII.byteLength = function (str) { return str.length; }; return ASCII; })(); exports.ASCII = ASCII; /** * (Nonstandard) String utility function for 8-bit ASCII with the extended * character set. Unlike the ASCII above, we do not mask the high bits. * @see http://en.wikipedia.org/wiki/Extended_ASCII */ var ExtendedASCII = (function () { function ExtendedASCII() { } ExtendedASCII.str2byte = function (str, buf) { var length = str.length > buf.length ? buf.length : str.length; for (var i = 0; i < length; i++) { var charCode = str.charCodeAt(i); if (charCode > 0x7F) { // Check if extended ASCII. var charIdx = ExtendedASCII.extendedChars.indexOf(str.charAt(i)); if (charIdx > -1) { charCode = charIdx + 0x80; } // Otherwise, keep it as-is. } buf.writeUInt8(charCode, i); } return length; }; ExtendedASCII.byte2str = function (buff) { var chars = new Array(buff.length); for (var i = 0; i < buff.length; i++) { var charCode = buff.readUInt8(i); if (charCode > 0x7F) { chars[i] = ExtendedASCII.extendedChars[charCode - 128]; } else { chars[i] = String.fromCharCode(charCode); } } return chars.join(''); }; ExtendedASCII.byteLength = function (str) { return str.length; }; ExtendedASCII.extendedChars = [ '\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB', '\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9', '\u00FF', '\u00D6', '\u00DC', '\u00F8', '\u00A3', '\u00D8', '\u00D7', '\u0192', '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1', '\u00AA', '\u00BA', '\u00BF', '\u00AE', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', '_', '_', '_', '\u00A6', '\u00A6', '\u00C1', '\u00C2', '\u00C0', '\u00A9', '\u00A6', '\u00A6', '+', '+', '\u00A2', '\u00A5', '+', '+', '-', '-', '+', '-', '+', '\u00E3', '\u00C3', '+', '+', '-', '-', '\u00A6', '-', '+', '\u00A4', '\u00F0', '\u00D0', '\u00CA', '\u00CB', '\u00C8', 'i', '\u00CD', '\u00CE', '\u00CF', '+', '+', '_', '_', '\u00A6', '\u00CC', '_', '\u00D3', '\u00DF', '\u00D4', '\u00D2', '\u00F5', '\u00D5', '\u00B5', '\u00FE', '\u00DE', '\u00DA', '\u00DB', '\u00D9', '\u00FD', '\u00DD', '\u00AF', '\u00B4', '\u00AD', '\u00B1', '_', '\u00BE', '\u00B6', '\u00A7', '\u00F7', '\u00B8', '\u00B0', '\u00A8', '\u00B7', '\u00B9', '\u00B3', '\u00B2', '_', ' ']; return ExtendedASCII; })(); exports.ExtendedASCII = ExtendedASCII; /** * String utility functions for Node's BINARY strings, which represent a single * byte per character. */ var BINARY = (function () { function BINARY() { } BINARY.str2byte = function (str, buf) { var length = str.length > buf.length ? buf.length : str.length; for (var i = 0; i < length; i++) { buf.writeUInt8(str.charCodeAt(i) & 0xFF, i); } return length; }; BINARY.byte2str = function (buff) { var chars = new Array(buff.length); for (var i = 0; i < buff.length; i++) { chars[i] = String.fromCharCode(buff.readUInt8(i) & 0xFF); } return chars.join(''); }; BINARY.byteLength = function (str) { return str.length; }; return BINARY; })(); exports.BINARY = BINARY; /** * Contains string utility functions for base-64 encoding. * * Adapted from the StackOverflow comment linked below. * @see http://stackoverflow.com/questions/246801/how-can-you-encode-to-base64-using-javascript#246813 * @see http://en.wikipedia.org/wiki/Base64 * @todo Bake in support for btoa() and atob() if available. */ var BASE64 = (function () { function BASE64() { } BASE64.byte2str = function (buff) { var output = ''; var i = 0; while (i < buff.length) { var chr1 = buff.readUInt8(i++); var chr2 = i < buff.length ? buff.readUInt8(i++) : NaN; var chr3 = i < buff.length ? buff.readUInt8(i++) : NaN; var enc1 = chr1 >> 2; var enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); var enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); var enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output = output + BASE64.num2b64[enc1] + BASE64.num2b64[enc2] + BASE64.num2b64[enc3] + BASE64.num2b64[enc4]; } return output; }; BASE64.str2byte = function (str, buf) { var length = buf.length; var output = ''; var i = 0; str = str.replace(/[^A-Za-z0-9\+\/\=\-\_]/g, ''); var j = 0; while (i < str.length) { var enc1 = BASE64.b642num[str.charAt(i++)]; var enc2 = BASE64.b642num[str.charAt(i++)]; var enc3 = BASE64.b642num[str.charAt(i++)]; var enc4 = BASE64.b642num[str.charAt(i++)]; var chr1 = (enc1 << 2) | (enc2 >> 4); var chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); var chr3 = ((enc3 & 3) << 6) | enc4; buf.writeUInt8(chr1, j++); if (j === length) { break; } if (enc3 !== 64) { output += buf.writeUInt8(chr2, j++); } if (j === length) { break; } if (enc4 !== 64) { output += buf.writeUInt8(chr3, j++); } if (j === length) { break; } } return j; }; BASE64.byteLength = function (str) { return Math.floor(((str.replace(/[^A-Za-z0-9\+\/\-\_]/g, '')).length * 6) / 8); }; BASE64.b64chars = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '=']; BASE64.num2b64 = (function () { var obj = new Array(BASE64.b64chars.length); for (var idx = 0; idx < BASE64.b64chars.length; idx++) { var i = BASE64.b64chars[idx]; obj[idx] = i; } return obj; })(); BASE64.b642num = (function () { var obj = {}; for (var idx = 0; idx < BASE64.b64chars.length; idx++) { var i = BASE64.b64chars[idx]; obj[i] = idx; } obj['-'] = 62; obj['_'] = 63; return obj; })(); return BASE64; })(); exports.BASE64 = BASE64; /** * String utility functions for the UCS-2 encoding. Note that our UCS-2 handling * is identical to our UTF-16 handling. * * Note: UCS-2 handling is identical to UTF-16. * @see http://en.wikipedia.org/wiki/UCS2 */ var UCS2 = (function () { function UCS2() { } UCS2.str2byte = function (str, buf) { var len = str.length; // Clip length to longest string of valid characters that can fit in the // byte range. if (len * 2 > buf.length) { len = buf.length % 2 === 1 ? (buf.length - 1) / 2 : buf.length / 2; } for (var i = 0; i < len; i++) { buf.writeUInt16LE(str.charCodeAt(i), i * 2); } return len * 2; }; UCS2.byte2str = function (buff) { if (buff.length % 2 !== 0) { throw new Error('Invalid UCS2 byte array.'); } var chars = new Array(buff.length / 2); for (var i = 0; i < buff.length; i += 2) { chars[i / 2] = String.fromCharCode(buff.readUInt8(i) | (buff.readUInt8(i + 1) << 8)); } return chars.join(''); }; UCS2.byteLength = function (str) { return str.length * 2; }; return UCS2; })(); exports.UCS2 = UCS2; /** * Contains string utility functions for hex encoding. * @see http://en.wikipedia.org/wiki/Hexadecimal */ var HEX = (function () { function HEX() { } HEX.str2byte = function (str, buf) { if (str.length % 2 === 1) { throw new Error('Invalid hex string'); } // Each character is 1 byte encoded as two hex characters; so 1 byte becomes // 2 bytes. var numBytes = str.length >> 1; if (numBytes > buf.length) { numBytes = buf.length; } for (var i = 0; i < numBytes; i++) { var char1 = this.hex2num[str.charAt(i << 1)]; var char2 = this.hex2num[str.charAt((i << 1) + 1)]; buf.writeUInt8((char1 << 4) | char2, i); } return numBytes; }; HEX.byte2str = function (buff) { var len = buff.length; var chars = new Array(len << 1); var j = 0; for (var i = 0; i < len; i++) { var hex2 = buff.readUInt8(i) & 0xF; var hex1 = buff.readUInt8(i) >> 4; chars[j++] = this.num2hex[hex1]; chars[j++] = this.num2hex[hex2]; } return chars.join(''); }; HEX.byteLength = function (str) { // Assuming a valid string. return str.length >> 1; }; HEX.HEXCHARS = '0123456789abcdef'; HEX.num2hex = (function () { var obj = new Array(HEX.HEXCHARS.length); for (var idx = 0; idx < HEX.HEXCHARS.length; idx++) { var i = HEX.HEXCHARS[idx]; obj[idx] = i; } return obj; })(); HEX.hex2num = (function () { var idx, i; var obj = {}; for (idx = 0; idx < HEX.HEXCHARS.length; idx++) { i = HEX.HEXCHARS[idx]; obj[i] = idx; } var capitals = 'ABCDEF'; for (idx = 0; idx < capitals.length; idx++) { i = capitals[idx]; obj[i] = idx + 10; } return obj; })(); return HEX; })(); exports.HEX = HEX; /** * Contains string utility functions for binary string encoding. This is where we * pack arbitrary binary data as a UTF-16 string. * * Each character in the string is two bytes. The first character in the string * is special: The first byte specifies if the binary data is of odd byte length. * If it is, then it is a 1 and the second byte is the first byte of data; if * not, it is a 0 and the second byte is 0. * * Everything is little endian. */ var BINSTR = (function () { function BINSTR() { } BINSTR.str2byte = function (str, buf) { // Special case: Empty string if (str.length === 0) { return 0; } var numBytes = BINSTR.byteLength(str); if (numBytes > buf.length) { numBytes = buf.length; } var j = 0; var startByte = 0; var endByte = startByte + numBytes; // Handle first character separately var firstChar = str.charCodeAt(j++); if (firstChar !== 0) { buf.writeUInt8(firstChar & 0xFF, 0); startByte = 1; } for (var i = startByte; i < endByte; i += 2) { var chr = str.charCodeAt(j++); if (endByte - i === 1) { // Write first byte of character buf.writeUInt8(chr >> 8, i); } if (endByte - i >= 2) { // Write both bytes in character buf.writeUInt16BE(chr, i); } } return numBytes; }; BINSTR.byte2str = function (buff) { var len = buff.length; // Special case: Empty string if (len === 0) { return ''; } var chars = new Array((len >> 1) + 1); var j = 0; for (var i = 0; i < chars.length; i++) { if (i === 0) { if (len % 2 === 1) { chars[i] = String.fromCharCode((1 << 8) | buff.readUInt8(j++)); } else { chars[i] = String.fromCharCode(0); } } else { chars[i] = String.fromCharCode((buff.readUInt8(j++) << 8) | buff.readUInt8(j++)); } } return chars.join(''); }; BINSTR.byteLength = function (str) { if (str.length === 0) { // Special case: Empty string. return 0; } var firstChar = str.charCodeAt(0); var bytelen = (str.length - 1) << 1; if (firstChar !== 0) { bytelen++; } return bytelen; }; return BINSTR; })(); exports.BINSTR = BINSTR; /** * IE/older FF version of binary string. One byte per character, offset by 0x20. */ var BINSTRIE = (function () { function BINSTRIE() { } BINSTRIE.str2byte = function (str, buf) { var length = str.length > buf.length ? buf.length : str.length; for (var i = 0; i < length; i++) { buf.writeUInt8(str.charCodeAt(i) - 0x20, i); } return length; }; BINSTRIE.byte2str = function (buff) { var chars = new Array(buff.length); for (var i = 0; i < buff.length; i++) { chars[i] = String.fromCharCode(buff.readUInt8(i) + 0x20); } return chars.join(''); }; BINSTRIE.byteLength = function (str) { return str.length; }; return BINSTRIE; })(); exports.BINSTRIE = BINSTRIE; }); //# sourceMappingURL=string_util.js.map ; define('core/buffer',["require", "exports", './buffer_core', './buffer_core_array', './buffer_core_arraybuffer', './buffer_core_imagedata', './string_util'], function(require, exports, buffer_core, buffer_core_array, buffer_core_arraybuffer, buffer_core_imagedata, string_util) { // BC implementations earlier in the array are preferred. var BufferCorePreferences = [ buffer_core_arraybuffer.BufferCoreArrayBuffer, buffer_core_imagedata.BufferCoreImageData, buffer_core_array.BufferCoreArray ]; var PreferredBufferCore = (function () { var i, bci; for (i = 0; i < BufferCorePreferences.length; i++) { bci = BufferCorePreferences[i]; if (bci.isAvailable()) return bci; } throw new Error("This browser does not support any available BufferCore implementations."); })(); /** * Emulates Node's Buffer API. Wraps a BufferCore object that is responsible * for actually writing/reading data from some data representation in memory. */ var Buffer = (function () { function Buffer(arg1, arg2, arg3) { if (typeof arg2 === "undefined") { arg2 = 'utf8'; } this.offset = 0; var i; // Node apparently allows you to construct buffers w/o 'new'. if (!(this instanceof Buffer)) { return new Buffer(arg1, arg2); } if (arg1 instanceof buffer_core.BufferCoreCommon) { // constructor (data: buffer_core.BufferCore, start?: number, end?: number) this.data = arg1; var start = typeof arg2 === 'number' ? arg2 : 0; var end = typeof arg3 === 'number' ? arg3 : this.data.getLength(); this.offset = start; this.length = end - start; } else if (typeof arg1 === 'number') { // constructor (size: number); if (arg1 !== (arg1 >>> 0)) { throw new TypeError('Buffer size must be a uint32.'); } this.length = arg1; this.data = new PreferredBufferCore(arg1); } else if (typeof DataView !== 'undefined' && arg1 instanceof DataView) { // constructor (data: DataView); this.data = new buffer_core_arraybuffer.BufferCoreArrayBuffer(arg1); this.length = arg1.byteLength; } else if (typeof ArrayBuffer !== 'undefined' && arg1 instanceof ArrayBuffer) { // constructor (data: ArrayBuffer); this.data = new buffer_core_arraybuffer.BufferCoreArrayBuffer(arg1); this.length = arg1.byteLength; } else if (arg1 instanceof Buffer) { // constructor (data: Buffer); var argBuff = arg1; this.data = new PreferredBufferCore(arg1.length); this.length = arg1.length; argBuff.copy(this); } else if (Array.isArray(arg1) || (arg1 != null && typeof arg1 === 'object' && typeof arg1[0] === 'number')) { // constructor (data: number[]); this.data = new PreferredBufferCore(arg1.length); for (i = 0; i < arg1.length; i++) { this.data.writeUInt8(i, arg1[i]); } this.length = arg1.length; } else if (typeof arg1 === 'string') { // constructor (data: string, encoding?: string); this.length = Buffer.byteLength(arg1, arg2); this.data = new PreferredBufferCore(this.length); this.write(arg1, 0, this.length, arg2); } else { throw new Error("Invalid argument to Buffer constructor: " + arg1); } } Buffer.prototype.getBufferCore = function () { return this.data; }; Buffer.prototype.getOffset = function () { return this.offset; }; /** * **NONSTANDARD**: Set the octet at index. Emulates NodeJS buffer's index * operation. Octet can be signed or unsigned. * @param {number} index - the index to set the value at * @param {number} value - the value to set at the given index */ Buffer.prototype.set = function (index, value) { // In Node, the following happens: // buffer[0] = -1; // buffer[0]; // 255 if (value < 0) { return this.writeInt8(value, index); } else { return this.writeUInt8(value, index); } }; /** * **NONSTANDARD**: Get the octet at index. * @param {number} index - index to fetch the value at * @return {number} the value at the given index */ Buffer.prototype.get = function (index) { return this.readUInt8(index); }; /** * Writes string to the buffer at offset using the given encoding. * If buffer did not contain enough space to fit the entire string, it will * write a partial amount of the string. * @param {string} str - Data to be written to buffer * @param {number} [offset=0] - Offset in the buffer to write to * @param {number} [length=this.length] - Number of bytes to write * @param {string} [encoding=utf8] - Character encoding * @return {number} Number of octets written. */ Buffer.prototype.write = function (str, offset, length, encoding) { if (typeof offset === "undefined") { offset = 0; } if (typeof length === "undefined") { length = this.length; } if (typeof encoding === "undefined") { encoding = 'utf8'; } // I hate Node's optional arguments. if (typeof offset === 'string') { // 'str' and 'encoding' specified encoding = "" + offset; offset = 0; length = this.length; } else if (typeof length === 'string') { // 'str', 'offset', and 'encoding' specified encoding = "" + length; length = this.length; } // Don't waste our time if the offset is beyond the buffer length if (offset >= this.length) { return 0; } var strUtil = string_util.FindUtil(encoding); // Are we trying to write past the buffer? length = length + offset > this.length ? this.length - offset : length; offset += this.offset; return strUtil.str2byte(str, offset === 0 && length === this.length ? this : new Buffer(this.data, offset, length + offset)); }; /** * Decodes a portion of the Buffer into a String. * @param {string} encoding - Character encoding to decode to * @param {number} [start=0] - Start position in the buffer * @param {number} [end=this.length] - Ending position in the buffer * @return {string} A string from buffer data encoded with encoding, beginning * at start, and ending at end. */ Buffer.prototype.toString = function (encoding, start, end) { if (typeof encoding === "undefined") { encoding = 'utf8'; } if (typeof start === "undefined") { start = 0; } if (typeof end === "undefined") { end = this.length; } if (!(start <= end)) { throw new Error("Invalid start/end positions: " + start + " - " + end); } if (start === end) { return ''; } if (end > this.length) { end = this.length; } var strUtil = string_util.FindUtil(encoding); // Get the string representation of the given slice. Create a new buffer // if need be. return strUtil.byte2str(start === 0 && end === this.length ? this : new Buffer(this.data, start + this.offset, end + this.offset)); }; /** * Returns a JSON-representation of the Buffer instance, which is identical to * the output for JSON Arrays. JSON.stringify implicitly calls this function * when stringifying a Buffer instance. * @return {object} An object that can be used for JSON stringification. */ Buffer.prototype.toJSON = function () { // Construct a byte array for the JSON 'data'. var len = this.length; var byteArr = new Array(len); for (var i = 0; i < len; i++) { byteArr[i] = this.readUInt8(i); } return { type: 'Buffer', data: byteArr }; }; /** * Does copy between buffers. The source and target regions can be overlapped. * All values passed that are undefined/NaN or are out of bounds are set equal * to their respective defaults. * @param {Buffer} target - Buffer to copy into * @param {number} [targetStart=0] - Index to start copying to in the targetBuffer * @param {number} [sourceStart=0] - Index in this buffer to start copying from * @param {number} [sourceEnd=this.length] - Index in this buffer stop copying at * @return {number} The number of bytes copied into the target buffer. */ Buffer.prototype.copy = function (target, targetStart, sourceStart, sourceEnd) { if (typeof targetStart === "undefined") { targetStart = 0; } if (typeof sourceStart === "undefined") { sourceStart = 0; } if (typeof sourceEnd === "undefined") { sourceEnd = this.length; } // The Node code is weird. It sets some out-of-bounds args to their defaults // and throws exceptions for others (sourceEnd). targetStart = targetStart < 0 ? 0 : targetStart; sourceStart = sourceStart < 0 ? 0 : sourceStart; // Need to sanity check all of the input. Node has really odd rules regarding // when to apply default arguments. I decided to copy Node's logic. if (sourceEnd < sourceStart) { throw new RangeError('sourceEnd < sourceStart'); } if (sourceEnd === sourceStart) { return 0; } if (targetStart >= target.length) { throw new RangeError('targetStart out of bounds'); } if (sourceStart >= this.length) { throw new RangeError('sourceStart out of bounds'); } if (sourceEnd > this.length) { throw new RangeError('sourceEnd out of bounds'); } var bytesCopied = Math.min(sourceEnd - sourceStart, target.length - targetStart, this.length - sourceStart); for (var i = 0; i < bytesCopied; i++) { target.writeUInt8(this.readUInt8(sourceStart + i), targetStart + i); } return bytesCopied; }; /** * Returns a slice of this buffer. * @param {number} [start=0] - Index to start slicing from * @param {number} [end=this.length] - Index to stop slicing at * @return {Buffer} A new buffer which references the same * memory as the old, but offset and cropped by the start (defaults to 0) and * end (defaults to buffer.length) indexes. Negative indexes start from the end * of the buffer. */ Buffer.prototype.slice = function (start, end) { if (typeof start === "undefined") { start = 0; } if (typeof end === "undefined") { end = this.length; } // Translate negative indices to positive ones. if (start < 0) { start += this.length; if (start < 0) { start = 0; } } if (end < 0) { end += this.length; if (end < 0) { end = 0; } } if (end > this.length) { end = this.length; } if (start > end) { start = end; } // Sanity check. if (start < 0 || end < 0 || start >= this.length || end > this.length) { throw new Error("Invalid slice indices."); } // Create a new buffer backed by the same BufferCore. return new Buffer(this.data, start + this.offset, end + this.offset); }; /** * [NONSTANDARD] A copy-based version of Buffer.slice. */ Buffer.prototype.sliceCopy = function (start, end) { if (typeof start === "undefined") { start = 0; } if (typeof end === "undefined") { end = this.length; } // Translate negative indices to positive ones. if (start < 0) { start += this.length; if (start < 0) { start = 0; } } if (end < 0) { end += this.length; if (end < 0) { end = 0; } } if (end > this.length) { end = this.length; } if (start > end) { start = end; } // Sanity check. if (start < 0 || end < 0 || start >= this.length || end > this.length) { throw new Error("Invalid slice indices."); } // Copy the BufferCore. return new Buffer(this.data.copy(start + this.offset, end + this.offset)); }; /** * Fills the buffer with the specified value. If the offset and end are not * given it will fill the entire buffer. * @param {(string|number)} value - The value to fill the buffer with * @param {number} [offset=0] * @param {number} [end=this.length] */ Buffer.prototype.fill = function (value, offset, end) { if (typeof offset === "undefined") { offset = 0; } if (typeof end === "undefined") { end = this.length; } var i; var valType = typeof value; switch (valType) { case "string": // Trim to a byte. value = value.charCodeAt(0) & 0xFF; break; case "number": break; default: throw new Error('Invalid argument to fill.'); } offset += this.offset; end += this.offset; this.data.fill(value, offset, end); }; Buffer.prototype.readUInt8 = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readUInt8(offset); }; Buffer.prototype.readUInt16LE = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readUInt16LE(offset); }; Buffer.prototype.readUInt16BE = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readUInt16BE(offset); }; Buffer.prototype.readUInt32LE = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readUInt32LE(offset); }; Buffer.prototype.readUInt32BE = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readUInt32BE(offset); }; Buffer.prototype.readInt8 = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readInt8(offset); }; Buffer.prototype.readInt16LE = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readInt16LE(offset); }; Buffer.prototype.readInt16BE = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readInt16BE(offset); }; Buffer.prototype.readInt32LE = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readInt32LE(offset); }; Buffer.prototype.readInt32BE = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readInt32BE(offset); }; Buffer.prototype.readFloatLE = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readFloatLE(offset); }; Buffer.prototype.readFloatBE = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readFloatBE(offset); }; Buffer.prototype.readDoubleLE = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readDoubleLE(offset); }; Buffer.prototype.readDoubleBE = function (offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; return this.data.readDoubleBE(offset); }; Buffer.prototype.writeUInt8 = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeUInt8(offset, value); }; Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeUInt16LE(offset, value); }; Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeUInt16BE(offset, value); }; Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeUInt32LE(offset, value); }; Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeUInt32BE(offset, value); }; Buffer.prototype.writeInt8 = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeInt8(offset, value); }; Buffer.prototype.writeInt16LE = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeInt16LE(offset, value); }; Buffer.prototype.writeInt16BE = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeInt16BE(offset, value); }; Buffer.prototype.writeInt32LE = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeInt32LE(offset, value); }; Buffer.prototype.writeInt32BE = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeInt32BE(offset, value); }; Buffer.prototype.writeFloatLE = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeFloatLE(offset, value); }; Buffer.prototype.writeFloatBE = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeFloatBE(offset, value); }; Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeDoubleLE(offset, value); }; Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) { if (typeof noAssert === "undefined") { noAssert = false; } offset += this.offset; this.data.writeDoubleBE(offset, value); }; ///**************************STATIC METHODS********************************/// /** * Checks if enc is a valid string encoding type. * @param {string} enc - Name of a string encoding type. * @return {boolean} Whether or not enc is a valid encoding type. */ Buffer.isEncoding = function (enc) { try { string_util.FindUtil(enc); } catch (e) { return false; } return true; }; /** * Tests if obj is a Buffer. * @param {object} obj - An arbitrary object * @return {boolean} True if this object is a Buffer. */ Buffer.isBuffer = function (obj) { return obj instanceof Buffer; }; /** * Gives the actual byte length of a string. This is not the same as * String.prototype.length since that returns the number of characters in a * string. * @param {string} str - The string to get the byte length of * @param {string} [encoding=utf8] - Character encoding of the string * @return {number} The number of bytes in the string */ Buffer.byteLength = function (str, encoding) { if (typeof encoding === "undefined") { encoding = 'utf8'; } var strUtil = string_util.FindUtil(encoding); return strUtil.byteLength(str); }; /** * Returns a buffer which is the result of concatenating all the buffers in the * list together. * If the list has no items, or if the totalLength is 0, then it returns a * zero-length buffer. * If the list has exactly one item, then the first item of the list is * returned. * If the list has more than one item, then a new Buffer is created. * If totalLength is not provided, it is read from the buffers in the list. * However, this adds an additional loop to the function, so it is faster to * provide the length explicitly. * @param {Buffer[]} list - List of Buffer objects to concat * @param {number} [totalLength] - Total length of the buffers when concatenated * @return {Buffer} */ Buffer.concat = function (list, totalLength) { var item; if (list.length === 0 || totalLength === 0) { return new Buffer(0); } else if (list.length === 1) { return list[0]; } else { if (totalLength == null) { // Calculate totalLength totalLength = 0; for (var i = 0; i < list.length; i++) { item = list[i]; totalLength += item.length; } } var buf = new Buffer(totalLength); var curPos = 0; for (var j = 0; j < list.length; j++) { item = list[j]; curPos += item.copy(buf, curPos); } return buf; } }; return Buffer; })(); exports.Buffer = Buffer; // Type-check the class. var _ = Buffer; }); //# sourceMappingURL=buffer.js.map ; define('core/file_flag',["require", "exports", './api_error'], function(require, exports, api_error) { /** * @class */ (function (ActionType) { // Indicates that the code should not do anything. ActionType[ActionType["NOP"] = 0] = "NOP"; // Indicates that the code should throw an exception. ActionType[ActionType["THROW_EXCEPTION"] = 1] = "THROW_EXCEPTION"; // Indicates that the code should truncate the file, but only if it is a file. ActionType[ActionType["TRUNCATE_FILE"] = 2] = "TRUNCATE_FILE"; // Indicates that the code should create the file. ActionType[ActionType["CREATE_FILE"] = 3] = "CREATE_FILE"; })(exports.ActionType || (exports.ActionType = {})); var ActionType = exports.ActionType; /** * Represents one of the following file flags. A convenience object. * * * `'r'` - Open file for reading. An exception occurs if the file does not exist. * * `'r+'` - Open file for reading and writing. An exception occurs if the file does not exist. * * `'rs'` - Open file for reading in synchronous mode. Instructs the filesystem to not cache writes. * * `'rs+'` - Open file for reading and writing, and opens the file in synchronous mode. * * `'w'` - Open file for writing. The file is created (if it does not exist) or truncated (if it exists). * * `'wx'` - Like 'w' but opens the file in exclusive mode. * * `'w+'` - Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists). * * `'wx+'` - Like 'w+' but opens the file in exclusive mode. * * `'a'` - Open file for appending. The file is created if it does not exist. * * `'ax'` - Like 'a' but opens the file in exclusive mode. * * `'a+'` - Open file for reading and appending. The file is created if it does not exist. * * `'ax+'` - Like 'a+' but opens the file in exclusive mode. * * Exclusive mode ensures that the file path is newly created. * @class */ var FileFlag = (function () { /** * This should never be called directly. * @param [String] modeStr The string representing the mode * @throw [BrowserFS.ApiError] when the mode string is invalid */ function FileFlag(flagStr) { this.flagStr = flagStr; if (FileFlag.validFlagStrs.indexOf(flagStr) < 0) { throw new api_error.ApiError(9 /* EINVAL */, "Invalid flag: " + flagStr); } } /** * Get an object representing the given file mode. * @param [String] modeStr The string representing the mode * @return [BrowserFS.FileMode] The FileMode object representing the mode * @throw [BrowserFS.ApiError] when the mode string is invalid */ FileFlag.getFileFlag = function (flagStr) { // Check cache first. if (FileFlag.flagCache.hasOwnProperty(flagStr)) { return FileFlag.flagCache[flagStr]; } return FileFlag.flagCache[flagStr] = new FileFlag(flagStr); }; /** * Returns true if the file is readable. * @return [Boolean] */ FileFlag.prototype.isReadable = function () { return this.flagStr.indexOf('r') !== -1 || this.flagStr.indexOf('+') !== -1; }; /** * Returns true if the file is writeable. * @return [Boolean] */ FileFlag.prototype.isWriteable = function () { return this.flagStr.indexOf('w') !== -1 || this.flagStr.indexOf('a') !== -1 || this.flagStr.indexOf('+') !== -1; }; /** * Returns true if the file mode should truncate. * @return [Boolean] */ FileFlag.prototype.isTruncating = function () { return this.flagStr.indexOf('w') !== -1; }; /** * Returns true if the file is appendable. * @return [Boolean] */ FileFlag.prototype.isAppendable = function () { return this.flagStr.indexOf('a') !== -1; }; /** * Returns true if the file is open in synchronous mode. * @return [Boolean] */ FileFlag.prototype.isSynchronous = function () { return this.flagStr.indexOf('s') !== -1; }; /** * Returns true if the file is open in exclusive mode. * @return [Boolean] */ FileFlag.prototype.isExclusive = function () { return this.flagStr.indexOf('x') !== -1; }; /** * Returns one of the static fields on this object that indicates the * appropriate response to the path existing. * @return [Number] */ FileFlag.prototype.pathExistsAction = function () { if (this.isExclusive()) { return 1 /* THROW_EXCEPTION */; } else if (this.isTruncating()) { return 2 /* TRUNCATE_FILE */; } else { return 0 /* NOP */; } }; /** * Returns one of the static fields on this object that indicates the * appropriate response to the path not existing. * @return [Number] */ FileFlag.prototype.pathNotExistsAction = function () { if ((this.isWriteable() || this.isAppendable()) && this.flagStr !== 'r+') { return 3 /* CREATE_FILE */; } else { return 1 /* THROW_EXCEPTION */; } }; FileFlag.flagCache = {}; FileFlag.validFlagStrs = ['r', 'r+', 'rs', 'rs+', 'w', 'wx', 'w+', 'wx+', 'a', 'ax', 'a+', 'ax+']; return FileFlag; })(); exports.FileFlag = FileFlag; }); //# sourceMappingURL=file_flag.js.map ; var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; define('core/node_eventemitter',["require", "exports", './buffer', './api_error'], function(require, exports, buffer, api_error) { var Buffer = buffer.Buffer; var ApiError = api_error.ApiError; var ErrorCode = api_error.ErrorCode; /** * Internal class. Represents a buffered event. */ var BufferedEvent = (function () { function BufferedEvent(data, encoding, cb) { this.data = data; this.encoding = encoding; this.cb = cb; this.size = typeof (data) !== 'string' ? data.length : Buffer.byteLength(data, encoding != null ? encoding : undefined); // If data is a buffer, we need to copy it. if (typeof (this.data) !== 'string') { this.data = this.data.sliceCopy(); } } BufferedEvent.prototype.getData = function (encoding) { if (encoding == null) { if (typeof (this.data) === 'string') { return new Buffer(this.data, this.encoding != null ? this.encoding : undefined); } else { return this.data; } } else { if (typeof (this.data) === 'string') { if (encoding === this.encoding) { return this.data; } else { return (new Buffer(this.data, this.encoding != null ? this.encoding : undefined)).toString(encoding); } } else { return this.data.toString(encoding); } } }; return BufferedEvent; })(); /** * Provides an abstract implementation of the EventEmitter interface. */ var AbstractEventEmitter = (function () { function AbstractEventEmitter() { this._listeners = {}; this.maxListeners = 10; } /** * Adds a listener for the particular event. */ AbstractEventEmitter.prototype.addListener = function (event, listener) { if (typeof (this._listeners[event]) === 'undefined') { this._listeners[event] = []; } if (this._listeners[event].push(listener) > this.maxListeners) { process.stdout.write("Warning: Event " + event + " has more than " + this.maxListeners + " listeners.\n"); } this.emit('newListener', event, listener); return this; }; /** * Adds a listener for the particular event. */ AbstractEventEmitter.prototype.on = function (event, listener) { return this.addListener(event, listener); }; /** * Adds a listener for the particular event that fires only once. */ AbstractEventEmitter.prototype.once = function (event, listener) { // Create a new callback that will only fire once. var fired = false, newListener = function () { this.removeListener(event, newListener); if (!fired) { fired = true; listener.apply(this, arguments); } }; return this.addListener(event, newListener); }; /** * Emits the 'removeListener' event for the specified listeners. */ AbstractEventEmitter.prototype._emitRemoveListener = function (event, listeners) { var i; // Only emit the event if someone is listening. if (this._listeners['removeListener'] && this._listeners['removeListener'].length > 0) { for (i = 0; i < listeners.length; i++) { this.emit('removeListener', event, listeners[i]); } } }; /** * Removes the particular listener for the given event. */ AbstractEventEmitter.prototype.removeListener = function (event, listener) { var listeners = this._listeners[event]; if (typeof (listeners) !== 'undefined') { // Remove listener, if present. var idx = listeners.indexOf(listener); if (idx > -1) { listeners.splice(idx, 1); } } this.emit('removeListener', event, listener); return this; }; /** * Removes all listeners, or those of the specified event. */ AbstractEventEmitter.prototype.removeAllListeners = function (event) { var removed, keys, i; if (typeof (event) !== 'undefined') { removed = this._listeners[event]; // Clear one event. this._listeners[event] = []; this._emitRemoveListener(event, removed); } else { // Clear all events. keys = Object.keys(this._listeners); for (i = 0; i < keys.length; i++) { this.removeAllListeners(keys[i]); } } return this; }; /** * EventEmitters print a warning when an event has greater than this specified * number of listeners. */ AbstractEventEmitter.prototype.setMaxListeners = function (n) { this.maxListeners = n; }; /** * Returns the listeners for the given event. */ AbstractEventEmitter.prototype.listeners = function (event) { if (typeof (this._listeners[event]) === 'undefined') { this._listeners[event] = []; } // Return a *copy* of our internal structure. return this._listeners[event].slice(0); }; /** * Emits the specified event to all listeners of the particular event. */ AbstractEventEmitter.prototype.emit = function (event) { var args = []; for (var _i = 0; _i < (arguments.length - 1); _i++) { args[_i] = arguments[_i + 1]; } var listeners = this._listeners[event], rv = false; if (typeof (listeners) !== 'undefined') { var i; for (i = 0; i < listeners.length; i++) { rv = true; listeners[i].apply(this, args); } } return rv; }; return AbstractEventEmitter; })(); exports.AbstractEventEmitter = AbstractEventEmitter; /** * Provides an abstract implementation of the WritableStream and ReadableStream * interfaces. * @todo: Check readable/writable status. */ var AbstractDuplexStream = (function (_super) { __extends(AbstractDuplexStream, _super); /** * Abstract stream implementation that can be configured to be readable and/or * writable. */ function AbstractDuplexStream(writable, readable) { _super.call(this); this.writable = writable; this.readable = readable; /** * How should the data output be encoded? 'null' means 'Buffer'. */ this.encoding = null; /** * Is this stream currently flowing (resumed) or non-flowing (paused)? */ this.flowing = false; /** * Event buffer. Simply queues up all write requests. */ this.buffer = []; /** * Once set, the stream is closed. Emitted once 'buffer' is empty. */ this.endEvent = null; /** * Has the stream ended? */ this.ended = false; /** * The last time we checked, was the buffer empty? * We emit 'readable' events when this transitions from 'true' -> 'false'. */ this.drained = true; } /** * Adds a listener for the particular event. * Implemented here so that we can capture data EventListeners, which trigger * us to 'resume'. */ AbstractDuplexStream.prototype.addListener = function (event, listener) { var rv = _super.prototype.addListener.call(this, event, listener), _this = this; if (event === 'data' && !this.flowing) { this.resume(); } else if (event === 'readable' && this.buffer.length > 0) { setTimeout(function () { _this.emit('readable'); }, 0); } return rv; }; /** * Helper function for 'write' and 'end' functions. */ AbstractDuplexStream.prototype._processArgs = function (data, arg2, arg3) { if (typeof (arg2) === 'string') { // data, encoding, cb? return new BufferedEvent(data, arg2, arg3); } else { // data, cb? return new BufferedEvent(data, null, arg2); } }; /** * If flowing, this will process pending events. */ AbstractDuplexStream.prototype._processEvents = function () { var drained = this.buffer.length === 0; if (this.drained !== drained) { if (this.drained) { // Went from drained to not drained. New stuff is available. // @todo: Is this event relevant in flowing mode? this.emit('readable'); } } if (this.flowing && this.buffer.length !== 0) { this.emit('data', this.read()); } // Are we drained? Check. this.drained = this.buffer.length === 0; }; /** * Emits the given buffered event. */ AbstractDuplexStream.prototype.emitEvent = function (type, event) { this.emit(type, event.getData(this.encoding)); if (event.cb) { event.cb(); } }; AbstractDuplexStream.prototype.write = function (data, arg2, arg3) { if (this.ended) { throw new ApiError(0 /* EPERM */, 'Cannot write to an ended stream.'); } var event = this._processArgs(data, arg2, arg3); this._push(event); return this.flowing; }; AbstractDuplexStream.prototype.end = function (data, arg2, arg3) { if (this.ended) { throw new ApiError(0 /* EPERM */, 'Stream is already closed.'); } var event = this._processArgs(data, arg2, arg3); this.ended = true; this.endEvent = event; this._processEvents(); }; /**** Readable Interface ****/ /** * Read a given number of bytes from the buffer. Should only be called in * non-flowing mode. * If we do not have `size` bytes available, return null. */ AbstractDuplexStream.prototype.read = function (size) { var events = [], eventsCbs = [], lastCb, eventsSize = 0, event, buff, trueSize, i = 0, sizeUnspecified = typeof (size) !== 'number'; // I do this so I do not need to specialize the loop below. if (sizeUnspecified) size = 4294967295; for (i = 0; i < this.buffer.length && eventsSize < size; i++) { event = this.buffer[i]; events.push(event.getData()); if (event.cb) { eventsCbs.push(event.cb); } eventsSize += event.size; lastCb = event.cb; } if (!sizeUnspecified && eventsSize < size) { // For some reason, the Node stream API specifies that we either return // 'size' bytes of data, or nothing at all. return null; } // Remove all of the events we are processing from the buffer. this.buffer = this.buffer.slice(events.length); // The 'true size' of the final event we're going to send out. trueSize = eventsSize > size ? size : eventsSize; // Concat at all of the events into one buffer. buff = Buffer.concat(events); if (eventsSize > size) { // If last event had a cb, ignore it -- we trigger it when that *entire* // write finishes. if (lastCb) eventsCbs.pop(); // Make a new event for the remaining data. this._push(new BufferedEvent(buff.slice(size), null, lastCb)); } // Schedule the relevant cbs to fire *after* we've returned these values. if (eventsCbs.length > 0) { setTimeout(function () { var i; for (i = 0; i < eventsCbs.length; i++) { eventsCbs[i](); } }, 0); } // If we're at the end of the buffer and an endEvent is specified, schedule // the event to fire. if (this.ended && this.buffer.length === 0 && this.endEvent !== null) { var endEvent = this.endEvent, _this = this; // Erase it so we don't accidentally trigger it again. this.endEvent = null; setTimeout(function () { _this.emitEvent('end', endEvent); }, 0); } // Return in correct encoding. if (events.length === 0) { // Buffer was empty. We're supposed to return 'null', as opposed to an // empty buffer or string. // [BFS] Emit a '_read' event to signal that maybe the write-end of this // should push some data into the pipe. this.emit('_read'); return null; } else if (this.encoding === null) { return buff.slice(0, trueSize); } else { return buff.toString(this.encoding, 0, trueSize); } }; /** * Set the encoding for the 'data' event. */ AbstractDuplexStream.prototype.setEncoding = function (encoding) { this.encoding = encoding; }; /** * Pause the stream. */ AbstractDuplexStream.prototype.pause = function () { this.flowing = false; }; /** * Resume the stream. */ AbstractDuplexStream.prototype.resume = function () { this.flowing = true; // Process any buffered writes. this._processEvents(); }; /** * Pipe a readable stream into a writable stream. Currently unimplemented. */ AbstractDuplexStream.prototype.pipe = function (destination, options) { throw new ApiError(0 /* EPERM */, "Unimplemented."); }; AbstractDuplexStream.prototype.unpipe = function (destination) { }; AbstractDuplexStream.prototype.unshift = function (chunk) { if (this.ended) { throw new ApiError(0 /* EPERM */, "Stream has ended."); } this.buffer.unshift(new BufferedEvent(chunk, this.encoding)); this._processEvents(); }; /** * 'Push' the given piece of data to the back of the buffer. * Returns true if the event was sent out, false if buffered. */ AbstractDuplexStream.prototype._push = function (event) { this.buffer.push(event); this._processEvents(); }; /** * Enables backwards-compatibility with older versions of Node and their * stream interface. Unimplemented. */ AbstractDuplexStream.prototype.wrap = function (stream) { throw new ApiError(0 /* EPERM */, "Unimplemented."); }; return AbstractDuplexStream; })(AbstractEventEmitter); exports.AbstractDuplexStream = AbstractDuplexStream; }); //# sourceMappingURL=node_eventemitter.js.map ; var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; define('core/node_process',["require", "exports", './node_eventemitter'], function(require, exports, eventemitter) { var path = null; var TTY = (function (_super) { __extends(TTY, _super); function TTY() { _super.call(this, true, true); this.isRaw = false; this.columns = 80; this.rows = 120; this.isTTY = true; } /** * Set read mode to 'true' to enable raw mode. */ TTY.prototype.setReadMode = function (mode) { if (this.isRaw !== mode) { this.isRaw = mode; // [BFS] TTY implementations can use this to change their event emitting // patterns. this.emit('modeChange'); } }; /** * [BFS] Update the number of columns available on the terminal. */ TTY.prototype.changeColumns = function (columns) { if (columns !== this.columns) { this.columns = columns; // Resize event. this.emit('resize'); } }; /** * [BFS] Update the number of rows available on the terminal. */ TTY.prototype.changeRows = function (rows) { if (rows !== this.rows) { this.rows = rows; // Resize event. this.emit('resize'); } }; /** * Returns 'true' if the given object is a TTY. */ TTY.isatty = function (fd) { return fd instanceof TTY; }; return TTY; })(eventemitter.AbstractDuplexStream); exports.TTY = TTY; /** * Partial implementation of Node's `process` module. * We implement the portions that are relevant for the filesystem. * @see http://nodejs.org/api/process.html * @class */ var Process = (function () { function Process() { this.startTime = Date.now(); this._cwd = '/'; /** * Returns what platform you are running on. * @return [String] */ this.platform = 'browser'; this.argv = []; this.stdout = new TTY(); this.stderr = new TTY(); this.stdin = new TTY(); } /** * Changes the current working directory. * * **Note**: BrowserFS does not validate that the directory actually exists. * * @example Usage example * console.log('Starting directory: ' + process.cwd()); * process.chdir('/tmp'); * console.log('New directory: ' + process.cwd()); * @param [String] dir The directory to change to. */ Process.prototype.chdir = function (dir) { // XXX: Circular dependency hack. if (path === null) { path = require('./node_path').path; } this._cwd = path.resolve(dir); }; /** * Returns the current working directory. * @example Usage example * console.log('Current directory: ' + process.cwd()); * @return [String] The current working directory. */ Process.prototype.cwd = function () { return this._cwd; }; /** * Number of seconds BrowserFS has been running. * @return [Number] */ Process.prototype.uptime = function () { return ((Date.now() - this.startTime) / 1000) | 0; }; return Process; })(); exports.Process = Process; // process is a singleton. exports.process = new Process(); }); //# sourceMappingURL=node_process.js.map ; define('core/node_path',["require", "exports", './node_process'], function(require, exports, node_process) { var process = node_process.process; /** * Emulates Node's `path` module. This module contains utilities for handling and * transforming file paths. **All** of these methods perform only string * transformations. The file system is not consulted to check whether paths are * valid. * @see http://nodejs.org/api/path.html * @class */ var path = (function () { function path() { } /** * Normalize a string path, taking care of '..' and '.' parts. * * When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used. * @example Usage example * path.normalize('/foo/bar//baz/asdf/quux/..') * // returns * '/foo/bar/baz/asdf' * @param [String] p The path to normalize. * @return [String] */ path.normalize = function (p) { // Special case: '' -> '.' if (p === '') { p = '.'; } // It's very important to know if the path is relative or not, since it // changes how we process .. and reconstruct the split string. var absolute = p.charAt(0) === path.sep; // Remove repeated //s p = path._removeDuplicateSeps(p); // Try to remove as many '../' as possible, and remove '.' completely. var components = p.split(path.sep); var goodComponents = []; for (var idx = 0; idx < components.length; idx++) { var c = components[idx]; if (c === '.') { continue; } else if (c === '..' && (absolute || (!absolute && goodComponents.length > 0 && goodComponents[0] !== '..'))) { // In the absolute case: Path is relative to root, so we may pop even if // goodComponents is empty (e.g. /../ => /) // In the relative case: We're getting rid of a directory that preceded // it (e.g. /foo/../bar -> /bar) goodComponents.pop(); } else { goodComponents.push(c); } } // Add in '.' when it's a relative path with no other nonempty components. // Possible results: '.' and './' (input: [''] or []) // @todo Can probably simplify this logic. if (!absolute && goodComponents.length < 2) { switch (goodComponents.length) { case 1: if (goodComponents[0] === '') { goodComponents.unshift('.'); } break; default: goodComponents.push('.'); } } p = goodComponents.join(path.sep); if (absolute && p.charAt(0) !== path.sep) { p = path.sep + p; } return p; }; /** * Join all arguments together and normalize the resulting path. * * Arguments must be strings. * @example Usage * path.join('/foo', 'bar', 'baz/asdf', 'quux', '..') * // returns * '/foo/bar/baz/asdf' * * path.join('foo', {}, 'bar') * // throws exception * TypeError: Arguments to path.join must be strings * @param [String,...] paths Each component of the path * @return [String] */ path.join = function () { var paths = []; for (var _i = 0; _i < (arguments.length - 0); _i++) { paths[_i] = arguments[_i + 0]; } // Required: Prune any non-strings from the path. I also prune empty segments // so we can do a simple join of the array. var processed = []; for (var i = 0; i < paths.length; i++) { var segment = paths[i]; if (typeof segment !== 'string') { throw new TypeError("Invalid argument type to path.join: " + (typeof segment)); } else if (segment !== '') { processed.push(segment); } } return path.normalize(processed.join(path.sep)); }; /** * Resolves to to an absolute path. * * If to isn't already absolute from arguments are prepended in right to left * order, until an absolute path is found. If after using all from paths still * no absolute path is found, the current working directory is used as well. * The resulting path is normalized, and trailing slashes are removed unless * the path gets resolved to the root directory. Non-string arguments are * ignored. * * Another way to think of it is as a sequence of cd commands in a shell. * * path.resolve('foo/bar', '/tmp/file/', '..', 'a/../subfile') * * Is similar to: * * cd foo/bar * cd /tmp/file/ * cd .. * cd a/../subfile * pwd * * The difference is that the different paths don't need to exist and may also * be files. * @example Usage example * path.resolve('/foo/bar', './baz') * // returns * '/foo/bar/baz' * * path.resolve('/foo/bar', '/tmp/file/') * // returns * '/tmp/file' * * path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif') * // if currently in /home/myself/node, it returns * '/home/myself/node/wwwroot/static_files/gif/image.gif' * @param [String,...] paths * @return [String] */ path.resolve = function () { var paths = []; for (var _i = 0; _i < (arguments.length - 0); _i++) { paths[_i] = arguments[_i + 0]; } // Monitor for invalid paths, throw out empty paths, and look for the *last* // absolute path that we see. var processed = []; for (var i = 0; i < paths.length; i++) { var p = paths[i]; if (typeof p !== 'string') { throw new TypeError("Invalid argument type to path.join: " + (typeof p)); } else if (p !== '') { // Remove anything that has occurred before this absolute path, as it // doesn't matter. if (p.charAt(0) === path.sep) { processed = []; } processed.push(p); } } // Special: Remove trailing slash unless it's the root var resolved = path.normalize(processed.join(path.sep)); if (resolved.length > 1 && resolved.charAt(resolved.length - 1) === path.sep) { return resolved.substr(0, resolved.length - 1); } // Special: If it doesn't start with '/', it's relative and we need to append // the current directory. if (resolved.charAt(0) !== path.sep) { // Remove ./, since we're going to append the current directory. if (resolved.charAt(0) === '.' && (resolved.length === 1 || resolved.charAt(1) === path.sep)) { resolved = resolved.length === 1 ? '' : resolved.substr(2); } // Append the current directory, which *must* be an absolute path. var cwd = process.cwd(); if (resolved !== '') { // cwd will never end in a /... unless it's the root. resolved = this.normalize(cwd + (cwd !== '/' ? path.sep : '') + resolved); } else { resolved = cwd; } } return resolved; }; /** * Solve the relative path from from to to. * * At times we have two absolute paths, and we need to derive the relative path * from one to the other. This is actually the reverse transform of * path.resolve, which means we see that: * * path.resolve(from, path.relative(from, to)) == path.resolve(to) * * @example Usage example * path.relative('C:\\orandea\\test\\aaa', 'C:\\orandea\\impl\\bbb') * // returns * '..\\..\\impl\\bbb' * * path.relative('/data/orandea/test/aaa', '/data/orandea/impl/bbb') * // returns * '../../impl/bbb' * @param [String] from * @param [String] to * @return [String] */ path.relative = function (from, to) { var i; // Alright. Let's resolve these two to absolute paths and remove any // weirdness. from = path.resolve(from); to = path.resolve(to); var fromSegs = from.split(path.sep); var toSegs = to.split(path.sep); // Remove the first segment on both, as it's '' (both are absolute paths) toSegs.shift(); fromSegs.shift(); // There are two segments to this path: // * Going *up* the directory hierarchy with '..' // * Going *down* the directory hierarchy with foo/baz/bat. var upCount = 0; var downSegs = []; for (i = 0; i < fromSegs.length; i++) { var seg = fromSegs[i]; if (seg === toSegs[i]) { continue; } // The rest of 'from', including the current element, indicates how many // directories we need to go up. upCount = fromSegs.length - i; break; } // The rest of 'to' indicates where we need to change to. We place this // outside of the loop, as toSegs.length may be greater than fromSegs.length. downSegs = toSegs.slice(i); // Special case: If 'from' is '/' if (fromSegs.length === 1 && fromSegs[0] === '') { upCount = 0; } // upCount can't be greater than the number of fromSegs // (cd .. from / is still /) if (upCount > fromSegs.length) { upCount = fromSegs.length; } // Create the final string! var rv = ''; for (i = 0; i < upCount; i++) { rv += '../'; } rv += downSegs.join(path.sep); // Special case: Remove trailing '/'. Happens if it's all up and no down. if (rv.length > 1 && rv.charAt(rv.length - 1) === path.sep) { rv = rv.substr(0, rv.length - 1); } return rv; }; /** * Return the directory name of a path. Similar to the Unix `dirname` command. * * Note that BrowserFS does not validate if the path is actually a valid * directory. * @example Usage example * path.dirname('/foo/bar/baz/asdf/quux') * // returns * '/foo/bar/baz/asdf' * @param [String] p The path to get the directory name of. * @return [String] */ path.dirname = function (p) { // We get rid of //, but we don't modify anything else (e.g. any extraneous . // and ../ are kept intact) p = path._removeDuplicateSeps(p); var absolute = p.charAt(0) === path.sep; var sections = p.split(path.sep); // Do 1 if it's /foo/bar, 2 if it's /foo/bar/ if (sections.pop() === '' && sections.length > 0) { sections.pop(); } if (sections.length > 1) { return sections.join(path.sep); } else if (absolute) { return path.sep; } else { return '.'; } }; /** * Return the last portion of a path. Similar to the Unix basename command. * @example Usage example * path.basename('/foo/bar/baz/asdf/quux.html') * // returns * 'quux.html' * * path.basename('/foo/bar/baz/asdf/quux.html', '.html') * // returns * 'quux' * @param [String] p * @param [String?] ext * @return [String] */ path.basename = function (p, ext) { if (typeof ext === "undefined") { ext = ""; } // Special case: Normalize will modify this to '.' if (p === '') { return p; } // Normalize the string first to remove any weirdness. p = path.normalize(p); // Get the last part of the string. var sections = p.split(path.sep); var lastPart = sections[sections.length - 1]; // Special case: If it's empty, then we have a string like so: foo/ // Meaning, 'foo' is guaranteed to be a directory. if (lastPart === '' && sections.length > 1) { return sections[sections.length - 2]; } // Remove the extension, if need be. if (ext.length > 0) { var lastPartExt = lastPart.substr(lastPart.length - ext.length); if (lastPartExt === ext) { return lastPart.substr(0, lastPart.length - ext.length); } } return lastPart; }; /** * Return the extension of the path, from the last '.' to end of string in the * last portion of the path. If there is no '.' in the last portion of the path * or the first character of it is '.', then it returns an empty string. * @example Usage example * path.extname('index.html') * // returns * '.html' * * path.extname('index.') * // returns * '.' * * path.extname('index') * // returns * '' * @param [String] p * @return [String] */ path.extname = function (p) { p = path.normalize(p); var sections = p.split(path.sep); p = sections.pop(); // Special case: foo/file.ext/ should return '.ext' if (p === '' && sections.length > 0) { p = sections.pop(); } if (p === '..') { return ''; } var i = p.lastIndexOf('.'); if (i === -1 || i === 0) { return ''; } return p.substr(i); }; /** * Checks if the given path is an absolute path. * * Despite not being documented, this is a tested part of Node's path API. * @param [String] p * @return [Boolean] True if the path appears to be an absolute path. */ path.isAbsolute = function (p) { return p.length > 0 && p.charAt(0) === path.sep; }; /** * Unknown. Undocumented. */ path._makeLong = function (p) { return p; }; path._removeDuplicateSeps = function (p) { p = p.replace(this._replaceRegex, this.sep); return p; }; path.sep = '/'; path._replaceRegex = new RegExp("//+", 'g'); path.delimiter = ':'; return path; })(); exports.path = path; }); //# sourceMappingURL=node_path.js.map ; define('core/node_fs',["require", "exports", './api_error', './file_flag', './buffer', './node_path'], function(require, exports, api_error, file_flag, buffer, node_path) { var ApiError = api_error.ApiError; var ErrorCode = api_error.ErrorCode; var FileFlag = file_flag.FileFlag; var Buffer = buffer.Buffer; var path = node_path.path; /** * Wraps a callback with a setImmediate call. * @param [Function] cb The callback to wrap. * @param [Number] numArgs The number of arguments that the callback takes. * @return [Function] The wrapped callback. */ function wrapCb(cb, numArgs) { if (typeof cb !== 'function') { throw new ApiError(9 /* EINVAL */, 'Callback must be a function.'); } // @todo This is used for unit testing. Maybe we should inject this logic // dynamically rather than bundle it in 'production' code. if (typeof __numWaiting === 'undefined') { __numWaiting = 0; } __numWaiting++; switch (numArgs) { case 1: return function (arg1) { setImmediate(function () { __numWaiting--; return cb(arg1); }); }; case 2: return function (arg1, arg2) { setImmediate(function () { __numWaiting--; return cb(arg1, arg2); }); }; case 3: return function (arg1, arg2, arg3) { setImmediate(function () { __numWaiting--; return cb(arg1, arg2, arg3); }); }; default: throw new Error('Invalid invocation of wrapCb.'); } } /** * Checks if the fd is valid. * @param [BrowserFS.File] fd A file descriptor (in BrowserFS, it's a File object) * @return [Boolean, BrowserFS.ApiError] Returns `true` if the FD is OK, * otherwise returns an ApiError. */ function checkFd(fd) { if (typeof fd['write'] !== 'function') { throw new ApiError(3 /* EBADF */, 'Invalid file descriptor.'); } } function normalizeMode(mode, def) { switch (typeof mode) { case 'number': // (path, flag, mode, cb?) return mode; case 'string': // (path, flag, modeString, cb?) var trueMode = parseInt(mode, 8); if (trueMode !== NaN) { return trueMode; } default: return def; } } function normalizePath(p) { // Node doesn't allow null characters in paths. if (p.indexOf('\u0000') >= 0) { throw new ApiError(9 /* EINVAL */, 'Path must be a string without null bytes.'); } else if (p === '') { throw new ApiError(9 /* EINVAL */, 'Path must not be empty.'); } return path.resolve(p); } function normalizeOptions(options, defEnc, defFlag, defMode) { switch (typeof options) { case 'object': return { encoding: typeof options['encoding'] !== 'undefined' ? options['encoding'] : defEnc, flag: typeof options['flag'] !== 'undefined' ? options['flag'] : defFlag, mode: normalizeMode(options['mode'], defMode) }; case 'string': return { encoding: options, flag: defFlag, mode: defMode }; default: return { encoding: defEnc, flag: defFlag, mode: defMode }; } } // The default callback is a NOP. function nopCb() { } ; /** * The node frontend to all filesystems. * This layer handles: * * * Sanity checking inputs. * * Normalizing paths. * * Resetting stack depth for asynchronous operations which may not go through * the browser by wrapping all input callbacks using `setImmediate`. * * Performing the requested operation through the filesystem or the file * descriptor, as appropriate. * * Handling optional arguments and setting default arguments. * @see http://nodejs.org/api/fs.html * @class */ var fs = (function () { function fs() { } fs._initialize = function (rootFS) { if (!rootFS.constructor.isAvailable()) { throw new ApiError(9 /* EINVAL */, 'Tried to instantiate BrowserFS with an unavailable file system.'); } return fs.root = rootFS; }; fs._toUnixTimestamp = function (time) { if (typeof time === 'number') { return time; } else if (time instanceof Date) { return time.getTime() / 1000; } throw new Error("Cannot parse time: " + time); }; /** * **NONSTANDARD**: Grab the FileSystem instance that backs this API. * @return [BrowserFS.FileSystem | null] Returns null if the file system has * not been initialized. */ fs.getRootFS = function () { if (fs.root) { return fs.root; } else { return null; } }; // FILE OR DIRECTORY METHODS /** * Asynchronous rename. No arguments other than a possible exception are given * to the completion callback. * @param [String] oldPath * @param [String] newPath * @param [Function(BrowserFS.ApiError)] callback */ fs.rename = function (oldPath, newPath, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { fs.root.rename(normalizePath(oldPath), normalizePath(newPath), newCb); } catch (e) { newCb(e); } }; /** * Synchronous rename. * @param [String] oldPath * @param [String] newPath */ fs.renameSync = function (oldPath, newPath) { fs.root.renameSync(normalizePath(oldPath), normalizePath(newPath)); }; /** * Test whether or not the given path exists by checking with the file system. * Then call the callback argument with either true or false. * @example Sample invocation * fs.exists('/etc/passwd', function (exists) { * util.debug(exists ? "it's there" : "no passwd!"); * }); * @param [String] path * @param [Function(Boolean)] callback */ fs.exists = function (path, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { return fs.root.exists(normalizePath(path), newCb); } catch (e) { // Doesn't return an error. If something bad happens, we assume it just // doesn't exist. return newCb(false); } }; /** * Test whether or not the given path exists by checking with the file system. * @param [String] path * @return [boolean] */ fs.existsSync = function (path) { try { return fs.root.existsSync(normalizePath(path)); } catch (e) { // Doesn't return an error. If something bad happens, we assume it just // doesn't exist. return false; } }; /** * Asynchronous `stat`. * @param [String] path * @param [Function(BrowserFS.ApiError, BrowserFS.node.fs.Stats)] callback */ fs.stat = function (path, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 2); try { return fs.root.stat(normalizePath(path), false, newCb); } catch (e) { return newCb(e, null); } }; /** * Synchronous `stat`. * @param [String] path * @return [BrowserFS.node.fs.Stats] */ fs.statSync = function (path) { return fs.root.statSync(normalizePath(path), false); }; /** * Asynchronous `lstat`. * `lstat()` is identical to `stat()`, except that if path is a symbolic link, * then the link itself is stat-ed, not the file that it refers to. * @param [String] path * @param [Function(BrowserFS.ApiError, BrowserFS.node.fs.Stats)] callback */ fs.lstat = function (path, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 2); try { return fs.root.stat(normalizePath(path), true, newCb); } catch (e) { return newCb(e, null); } }; /** * Synchronous `lstat`. * `lstat()` is identical to `stat()`, except that if path is a symbolic link, * then the link itself is stat-ed, not the file that it refers to. * @param [String] path * @return [BrowserFS.node.fs.Stats] */ fs.lstatSync = function (path) { return fs.root.statSync(normalizePath(path), true); }; fs.truncate = function (path, arg2, cb) { if (typeof arg2 === "undefined") { arg2 = 0; } if (typeof cb === "undefined") { cb = nopCb; } var len = 0; if (typeof arg2 === 'function') { cb = arg2; } else if (typeof arg2 === 'number') { len = arg2; } var newCb = wrapCb(cb, 1); try { if (len < 0) { throw new ApiError(9 /* EINVAL */); } return fs.root.truncate(normalizePath(path), len, newCb); } catch (e) { return newCb(e); } }; /** * Synchronous `truncate`. * @param [String] path * @param [Number] len */ fs.truncateSync = function (path, len) { if (typeof len === "undefined") { len = 0; } if (len < 0) { throw new ApiError(9 /* EINVAL */); } return fs.root.truncateSync(normalizePath(path), len); }; /** * Asynchronous `unlink`. * @param [String] path * @param [Function(BrowserFS.ApiError)] callback */ fs.unlink = function (path, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { return fs.root.unlink(normalizePath(path), newCb); } catch (e) { return newCb(e); } }; /** * Synchronous `unlink`. * @param [String] path */ fs.unlinkSync = function (path) { return fs.root.unlinkSync(normalizePath(path)); }; fs.open = function (path, flag, arg2, cb) { if (typeof cb === "undefined") { cb = nopCb; } var mode = normalizeMode(arg2, 0x1a4); cb = typeof arg2 === 'function' ? arg2 : cb; var newCb = wrapCb(cb, 2); try { return fs.root.open(normalizePath(path), FileFlag.getFileFlag(flag), mode, newCb); } catch (e) { return newCb(e, null); } }; fs.openSync = function (path, flag, mode) { if (typeof mode === "undefined") { mode = 0x1a4; } return fs.root.openSync(normalizePath(path), FileFlag.getFileFlag(flag), mode); }; fs.readFile = function (filename, arg2, cb) { if (typeof arg2 === "undefined") { arg2 = {}; } if (typeof cb === "undefined") { cb = nopCb; } var options = normalizeOptions(arg2, null, 'r', null); cb = typeof arg2 === 'function' ? arg2 : cb; var newCb = wrapCb(cb, 2); try { var flag = FileFlag.getFileFlag(options['flag']); if (!flag.isReadable()) { return newCb(new ApiError(9 /* EINVAL */, 'Flag passed to readFile must allow for reading.')); } return fs.root.readFile(normalizePath(filename), options.encoding, flag, newCb); } catch (e) { return newCb(e, null); } }; fs.readFileSync = function (filename, arg2) { if (typeof arg2 === "undefined") { arg2 = {}; } var options = normalizeOptions(arg2, null, 'r', null); var flag = FileFlag.getFileFlag(options.flag); if (!flag.isReadable()) { throw new ApiError(9 /* EINVAL */, 'Flag passed to readFile must allow for reading.'); } return fs.root.readFileSync(normalizePath(filename), options.encoding, flag); }; fs.writeFile = function (filename, data, arg3, cb) { if (typeof arg3 === "undefined") { arg3 = {}; } if (typeof cb === "undefined") { cb = nopCb; } var options = normalizeOptions(arg3, 'utf8', 'w', 0x1a4); cb = typeof arg3 === 'function' ? arg3 : cb; var newCb = wrapCb(cb, 1); try { var flag = FileFlag.getFileFlag(options.flag); if (!flag.isWriteable()) { return newCb(new ApiError(9 /* EINVAL */, 'Flag passed to writeFile must allow for writing.')); } return fs.root.writeFile(normalizePath(filename), data, options.encoding, flag, options.mode, newCb); } catch (e) { return newCb(e); } }; fs.writeFileSync = function (filename, data, arg3) { var options = normalizeOptions(arg3, 'utf8', 'w', 0x1a4); var flag = FileFlag.getFileFlag(options.flag); if (!flag.isWriteable()) { throw new ApiError(9 /* EINVAL */, 'Flag passed to writeFile must allow for writing.'); } return fs.root.writeFileSync(normalizePath(filename), data, options.encoding, flag, options.mode); }; fs.appendFile = function (filename, data, arg3, cb) { if (typeof cb === "undefined") { cb = nopCb; } var options = normalizeOptions(arg3, 'utf8', 'a', 0x1a4); cb = typeof arg3 === 'function' ? arg3 : cb; var newCb = wrapCb(cb, 1); try { var flag = FileFlag.getFileFlag(options.flag); if (!flag.isAppendable()) { return newCb(new ApiError(9 /* EINVAL */, 'Flag passed to appendFile must allow for appending.')); } fs.root.appendFile(normalizePath(filename), data, options.encoding, flag, options.mode, newCb); } catch (e) { newCb(e); } }; fs.appendFileSync = function (filename, data, arg3) { var options = normalizeOptions(arg3, 'utf8', 'a', 0x1a4); var flag = FileFlag.getFileFlag(options.flag); if (!flag.isAppendable()) { throw new ApiError(9 /* EINVAL */, 'Flag passed to appendFile must allow for appending.'); } return fs.root.appendFileSync(normalizePath(filename), data, options.encoding, flag, options.mode); }; // FILE DESCRIPTOR METHODS /** * Asynchronous `fstat`. * `fstat()` is identical to `stat()`, except that the file to be stat-ed is * specified by the file descriptor `fd`. * @param [BrowserFS.File] fd * @param [Function(BrowserFS.ApiError, BrowserFS.node.fs.Stats)] callback */ fs.fstat = function (fd, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 2); try { checkFd(fd); fd.stat(newCb); } catch (e) { newCb(e); } }; /** * Synchronous `fstat`. * `fstat()` is identical to `stat()`, except that the file to be stat-ed is * specified by the file descriptor `fd`. * @param [BrowserFS.File] fd * @return [BrowserFS.node.fs.Stats] */ fs.fstatSync = function (fd) { checkFd(fd); return fd.statSync(); }; /** * Asynchronous close. * @param [BrowserFS.File] fd * @param [Function(BrowserFS.ApiError)] callback */ fs.close = function (fd, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { checkFd(fd); fd.close(newCb); } catch (e) { newCb(e); } }; /** * Synchronous close. * @param [BrowserFS.File] fd */ fs.closeSync = function (fd) { checkFd(fd); return fd.closeSync(); }; fs.ftruncate = function (fd, arg2, cb) { if (typeof cb === "undefined") { cb = nopCb; } var length = typeof arg2 === 'number' ? arg2 : 0; cb = typeof arg2 === 'function' ? arg2 : cb; var newCb = wrapCb(cb, 1); try { checkFd(fd); if (length < 0) { throw new ApiError(9 /* EINVAL */); } fd.truncate(length, newCb); } catch (e) { newCb(e); } }; /** * Synchronous ftruncate. * @param [BrowserFS.File] fd * @param [Number] len */ fs.ftruncateSync = function (fd, len) { if (typeof len === "undefined") { len = 0; } checkFd(fd); return fd.truncateSync(len); }; /** * Asynchronous fsync. * @param [BrowserFS.File] fd * @param [Function(BrowserFS.ApiError)] callback */ fs.fsync = function (fd, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { checkFd(fd); fd.sync(newCb); } catch (e) { newCb(e); } }; /** * Synchronous fsync. * @param [BrowserFS.File] fd */ fs.fsyncSync = function (fd) { checkFd(fd); return fd.syncSync(); }; /** * Asynchronous fdatasync. * @param [BrowserFS.File] fd * @param [Function(BrowserFS.ApiError)] callback */ fs.fdatasync = function (fd, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { checkFd(fd); fd.datasync(newCb); } catch (e) { newCb(e); } }; /** * Synchronous fdatasync. * @param [BrowserFS.File] fd */ fs.fdatasyncSync = function (fd) { checkFd(fd); fd.datasyncSync(); }; fs.write = function (fd, arg2, arg3, arg4, arg5, cb) { if (typeof cb === "undefined") { cb = nopCb; } var buffer, offset, length, position = null; if (typeof arg2 === 'string') { // Signature 1: (fd, string, [position?, [encoding?]], cb?) var encoding = 'utf8'; switch (typeof arg3) { case 'function': // (fd, string, cb) cb = arg3; break; case 'number': // (fd, string, position, encoding?, cb?) position = arg3; encoding = typeof arg4 === 'string' ? arg4 : 'utf8'; cb = typeof arg5 === 'function' ? arg5 : cb; break; default: // ...try to find the callback and get out of here! cb = typeof arg4 === 'function' ? arg4 : typeof arg5 === 'function' ? arg5 : cb; return cb(new ApiError(9 /* EINVAL */, 'Invalid arguments.')); } buffer = new Buffer(arg2, encoding); offset = 0; length = buffer.length; } else { // Signature 2: (fd, buffer, offset, length, position?, cb?) buffer = arg2; offset = arg3; length = arg4; position = typeof arg5 === 'number' ? arg5 : null; cb = typeof arg5 === 'function' ? arg5 : cb; } var newCb = wrapCb(cb, 3); try { checkFd(fd); if (position == null) { position = fd.getPos(); } fd.write(buffer, offset, length, position, newCb); } catch (e) { newCb(e); } }; fs.writeSync = function (fd, arg2, arg3, arg4, arg5) { var buffer, offset = 0, length, position; if (typeof arg2 === 'string') { // Signature 1: (fd, string, [position?, [encoding?]]) position = typeof arg3 === 'number' ? arg3 : null; var encoding = typeof arg4 === 'string' ? arg4 : 'utf8'; offset = 0; buffer = new Buffer(arg2, encoding); length = buffer.length; } else { // Signature 2: (fd, buffer, offset, length, position?) buffer = arg2; offset = arg3; length = arg4; position = typeof arg5 === 'number' ? arg5 : null; } checkFd(fd); if (position == null) { position = fd.getPos(); } return fd.writeSync(buffer, offset, length, position); }; fs.read = function (fd, arg2, arg3, arg4, arg5, cb) { if (typeof cb === "undefined") { cb = nopCb; } var position, offset, length, buffer, newCb; if (typeof arg2 === 'number') { // legacy interface // (fd, length, position, encoding, callback) length = arg2; position = arg3; var encoding = arg4; cb = typeof arg5 === 'function' ? arg5 : cb; offset = 0; buffer = new Buffer(length); // XXX: Inefficient. // Wrap the cb so we shelter upper layers of the API from these // shenanigans. newCb = wrapCb((function (err, bytesRead, buf) { if (err) { return cb(err); } cb(err, buf.toString(encoding), bytesRead); }), 3); } else { buffer = arg2; offset = arg3; length = arg4; position = arg5; newCb = wrapCb(cb, 3); } try { checkFd(fd); if (position == null) { position = fd.getPos(); } fd.read(buffer, offset, length, position, newCb); } catch (e) { newCb(e); } }; fs.readSync = function (fd, arg2, arg3, arg4, arg5) { var shenanigans = false; var buffer, offset, length, position; if (typeof arg2 === 'number') { length = arg2; position = arg3; var encoding = arg4; offset = 0; buffer = new Buffer(length); shenanigans = true; } else { buffer = arg2; offset = arg3; length = arg4; position = arg5; } checkFd(fd); if (position == null) { position = fd.getPos(); } var rv = fd.readSync(buffer, offset, length, position); if (!shenanigans) { return rv; } else { return [buffer.toString(encoding), rv]; } }; /** * Asynchronous `fchown`. * @param [BrowserFS.File] fd * @param [Number] uid * @param [Number] gid * @param [Function(BrowserFS.ApiError)] callback */ fs.fchown = function (fd, uid, gid, callback) { if (typeof callback === "undefined") { callback = nopCb; } var newCb = wrapCb(callback, 1); try { checkFd(fd); fd.chown(uid, gid, newCb); } catch (e) { newCb(e); } }; /** * Synchronous `fchown`. * @param [BrowserFS.File] fd * @param [Number] uid * @param [Number] gid */ fs.fchownSync = function (fd, uid, gid) { checkFd(fd); return fd.chownSync(uid, gid); }; fs.fchmod = function (fd, mode, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { mode = typeof mode === 'string' ? parseInt(mode, 8) : mode; checkFd(fd); fd.chmod(mode, newCb); } catch (e) { newCb(e); } }; fs.fchmodSync = function (fd, mode) { mode = typeof mode === 'string' ? parseInt(mode, 8) : mode; checkFd(fd); return fd.chmodSync(mode); }; fs.futimes = function (fd, atime, mtime, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { checkFd(fd); if (typeof atime === 'number') { atime = new Date(atime * 1000); } if (typeof mtime === 'number') { mtime = new Date(mtime * 1000); } fd.utimes(atime, mtime, newCb); } catch (e) { newCb(e); } }; fs.futimesSync = function (fd, atime, mtime) { checkFd(fd); if (typeof atime === 'number') { atime = new Date(atime * 1000); } if (typeof mtime === 'number') { mtime = new Date(mtime * 1000); } return fd.utimesSync(atime, mtime); }; // DIRECTORY-ONLY METHODS /** * Asynchronous `rmdir`. * @param [String] path * @param [Function(BrowserFS.ApiError)] callback */ fs.rmdir = function (path, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { path = normalizePath(path); fs.root.rmdir(path, newCb); } catch (e) { newCb(e); } }; /** * Synchronous `rmdir`. * @param [String] path */ fs.rmdirSync = function (path) { path = normalizePath(path); return fs.root.rmdirSync(path); }; /** * Asynchronous `mkdir`. * @param [String] path * @param [Number?] mode defaults to `0777` * @param [Function(BrowserFS.ApiError)] callback */ fs.mkdir = function (path, mode, cb) { if (typeof cb === "undefined") { cb = nopCb; } if (typeof mode === 'function') { cb = mode; mode = 0x1ff; } var newCb = wrapCb(cb, 1); try { path = normalizePath(path); fs.root.mkdir(path, mode, newCb); } catch (e) { newCb(e); } }; fs.mkdirSync = function (path, mode) { if (typeof mode === "undefined") { mode = 0x1ff; } mode = typeof mode === 'string' ? parseInt(mode, 8) : mode; path = normalizePath(path); return fs.root.mkdirSync(path, mode); }; /** * Asynchronous `readdir`. Reads the contents of a directory. * The callback gets two arguments `(err, files)` where `files` is an array of * the names of the files in the directory excluding `'.'` and `'..'`. * @param [String] path * @param [Function(BrowserFS.ApiError, String[])] callback */ fs.readdir = function (path, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 2); try { path = normalizePath(path); fs.root.readdir(path, newCb); } catch (e) { newCb(e); } }; /** * Synchronous `readdir`. Reads the contents of a directory. * @param [String] path * @return [String[]] */ fs.readdirSync = function (path) { path = normalizePath(path); return fs.root.readdirSync(path); }; // SYMLINK METHODS /** * Asynchronous `link`. * @param [String] srcpath * @param [String] dstpath * @param [Function(BrowserFS.ApiError)] callback */ fs.link = function (srcpath, dstpath, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { srcpath = normalizePath(srcpath); dstpath = normalizePath(dstpath); fs.root.link(srcpath, dstpath, newCb); } catch (e) { newCb(e); } }; /** * Synchronous `link`. * @param [String] srcpath * @param [String] dstpath */ fs.linkSync = function (srcpath, dstpath) { srcpath = normalizePath(srcpath); dstpath = normalizePath(dstpath); return fs.root.linkSync(srcpath, dstpath); }; fs.symlink = function (srcpath, dstpath, arg3, cb) { if (typeof cb === "undefined") { cb = nopCb; } var type = typeof arg3 === 'string' ? arg3 : 'file'; cb = typeof arg3 === 'function' ? arg3 : cb; var newCb = wrapCb(cb, 1); try { if (type !== 'file' && type !== 'dir') { return newCb(new ApiError(9 /* EINVAL */, "Invalid type: " + type)); } srcpath = normalizePath(srcpath); dstpath = normalizePath(dstpath); fs.root.symlink(srcpath, dstpath, type, newCb); } catch (e) { newCb(e); } }; /** * Synchronous `symlink`. * @param [String] srcpath * @param [String] dstpath * @param [String?] type can be either `'dir'` or `'file'` (default is `'file'`) */ fs.symlinkSync = function (srcpath, dstpath, type) { if (type == null) { type = 'file'; } else if (type !== 'file' && type !== 'dir') { throw new ApiError(9 /* EINVAL */, "Invalid type: " + type); } srcpath = normalizePath(srcpath); dstpath = normalizePath(dstpath); return fs.root.symlinkSync(srcpath, dstpath, type); }; /** * Asynchronous readlink. * @param [String] path * @param [Function(BrowserFS.ApiError, String)] callback */ fs.readlink = function (path, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 2); try { path = normalizePath(path); fs.root.readlink(path, newCb); } catch (e) { newCb(e); } }; /** * Synchronous readlink. * @param [String] path * @return [String] */ fs.readlinkSync = function (path) { path = normalizePath(path); return fs.root.readlinkSync(path); }; // PROPERTY OPERATIONS /** * Asynchronous `chown`. * @param [String] path * @param [Number] uid * @param [Number] gid * @param [Function(BrowserFS.ApiError)] callback */ fs.chown = function (path, uid, gid, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { path = normalizePath(path); fs.root.chown(path, false, uid, gid, newCb); } catch (e) { newCb(e); } }; /** * Synchronous `chown`. * @param [String] path * @param [Number] uid * @param [Number] gid */ fs.chownSync = function (path, uid, gid) { path = normalizePath(path); fs.root.chownSync(path, false, uid, gid); }; /** * Asynchronous `lchown`. * @param [String] path * @param [Number] uid * @param [Number] gid * @param [Function(BrowserFS.ApiError)] callback */ fs.lchown = function (path, uid, gid, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { path = normalizePath(path); fs.root.chown(path, true, uid, gid, newCb); } catch (e) { newCb(e); } }; /** * Synchronous `lchown`. * @param [String] path * @param [Number] uid * @param [Number] gid */ fs.lchownSync = function (path, uid, gid) { path = normalizePath(path); return fs.root.chownSync(path, true, uid, gid); }; fs.chmod = function (path, mode, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { mode = typeof mode === 'string' ? parseInt(mode, 8) : mode; path = normalizePath(path); fs.root.chmod(path, false, mode, newCb); } catch (e) { newCb(e); } }; fs.chmodSync = function (path, mode) { mode = typeof mode === 'string' ? parseInt(mode, 8) : mode; path = normalizePath(path); return fs.root.chmodSync(path, false, mode); }; fs.lchmod = function (path, mode, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { mode = typeof mode === 'string' ? parseInt(mode, 8) : mode; path = normalizePath(path); fs.root.chmod(path, true, mode, newCb); } catch (e) { newCb(e); } }; fs.lchmodSync = function (path, mode) { path = normalizePath(path); mode = typeof mode === 'string' ? parseInt(mode, 8) : mode; return fs.root.chmodSync(path, true, mode); }; fs.utimes = function (path, atime, mtime, cb) { if (typeof cb === "undefined") { cb = nopCb; } var newCb = wrapCb(cb, 1); try { path = normalizePath(path); if (typeof atime === 'number') { atime = new Date(atime * 1000); } if (typeof mtime === 'number') { mtime = new Date(mtime * 1000); } fs.root.utimes(path, atime, mtime, newCb); } catch (e) { newCb(e); } }; fs.utimesSync = function (path, atime, mtime) { path = normalizePath(path); if (typeof atime === 'number') { atime = new Date(atime * 1000); } if (typeof mtime === 'number') { mtime = new Date(mtime * 1000); } return fs.root.utimesSync(path, atime, mtime); }; fs.realpath = function (path, arg2, cb) { if (typeof cb === "undefined") { cb = nopCb; } var cache = typeof arg2 === 'object' ? arg2 : {}; cb = typeof arg2 === 'function' ? arg2 : nopCb; var newCb = wrapCb(cb, 2); try { path = normalizePath(path); fs.root.realpath(path, cache, newCb); } catch (e) { newCb(e); } }; /** * Synchronous `realpath`. * @param [String] path * @param [Object?] cache An object literal of mapped paths that can be used to * force a specific path resolution or avoid additional `fs.stat` calls for * known real paths. * @return [String] */ fs.realpathSync = function (path, cache) { if (typeof cache === "undefined") { cache = {}; } path = normalizePath(path); return fs.root.realpathSync(path, cache); }; fs.root = null; return fs; })(); exports.fs = fs; }); //# sourceMappingURL=node_fs.js.map ; define('core/browserfs',["require", "exports", './buffer', './node_fs', './node_path', './node_process'], function(require, exports, buffer, node_fs, node_path, node_process) { /** * Installs BrowserFS onto the given object. * We recommend that you run install with the 'window' object to make things * global, as in Node. * * Properties installed: * * * Buffer * * process * * require (we monkey-patch it) * * This allows you to write code as if you were running inside Node. * @param {object} obj - The object to install things onto (e.g. window) */ function install(obj) { obj.Buffer = buffer.Buffer; obj.process = node_process.process; var oldRequire = obj.require != null ? obj.require : null; // Monkey-patch require for Node-style code. obj.require = function (arg) { var rv = exports.BFSRequire(arg); if (rv == null) { return oldRequire.apply(null, Array.prototype.slice.call(arguments, 0)); } else { return rv; } }; } exports.install = install; exports.FileSystem = {}; function registerFileSystem(name, fs) { exports.FileSystem[name] = fs; } exports.registerFileSystem = registerFileSystem; function BFSRequire(module) { switch (module) { case 'fs': return node_fs.fs; case 'path': return node_path.path; case 'buffer': // The 'buffer' module has 'Buffer' as a property. return buffer; case 'process': return node_process.process; default: return exports.FileSystem[module]; } } exports.BFSRequire = BFSRequire; /** * You must call this function with a properly-instantiated root file system * before using any file system API method. * @param {BrowserFS.FileSystem} rootFS - The root filesystem to use for the * entire BrowserFS file system. */ function initialize(rootfs) { return node_fs.fs._initialize(rootfs); } exports.initialize = initialize; }); //# sourceMappingURL=browserfs.js.map ; define('generic/emscripten_fs',["require", "exports", '../core/browserfs', '../core/node_fs', '../core/buffer', '../core/buffer_core_arraybuffer'], function(require, exports, BrowserFS, node_fs, buffer, buffer_core_arraybuffer) { var Buffer = buffer.Buffer; var BufferCoreArrayBuffer = buffer_core_arraybuffer.BufferCoreArrayBuffer; var fs = node_fs.fs; var BFSEmscriptenStreamOps = (function () { function BFSEmscriptenStreamOps(fs) { this.fs = fs; } BFSEmscriptenStreamOps.prototype.open = function (stream) { var path = this.fs.realPath(stream.node); try { if (FS.isFile(stream.node.mode)) { stream.nfd = fs.openSync(path, this.fs.flagsToPermissionString(stream.flags)); } } catch (e) { if (!e.code) throw e; throw new FS.ErrnoError(ERRNO_CODES[e.code]); } }; BFSEmscriptenStreamOps.prototype.close = function (stream) { try { if (FS.isFile(stream.node.mode) && stream.nfd) { fs.closeSync(stream.nfd); } } catch (e) { if (!e.code) throw e; throw new FS.ErrnoError(ERRNO_CODES[e.code]); } }; BFSEmscriptenStreamOps.prototype.read = function (stream, buffer, offset, length, position) { // Avoid copying overhead by reading directly into buffer. var bcore = new BufferCoreArrayBuffer(buffer.buffer); var nbuffer = new Buffer(bcore, buffer.byteOffset + offset, buffer.byteOffset + offset + length); var res; try { res = fs.readSync(stream.nfd, nbuffer, 0, length, position); } catch (e) { throw new FS.ErrnoError(ERRNO_CODES[e.code]); } // No copying needed, since we wrote directly into UintArray. return res; }; BFSEmscriptenStreamOps.prototype.write = function (stream, buffer, offset, length, position) { // Avoid copying overhead; plug the buffer directly into a BufferCore. var bcore = new BufferCoreArrayBuffer(buffer.buffer); var nbuffer = new Buffer(bcore, buffer.byteOffset + offset, buffer.byteOffset + offset + length); var res; try { res = fs.writeSync(stream.nfd, nbuffer, 0, length, position); } catch (e) { throw new FS.ErrnoError(ERRNO_CODES[e.code]); } return res; }; BFSEmscriptenStreamOps.prototype.llseek = function (stream, offset, whence) { var position = offset; if (whence === 1) { position += stream.position; } else if (whence === 2) { if (FS.isFile(stream.node.mode)) { try { var stat = fs.fstatSync(stream.nfd); position += stat.size; } catch (e) { throw new FS.ErrnoError(ERRNO_CODES[e.code]); } } } if (position < 0) { throw new FS.ErrnoError(ERRNO_CODES.EINVAL); } stream.position = position; return position; }; return BFSEmscriptenStreamOps; })(); var BFSEmscriptenNodeOps = (function () { function BFSEmscriptenNodeOps(fs) { this.fs = fs; } BFSEmscriptenNodeOps.prototype.getattr = function (node) { var path = this.fs.realPath(node); var stat; try { stat = fs.lstatSync(path); } catch (e) { if (!e.code) throw e; throw new FS.ErrnoError(ERRNO_CODES[e.code]); } return { dev: stat.dev, ino: stat.ino, mode: stat.mode, nlink: stat.nlink, uid: stat.uid, gid: stat.gid, rdev: stat.rdev, size: stat.size, atime: stat.atime, mtime: stat.mtime, ctime: stat.ctime, blksize: stat.blksize, blocks: stat.blocks }; }; BFSEmscriptenNodeOps.prototype.setattr = function (node, attr) { var path = this.fs.realPath(node); try { if (attr.mode !== undefined) { fs.chmodSync(path, attr.mode); // update the common node structure mode as well node.mode = attr.mode; } if (attr.timestamp !== undefined) { var date = new Date(attr.timestamp); fs.utimesSync(path, date, date); } if (attr.size !== undefined) { fs.truncateSync(path, attr.size); } } catch (e) { if (!e.code) throw e; if (e.code === "ENOTSUP") { // Ignore not supported errors. Emscripten does utimesSync when it // writes files, but never really requires the value to be set. return; } throw new FS.ErrnoError(ERRNO_CODES[e.code]); } }; BFSEmscriptenNodeOps.prototype.lookup = function (parent, name) { var path = PATH.join2(this.fs.realPath(parent), name); var mode = this.fs.getMode(path); return this.fs.createNode(parent, name, mode); }; BFSEmscriptenNodeOps.prototype.mknod = function (parent, name, mode, dev) { var node = this.fs.createNode(parent, name, mode, dev); // create the backing node for this in the fs root as well var path = this.fs.realPath(node); try { if (FS.isDir(node.mode)) { fs.mkdirSync(path, node.mode); } else { fs.writeFileSync(path, '', { mode: node.mode }); } } catch (e) { if (!e.code) throw e; throw new FS.ErrnoError(ERRNO_CODES[e.code]); } return node; }; BFSEmscriptenNodeOps.prototype.rename = function (oldNode, newDir, newName) { var oldPath = this.fs.realPath(oldNode); var newPath = PATH.join2(this.fs.realPath(newDir), newName); try { fs.renameSync(oldPath, newPath); } catch (e) { if (!e.code) throw e; throw new FS.ErrnoError(ERRNO_CODES[e.code]); } }; BFSEmscriptenNodeOps.prototype.unlink = function (parent, name) { var path = PATH.join2(this.fs.realPath(parent), name); try { fs.unlinkSync(path); } catch (e) { if (!e.code) throw e; throw new FS.ErrnoError(ERRNO_CODES[e.code]); } }; BFSEmscriptenNodeOps.prototype.rmdir = function (parent, name) { var path = PATH.join2(this.fs.realPath(parent), name); try { fs.rmdirSync(path); } catch (e) { if (!e.code) throw e; throw new FS.ErrnoError(ERRNO_CODES[e.code]); } }; BFSEmscriptenNodeOps.prototype.readdir = function (node) { var path = this.fs.realPath(node); try { return fs.readdirSync(path); } catch (e) { if (!e.code) throw e; throw new FS.ErrnoError(ERRNO_CODES[e.code]); } }; BFSEmscriptenNodeOps.prototype.symlink = function (parent, newName, oldPath) { var newPath = PATH.join2(this.fs.realPath(parent), newName); try { fs.symlinkSync(oldPath, newPath); } catch (e) { if (!e.code) throw e; throw new FS.ErrnoError(ERRNO_CODES[e.code]); } }; BFSEmscriptenNodeOps.prototype.readlink = function (node) { var path = this.fs.realPath(node); try { return fs.readlinkSync(path); } catch (e) { if (!e.code) throw e; throw new FS.ErrnoError(ERRNO_CODES[e.code]); } }; return BFSEmscriptenNodeOps; })(); var BFSEmscriptenFS = (function () { function BFSEmscriptenFS() { // This maps the integer permission modes from http://linux.die.net/man/3/open // to node.js-specific file open permission strings at http://nodejs.org/api/fs.html#fs_fs_open_path_flags_mode_callback this.flagsToPermissionStringMap = { 0: 'r', 1: 'r+', 2: 'r+', 64: 'r', 65: 'r+', 66: 'r+', 129: 'rx+', 193: 'rx+', 514: 'w+', 577: 'w', 578: 'w+', 705: 'wx', 706: 'wx+', 1024: 'a', 1025: 'a', 1026: 'a+', 1089: 'a', 1090: 'a+', 1153: 'ax', 1154: 'ax+', 1217: 'ax', 1218: 'ax+', 4096: 'rs', 4098: 'rs+' }; this.node_ops = new BFSEmscriptenNodeOps(this); this.stream_ops = new BFSEmscriptenStreamOps(this); if (typeof BrowserFS === 'undefined') { throw new Error("BrowserFS is not loaded. Please load it before this library."); } } BFSEmscriptenFS.prototype.mount = function (mount) { return this.createNode(null, '/', this.getMode(mount.opts.root), 0); }; BFSEmscriptenFS.prototype.createNode = function (parent, name, mode, dev) { if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) { throw new FS.ErrnoError(ERRNO_CODES.EINVAL); } var node = FS.createNode(parent, name, mode); node.node_ops = this.node_ops; node.stream_ops = this.stream_ops; return node; }; BFSEmscriptenFS.prototype.getMode = function (path) { var stat; try { stat = fs.lstatSync(path); } catch (e) { if (!e.code) throw e; throw new FS.ErrnoError(ERRNO_CODES[e.code]); } return stat.mode; }; BFSEmscriptenFS.prototype.realPath = function (node) { var parts = []; while (node.parent !== node) { parts.push(node.name); node = node.parent; } parts.push(node.mount.opts.root); parts.reverse(); return PATH.join.apply(null, parts); }; BFSEmscriptenFS.prototype.flagsToPermissionString = function (flags) { if (flags in this.flagsToPermissionStringMap) { return this.flagsToPermissionStringMap[flags]; } else { return flags; } }; return BFSEmscriptenFS; })(); exports.BFSEmscriptenFS = BFSEmscriptenFS; // Make it available on the global BrowserFS object. BrowserFS['EmscriptenFS'] = BFSEmscriptenFS; }); //# sourceMappingURL=emscripten_fs.js.map ; var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; define('core/file_system',["require", "exports", './api_error', './file_flag', './node_path', './buffer'], function(require, exports, api_error, file_flag, node_path, buffer) { var ApiError = api_error.ApiError; var ErrorCode = api_error.ErrorCode; var path = node_path.path; var Buffer = buffer.Buffer; var ActionType = file_flag.ActionType; /** * Basic filesystem class. Most filesystems should extend this class, as it * provides default implementations for a handful of methods. */ var BaseFileSystem = (function () { function BaseFileSystem() { } BaseFileSystem.prototype.supportsLinks = function () { return false; }; BaseFileSystem.prototype.diskSpace = function (p, cb) { cb(0, 0); }; /** * Opens the file at path p with the given flag. The file must exist. * @param p The path to open. * @param flag The flag to use when opening the file. */ BaseFileSystem.prototype.openFile = function (p, flag, cb) { throw new ApiError(14 /* ENOTSUP */); }; /** * Create the file at path p with the given mode. Then, open it with the given * flag. */ BaseFileSystem.prototype.createFile = function (p, flag, mode, cb) { throw new ApiError(14 /* ENOTSUP */); }; BaseFileSystem.prototype.open = function (p, flag, mode, cb) { var _this = this; var must_be_file = function (e, stats) { if (e) { switch (flag.pathNotExistsAction()) { case 3 /* CREATE_FILE */: // Ensure parent exists. return _this.stat(path.dirname(p), false, function (e, parentStats) { if (e) { cb(e); } else if (!parentStats.isDirectory()) { cb(new ApiError(7 /* ENOTDIR */, path.dirname(p) + " is not a directory.")); } else { _this.createFile(p, flag, mode, cb); } }); case 1 /* THROW_EXCEPTION */: return cb(new ApiError(1 /* ENOENT */, "" + p + " doesn't exist.")); default: return cb(new ApiError(9 /* EINVAL */, 'Invalid FileFlag object.')); } } else { // File exists. if (stats.isDirectory()) { return cb(new ApiError(8 /* EISDIR */, p + " is a directory.")); } switch (flag.pathExistsAction()) { case 1 /* THROW_EXCEPTION */: return cb(new ApiError(6 /* EEXIST */, p + " already exists.")); case 2 /* TRUNCATE_FILE */: // NOTE: In a previous implementation, we deleted the file and // re-created it. However, this created a race condition if another // asynchronous request was trying to read the file, as the file // would not exist for a small period of time. return _this.openFile(p, flag, function (e, fd) { if (e) { cb(e); } else { fd.truncate(0, function () { fd.sync(function () { cb(null, fd); }); }); } }); case 0 /* NOP */: return _this.openFile(p, flag, cb); default: return cb(new ApiError(9 /* EINVAL */, 'Invalid FileFlag object.')); } } }; this.stat(p, false, must_be_file); }; BaseFileSystem.prototype.rename = function (oldPath, newPath, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFileSystem.prototype.renameSync = function (oldPath, newPath) { throw new ApiError(14 /* ENOTSUP */); }; BaseFileSystem.prototype.stat = function (p, isLstat, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFileSystem.prototype.statSync = function (p, isLstat) { throw new ApiError(14 /* ENOTSUP */); }; /** * Opens the file at path p with the given flag. The file must exist. * @param p The path to open. * @param flag The flag to use when opening the file. * @return A File object corresponding to the opened file. */ BaseFileSystem.prototype.openFileSync = function (p, flag) { throw new ApiError(14 /* ENOTSUP */); }; /** * Create the file at path p with the given mode. Then, open it with the given * flag. */ BaseFileSystem.prototype.createFileSync = function (p, flag, mode) { throw new ApiError(14 /* ENOTSUP */); }; BaseFileSystem.prototype.openSync = function (p, flag, mode) { // Check if the path exists, and is a file. var stats; try { stats = this.statSync(p, false); } catch (e) { switch (flag.pathNotExistsAction()) { case 3 /* CREATE_FILE */: // Ensure parent exists. var parentStats = this.statSync(path.dirname(p), false); if (!parentStats.isDirectory()) { throw new ApiError(7 /* ENOTDIR */, path.dirname(p) + " is not a directory."); } return this.createFileSync(p, flag, mode); case 1 /* THROW_EXCEPTION */: throw new ApiError(1 /* ENOENT */, "" + p + " doesn't exist."); default: throw new ApiError(9 /* EINVAL */, 'Invalid FileFlag object.'); } } // File exists. if (stats.isDirectory()) { throw new ApiError(8 /* EISDIR */, p + " is a directory."); } switch (flag.pathExistsAction()) { case 1 /* THROW_EXCEPTION */: throw new ApiError(6 /* EEXIST */, p + " already exists."); case 2 /* TRUNCATE_FILE */: // Delete file. this.unlinkSync(p); // Create file. Use the same mode as the old file. // Node itself modifies the ctime when this occurs, so this action // will preserve that behavior if the underlying file system // supports those properties. return this.createFileSync(p, flag, stats.mode); case 0 /* NOP */: return this.openFileSync(p, flag); default: throw new ApiError(9 /* EINVAL */, 'Invalid FileFlag object.'); } }; BaseFileSystem.prototype.unlink = function (p, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFileSystem.prototype.unlinkSync = function (p) { throw new ApiError(14 /* ENOTSUP */); }; BaseFileSystem.prototype.rmdir = function (p, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFileSystem.prototype.rmdirSync = function (p) { throw new ApiError(14 /* ENOTSUP */); }; BaseFileSystem.prototype.mkdir = function (p, mode, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFileSystem.prototype.mkdirSync = function (p, mode) { throw new ApiError(14 /* ENOTSUP */); }; BaseFileSystem.prototype.readdir = function (p, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFileSystem.prototype.readdirSync = function (p) { throw new ApiError(14 /* ENOTSUP */); }; BaseFileSystem.prototype.exists = function (p, cb) { this.stat(p, null, function (err) { cb(err == null); }); }; BaseFileSystem.prototype.existsSync = function (p) { try { this.statSync(p, true); return true; } catch (e) { return false; } }; BaseFileSystem.prototype.realpath = function (p, cache, cb) { if (this.supportsLinks()) { // The path could contain symlinks. Split up the path, // resolve any symlinks, return the resolved string. var splitPath = p.split(path.sep); for (var i = 0; i < splitPath.length; i++) { var addPaths = splitPath.slice(0, i + 1); splitPath[i] = path.join.apply(null, addPaths); } } else { // No symlinks. We just need to verify that it exists. this.exists(p, function (doesExist) { if (doesExist) { cb(null, p); } else { cb(new ApiError(1 /* ENOENT */, "File " + p + " not found.")); } }); } }; BaseFileSystem.prototype.realpathSync = function (p, cache) { if (this.supportsLinks()) { // The path could contain symlinks. Split up the path, // resolve any symlinks, return the resolved string. var splitPath = p.split(path.sep); for (var i = 0; i < splitPath.length; i++) { var addPaths = splitPath.slice(0, i + 1); splitPath[i] = path.join.apply(null, addPaths); } } else { // No symlinks. We just need to verify that it exists. if (this.existsSync(p)) { return p; } else { throw new ApiError(1 /* ENOENT */, "File " + p + " not found."); } } }; BaseFileSystem.prototype.truncate = function (p, len, cb) { this.open(p, file_flag.FileFlag.getFileFlag('r+'), 0x1a4, (function (er, fd) { if (er) { return cb(er); } fd.truncate(len, (function (er) { fd.close((function (er2) { cb(er || er2); })); })); })); }; BaseFileSystem.prototype.truncateSync = function (p, len) { var fd = this.openSync(p, file_flag.FileFlag.getFileFlag('r+'), 0x1a4); try { fd.truncateSync(len); } catch (e) { throw e; } finally { fd.closeSync(); } }; BaseFileSystem.prototype.readFile = function (fname, encoding, flag, cb) { // Wrap cb in file closing code. var oldCb = cb; // Get file. this.open(fname, flag, 0x1a4, function (err, fd) { if (err) { return cb(err); } cb = function (err, arg) { fd.close(function (err2) { if (err == null) { err = err2; } return oldCb(err, arg); }); }; fd.stat(function (err, stat) { if (err != null) { return cb(err); } // Allocate buffer. var buf = new Buffer(stat.size); fd.read(buf, 0, stat.size, 0, function (err) { if (err != null) { return cb(err); } else if (encoding === null) { return cb(err, buf); } try { cb(null, buf.toString(encoding)); } catch (e) { cb(e); } }); }); }); }; BaseFileSystem.prototype.readFileSync = function (fname, encoding, flag) { // Get file. var fd = this.openSync(fname, flag, 0x1a4); try { var stat = fd.statSync(); // Allocate buffer. var buf = new Buffer(stat.size); fd.readSync(buf, 0, stat.size, 0); fd.closeSync(); if (encoding === null) { return buf; } return buf.toString(encoding); } finally { fd.closeSync(); } }; BaseFileSystem.prototype.writeFile = function (fname, data, encoding, flag, mode, cb) { // Wrap cb in file closing code. var oldCb = cb; // Get file. this.open(fname, flag, 0x1a4, function (err, fd) { if (err != null) { return cb(err); } cb = function (err) { fd.close(function (err2) { oldCb(err != null ? err : err2); }); }; try { if (typeof data === 'string') { data = new Buffer(data, encoding); } } catch (e) { return cb(e); } // Write into file. fd.write(data, 0, data.length, 0, cb); }); }; BaseFileSystem.prototype.writeFileSync = function (fname, data, encoding, flag, mode) { // Get file. var fd = this.openSync(fname, flag, mode); try { if (typeof data === 'string') { data = new Buffer(data, encoding); } // Write into file. fd.writeSync(data, 0, data.length, 0); } finally { fd.closeSync(); } }; BaseFileSystem.prototype.appendFile = function (fname, data, encoding, flag, mode, cb) { // Wrap cb in file closing code. var oldCb = cb; this.open(fname, flag, mode, function (err, fd) { if (err != null) { return cb(err); } cb = function (err) { fd.close(function (err2) { oldCb(err != null ? err : err2); }); }; if (typeof data === 'string') { data = new Buffer(data, encoding); } fd.write(data, 0, data.length, null, cb); }); }; BaseFileSystem.prototype.appendFileSync = function (fname, data, encoding, flag, mode) { var fd = this.openSync(fname, flag, mode); try { if (typeof data === 'string') { data = new Buffer(data, encoding); } fd.writeSync(data, 0, data.length, null); } finally { fd.closeSync(); } }; BaseFileSystem.prototype.chmod = function (p, isLchmod, mode, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFileSystem.prototype.chmodSync = function (p, isLchmod, mode) { throw new ApiError(14 /* ENOTSUP */); }; BaseFileSystem.prototype.chown = function (p, isLchown, uid, gid, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFileSystem.prototype.chownSync = function (p, isLchown, uid, gid) { throw new ApiError(14 /* ENOTSUP */); }; BaseFileSystem.prototype.utimes = function (p, atime, mtime, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFileSystem.prototype.utimesSync = function (p, atime, mtime) { throw new ApiError(14 /* ENOTSUP */); }; BaseFileSystem.prototype.link = function (srcpath, dstpath, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFileSystem.prototype.linkSync = function (srcpath, dstpath) { throw new ApiError(14 /* ENOTSUP */); }; BaseFileSystem.prototype.symlink = function (srcpath, dstpath, type, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFileSystem.prototype.symlinkSync = function (srcpath, dstpath, type) { throw new ApiError(14 /* ENOTSUP */); }; BaseFileSystem.prototype.readlink = function (p, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFileSystem.prototype.readlinkSync = function (p) { throw new ApiError(14 /* ENOTSUP */); }; return BaseFileSystem; })(); exports.BaseFileSystem = BaseFileSystem; /** * Implements the asynchronous API in terms of the synchronous API. * @class SynchronousFileSystem */ var SynchronousFileSystem = (function (_super) { __extends(SynchronousFileSystem, _super); function SynchronousFileSystem() { _super.apply(this, arguments); } SynchronousFileSystem.prototype.supportsSynch = function () { return true; }; SynchronousFileSystem.prototype.rename = function (oldPath, newPath, cb) { try { this.renameSync(oldPath, newPath); cb(); } catch (e) { cb(e); } }; SynchronousFileSystem.prototype.stat = function (p, isLstat, cb) { try { cb(null, this.statSync(p, isLstat)); } catch (e) { cb(e); } }; SynchronousFileSystem.prototype.open = function (p, flags, mode, cb) { try { cb(null, this.openSync(p, flags, mode)); } catch (e) { cb(e); } }; SynchronousFileSystem.prototype.unlink = function (p, cb) { try { this.unlinkSync(p); cb(); } catch (e) { cb(e); } }; SynchronousFileSystem.prototype.rmdir = function (p, cb) { try { this.rmdirSync(p); cb(); } catch (e) { cb(e); } }; SynchronousFileSystem.prototype.mkdir = function (p, mode, cb) { try { this.mkdirSync(p, mode); cb(); } catch (e) { cb(e); } }; SynchronousFileSystem.prototype.readdir = function (p, cb) { try { cb(null, this.readdirSync(p)); } catch (e) { cb(e); } }; SynchronousFileSystem.prototype.chmod = function (p, isLchmod, mode, cb) { try { this.chmodSync(p, isLchmod, mode); cb(); } catch (e) { cb(e); } }; SynchronousFileSystem.prototype.chown = function (p, isLchown, uid, gid, cb) { try { this.chownSync(p, isLchown, uid, gid); cb(); } catch (e) { cb(e); } }; SynchronousFileSystem.prototype.utimes = function (p, atime, mtime, cb) { try { this.utimesSync(p, atime, mtime); cb(); } catch (e) { cb(e); } }; SynchronousFileSystem.prototype.link = function (srcpath, dstpath, cb) { try { this.linkSync(srcpath, dstpath); cb(); } catch (e) { cb(e); } }; SynchronousFileSystem.prototype.symlink = function (srcpath, dstpath, type, cb) { try { this.symlinkSync(srcpath, dstpath, type); cb(); } catch (e) { cb(e); } }; SynchronousFileSystem.prototype.readlink = function (p, cb) { try { cb(null, this.readlinkSync(p)); } catch (e) { cb(e); } }; return SynchronousFileSystem; })(BaseFileSystem); exports.SynchronousFileSystem = SynchronousFileSystem; }); //# sourceMappingURL=file_system.js.map ; define('core/node_fs_stats',["require", "exports"], function(require, exports) { /** * Indicates the type of the given file. Applied to 'mode'. */ (function (FileType) { FileType[FileType["FILE"] = 0x8000] = "FILE"; FileType[FileType["DIRECTORY"] = 0x4000] = "DIRECTORY"; FileType[FileType["SYMLINK"] = 0xA000] = "SYMLINK"; })(exports.FileType || (exports.FileType = {})); var FileType = exports.FileType; /** * Emulation of Node's `fs.Stats` object. * * Attribute descriptions are from `man 2 stat' * @see http://nodejs.org/api/fs.html#fs_class_fs_stats * @see http://man7.org/linux/man-pages/man2/stat.2.html * @class */ var Stats = (function () { /** * Provides information about a particular entry in the file system. * @param [Number] item_type type of the item (FILE, DIRECTORY, SYMLINK, or SOCKET) * @param [Number] size Size of the item in bytes. For directories/symlinks, * this is normally the size of the struct that represents the item. * @param [Number] mode Unix-style file mode (e.g. 0o644) * @param [Date?] atime time of last access * @param [Date?] mtime time of last modification * @param [Date?] ctime time of creation */ function Stats(item_type, size, mode, atime, mtime, ctime) { if (typeof atime === "undefined") { atime = new Date(); } if (typeof mtime === "undefined") { mtime = new Date(); } if (typeof ctime === "undefined") { ctime = new Date(); } this.size = size; this.mode = mode; this.atime = atime; this.mtime = mtime; this.ctime = ctime; /** * UNSUPPORTED ATTRIBUTES * I assume no one is going to need these details, although we could fake * appropriate values if need be. */ // ID of device containing file this.dev = 0; // inode number this.ino = 0; // device ID (if special file) this.rdev = 0; // number of hard links this.nlink = 1; // blocksize for file system I/O this.blksize = 4096; // @todo Maybe support these? atm, it's a one-user filesystem. // user ID of owner this.uid = 0; // group ID of owner this.gid = 0; if (this.mode == null) { switch (item_type) { case 32768 /* FILE */: this.mode = 0x1a4; break; case 16384 /* DIRECTORY */: default: this.mode = 0x1ff; } } // number of 512B blocks allocated this.blocks = Math.ceil(size / 512); // Check if mode also includes top-most bits, which indicate the file's // type. if (this.mode < 0x1000) { this.mode |= item_type; } } /** * **Nonstandard**: Clone the stats object. * @return [BrowserFS.node.fs.Stats] */ Stats.prototype.clone = function () { return new Stats(this.mode & 0xF000, this.size, this.mode & 0xFFF, this.atime, this.mtime, this.ctime); }; /** * @return [Boolean] True if this item is a file. */ Stats.prototype.isFile = function () { return (this.mode & 0xF000) === 32768 /* FILE */; }; /** * @return [Boolean] True if this item is a directory. */ Stats.prototype.isDirectory = function () { return (this.mode & 0xF000) === 16384 /* DIRECTORY */; }; /** * @return [Boolean] True if this item is a symbolic link (only valid through lstat) */ Stats.prototype.isSymbolicLink = function () { return (this.mode & 0xF000) === 40960 /* SYMLINK */; }; /** * Change the mode of the file. We use this helper function to prevent messing * up the type of the file, which is encoded in mode. */ Stats.prototype.chmod = function (mode) { this.mode = (this.mode & 0xF000) | mode; }; // We don't support the following types of files. Stats.prototype.isSocket = function () { return false; }; Stats.prototype.isBlockDevice = function () { return false; }; Stats.prototype.isCharacterDevice = function () { return false; }; Stats.prototype.isFIFO = function () { return false; }; return Stats; })(); exports.Stats = Stats; }); //# sourceMappingURL=node_fs_stats.js.map ; define('generic/inode',["require", "exports", '../core/node_fs_stats', '../core/buffer'], function(require, exports, node_fs_stats, buffer) { /** * Generic inode definition that can easily be serialized. */ var Inode = (function () { function Inode(id, size, mode, atime, mtime, ctime) { this.id = id; this.size = size; this.mode = mode; this.atime = atime; this.mtime = mtime; this.ctime = ctime; } /** * Handy function that converts the Inode to a Node Stats object. */ Inode.prototype.toStats = function () { return new node_fs_stats.Stats((this.mode & 0xF000) === 16384 /* DIRECTORY */ ? 16384 /* DIRECTORY */ : 32768 /* FILE */, this.size, this.mode, new Date(this.atime), new Date(this.mtime), new Date(this.ctime)); }; /** * Get the size of this Inode, in bytes. */ Inode.prototype.getSize = function () { // ASSUMPTION: ID is ASCII (1 byte per char). return 30 + this.id.length; }; /** * Writes the inode into the start of the buffer. */ Inode.prototype.toBuffer = function (buff) { if (typeof buff === "undefined") { buff = new buffer.Buffer(this.getSize()); } buff.writeUInt32LE(this.size, 0); buff.writeUInt16LE(this.mode, 4); buff.writeDoubleLE(this.atime, 6); buff.writeDoubleLE(this.mtime, 14); buff.writeDoubleLE(this.ctime, 22); buff.write(this.id, 30, this.id.length, 'ascii'); return buff; }; /** * Updates the Inode using information from the stats object. Used by file * systems at sync time, e.g.: * - Program opens file and gets a File object. * - Program mutates file. File object is responsible for maintaining * metadata changes locally -- typically in a Stats object. * - Program closes file. File object's metadata changes are synced with the * file system. * @return True if any changes have occurred. */ Inode.prototype.update = function (stats) { var hasChanged = false; if (this.size !== stats.size) { this.size = stats.size; hasChanged = true; } if (this.mode !== stats.mode) { this.mode = stats.mode; hasChanged = true; } var atimeMs = stats.atime.getTime(); if (this.atime !== atimeMs) { this.atime = atimeMs; hasChanged = true; } var mtimeMs = stats.mtime.getTime(); if (this.mtime !== mtimeMs) { this.mtime = mtimeMs; hasChanged = true; } var ctimeMs = stats.ctime.getTime(); if (this.ctime !== ctimeMs) { this.ctime = ctimeMs; hasChanged = true; } return hasChanged; }; /** * Converts the buffer into an Inode. */ Inode.fromBuffer = function (buffer) { if (buffer === undefined) { throw new Error("NO"); } return new Inode(buffer.toString('ascii', 30), buffer.readUInt32LE(0), buffer.readUInt16LE(4), buffer.readDoubleLE(6), buffer.readDoubleLE(14), buffer.readDoubleLE(22)); }; // XXX: Copied from Stats. Should reconcile these two into something more // compact. /** * @return [Boolean] True if this item is a file. */ Inode.prototype.isFile = function () { return (this.mode & 0xF000) === 32768 /* FILE */; }; /** * @return [Boolean] True if this item is a directory. */ Inode.prototype.isDirectory = function () { return (this.mode & 0xF000) === 16384 /* DIRECTORY */; }; return Inode; })(); return Inode; }); //# sourceMappingURL=inode.js.map ; define('core/file',["require", "exports", './api_error'], function(require, exports, api_error) { var ApiError = api_error.ApiError; var ErrorCode = api_error.ErrorCode; /** * Base class that contains shared implementations of functions for the file * object. * @class */ var BaseFile = (function () { function BaseFile() { } BaseFile.prototype.sync = function (cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFile.prototype.syncSync = function () { throw new ApiError(14 /* ENOTSUP */); }; BaseFile.prototype.datasync = function (cb) { this.sync(cb); }; BaseFile.prototype.datasyncSync = function () { return this.syncSync(); }; BaseFile.prototype.chown = function (uid, gid, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFile.prototype.chownSync = function (uid, gid) { throw new ApiError(14 /* ENOTSUP */); }; BaseFile.prototype.chmod = function (mode, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFile.prototype.chmodSync = function (mode) { throw new ApiError(14 /* ENOTSUP */); }; BaseFile.prototype.utimes = function (atime, mtime, cb) { cb(new ApiError(14 /* ENOTSUP */)); }; BaseFile.prototype.utimesSync = function (atime, mtime) { throw new ApiError(14 /* ENOTSUP */); }; return BaseFile; })(); exports.BaseFile = BaseFile; }); //# sourceMappingURL=file.js.map ; var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; define('generic/preload_file',["require", "exports", '../core/file', '../core/buffer', '../core/api_error', '../core/node_fs'], function(require, exports, file, buffer, api_error, node_fs) { var ApiError = api_error.ApiError; var ErrorCode = api_error.ErrorCode; var fs = node_fs.fs; var Buffer = buffer.Buffer; /** * An implementation of the File interface that operates on a file that is * completely in-memory. PreloadFiles are backed by a Buffer. * * This is also an abstract class, as it lacks an implementation of 'sync' and * 'close'. Each filesystem that wishes to use this file representation must * extend this class and implement those two methods. * @todo 'close' lever that disables functionality once closed. */ var PreloadFile = (function (_super) { __extends(PreloadFile, _super); /** * Creates a file with the given path and, optionally, the given contents. Note * that, if contents is specified, it will be mutated by the file! * @param [BrowserFS.FileSystem] _fs The file system that created the file. * @param [String] _path * @param [BrowserFS.FileMode] _mode The mode that the file was opened using. * Dictates permissions and where the file pointer starts. * @param [BrowserFS.node.fs.Stats] _stat The stats object for the given file. * PreloadFile will mutate this object. Note that this object must contain * the appropriate mode that the file was opened as. * @param [BrowserFS.node.Buffer?] contents A buffer containing the entire * contents of the file. PreloadFile will mutate this buffer. If not * specified, we assume it is a new file. */ function PreloadFile(_fs, _path, _flag, _stat, contents) { _super.call(this); this._pos = 0; this._fs = _fs; this._path = _path; this._flag = _flag; this._stat = _stat; if (contents != null) { this._buffer = contents; } else { // Empty buffer. It'll expand once we write stuff to it. this._buffer = new Buffer(0); } // Note: This invariant is *not* maintained once the file starts getting // modified. if (this._stat.size !== this._buffer.length) { throw new Error("Invalid buffer: Buffer is " + this._buffer.length + " long, yet Stats object specifies that file is " + this._stat.size + " long."); } } /** * Get the path to this file. * @return [String] The path to the file. */ PreloadFile.prototype.getPath = function () { return this._path; }; /** * Get the current file position. * * We emulate the following bug mentioned in the Node documentation: * > On Linux, positional writes don't work when the file is opened in append * mode. The kernel ignores the position argument and always appends the data * to the end of the file. * @return [Number] The current file position. */ PreloadFile.prototype.getPos = function () { if (this._flag.isAppendable()) { return this._stat.size; } return this._pos; }; /** * Advance the current file position by the indicated number of positions. * @param [Number] delta */ PreloadFile.prototype.advancePos = function (delta) { return this._pos += delta; }; /** * Set the file position. * @param [Number] newPos */ PreloadFile.prototype.setPos = function (newPos) { return this._pos = newPos; }; /** * **Core**: Asynchronous sync. Must be implemented by subclasses of this * class. * @param [Function(BrowserFS.ApiError)] cb */ PreloadFile.prototype.sync = function (cb) { try { this.syncSync(); cb(); } catch (e) { cb(e); } }; /** * **Core**: Synchronous sync. */ PreloadFile.prototype.syncSync = function () { throw new ApiError(14 /* ENOTSUP */); }; /** * **Core**: Asynchronous close. Must be implemented by subclasses of this * class. * @param [Function(BrowserFS.ApiError)] cb */ PreloadFile.prototype.close = function (cb) { try { this.closeSync(); cb(); } catch (e) { cb(e); } }; /** * **Core**: Synchronous close. */ PreloadFile.prototype.closeSync = function () { throw new ApiError(14 /* ENOTSUP */); }; /** * Asynchronous `stat`. * @param [Function(BrowserFS.ApiError, BrowserFS.node.fs.Stats)] cb */ PreloadFile.prototype.stat = function (cb) { try { cb(null, this._stat.clone()); } catch (e) { cb(e); } }; /** * Synchronous `stat`. */ PreloadFile.prototype.statSync = function () { return this._stat.clone(); }; /** * Asynchronous truncate. * @param [Number] len * @param [Function(BrowserFS.ApiError)] cb */ PreloadFile.prototype.truncate = function (len, cb) { try { this.truncateSync(len); if (this._flag.isSynchronous() && !fs.getRootFS().supportsSynch()) { this.sync(cb); } cb(); } catch (e) { return cb(e); } }; /** * Synchronous truncate. * @param [Number] len */ PreloadFile.prototype.truncateSync = function (len) { if (!this._flag.isWriteable()) { throw new ApiError(0 /* EPERM */, 'File not opened with a writeable mode.'); } this._stat.mtime = new Date(); if (len > this._buffer.length) { var buf = new Buffer(len - this._buffer.length); buf.fill(0); // Write will set @_stat.size for us. this.writeSync(buf, 0, buf.length, this._buffer.length); if (this._flag.isSynchronous() && fs.getRootFS().supportsSynch()) { this.syncSync(); } return; } this._stat.size = len; // Truncate buffer to 'len'. var newBuff = new Buffer(len); this._buffer.copy(newBuff, 0, 0, len); this._buffer = newBuff; if (this._flag.isSynchronous() && fs.getRootFS().supportsSynch()) { this.syncSync(); } }; /** * Write buffer to the file. * Note that it is unsafe to use fs.write multiple times on the same file * without waiting for the callback. * @param [BrowserFS.node.Buffer] buffer Buffer containing the data to write to * the file. * @param [Number] offset Offset in the buffer to start reading data from. * @param [Number] length The amount of bytes to write to the file. * @param [Number] position Offset from the beginning of the file where this * data should be written. If position is null, the data will be written at * the current position. * @param [Function(BrowserFS.ApiError, Number, BrowserFS.node.Buffer)] * cb The number specifies the number of bytes written into the file. */ PreloadFile.prototype.write = function (buffer, offset, length, position, cb) { try { cb(null, this.writeSync(buffer, offset, length, position), buffer); } catch (e) { cb(e); } }; /** * Write buffer to the file. * Note that it is unsafe to use fs.writeSync multiple times on the same file * without waiting for the callback. * @param [BrowserFS.node.Buffer] buffer Buffer containing the data to write to * the file. * @param [Number] offset Offset in the buffer to start reading data from. * @param [Number] length The amount of bytes to write to the file. * @param [Number] position Offset from the beginning of the file where this * data should be written. If position is null, the data will be written at * the current position. * @return [Number] */ PreloadFile.prototype.writeSync = function (buffer, offset, length, position) { if (position == null) { position = this.getPos(); } if (!this._flag.isWriteable()) { throw new ApiError(0 /* EPERM */, 'File not opened with a writeable mode.'); } var endFp = position + length; if (endFp > this._stat.size) { this._stat.size = endFp; if (endFp > this._buffer.length) { // Extend the buffer! var newBuff = new Buffer(endFp); this._buffer.copy(newBuff); this._buffer = newBuff; } } var len = buffer.copy(this._buffer, position, offset, offset + length); this._stat.mtime = new Date(); if (this._flag.isSynchronous()) { this.syncSync(); return len; } this.setPos(position + len); return len; }; /** * Read data from the file. * @param [BrowserFS.node.Buffer] buffer The buffer that the data will be * written to. * @param [Number] offset The offset within the buffer where writing will * start. * @param [Number] length An integer specifying the number of bytes to read. * @param [Number] position An integer specifying where to begin reading from * in the file. If position is null, data will be read from the current file * position. * @param [Function(BrowserFS.ApiError, Number, BrowserFS.node.Buffer)] cb The * number is the number of bytes read */ PreloadFile.prototype.read = function (buffer, offset, length, position, cb) { try { cb(null, this.readSync(buffer, offset, length, position), buffer); } catch (e) { cb(e); } }; /** * Read data from the file. * @param [BrowserFS.node.Buffer] buffer The buffer that the data will be * written to. * @param [Number] offset The offset within the buffer where writing will * start. * @param [Number] length An integer specifying the number of bytes to read. * @param [Number] position An integer specifying where to begin reading from * in the file. If position is null, data will be read from the current file * position. * @return [Number] */ PreloadFile.prototype.readSync = function (buffer, offset, length, position) { if (!this._flag.isReadable()) { throw new ApiError(0 /* EPERM */, 'File not opened with a readable mode.'); } if (position == null) { position = this.getPos(); } var endRead = position + length; if (endRead > this._stat.size) { length = this._stat.size - position; } var rv = this._buffer.copy(buffer, offset, position, position + length); this._stat.atime = new Date(); this._pos = position + length; return rv; }; /** * Asynchronous `fchmod`. * @param [Number|String] mode * @param [Function(BrowserFS.ApiError)] cb */ PreloadFile.prototype.chmod = function (mode, cb) { try { this.chmodSync(mode); cb(); } catch (e) { cb(e); } }; /** * Asynchronous `fchmod`. * @param [Number] mode */ PreloadFile.prototype.chmodSync = function (mode) { if (!this._fs.supportsProps()) { throw new ApiError(14 /* ENOTSUP */); } this._stat.chmod(mode); this.syncSync(); }; return PreloadFile; })(file.BaseFile); exports.PreloadFile = PreloadFile; /** * File class for the InMemory and XHR file systems. * Doesn't sync to anything, so it works nicely for memory-only files. */ var NoSyncFile = (function (_super) { __extends(NoSyncFile, _super); function NoSyncFile(_fs, _path, _flag, _stat, contents) { _super.call(this, _fs, _path, _flag, _stat, contents); } /** * Asynchronous sync. Doesn't do anything, simply calls the cb. * @param [Function(BrowserFS.ApiError)] cb */ NoSyncFile.prototype.sync = function (cb) { cb(); }; /** * Synchronous sync. Doesn't do anything. */ NoSyncFile.prototype.syncSync = function () { }; /** * Asynchronous close. Doesn't do anything, simply calls the cb. * @param [Function(BrowserFS.ApiError)] cb */ NoSyncFile.prototype.close = function (cb) { cb(); }; /** * Synchronous close. Doesn't do anything. */ NoSyncFile.prototype.closeSync = function () { }; return NoSyncFile; })(PreloadFile); exports.NoSyncFile = NoSyncFile; }); //# sourceMappingURL=preload_file.js.map ; var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; define('generic/key_value_filesystem',["require", "exports", '../core/file_system', '../core/api_error', '../core/node_fs_stats', '../core/node_path', '../generic/inode', '../core/buffer', '../generic/preload_file'], function(require, exports, file_system, api_error, node_fs_stats, node_path, Inode, buffer, preload_file) { var ROOT_NODE_ID = "/", path = node_path.path, ApiError = api_error.ApiError, Buffer = buffer.Buffer; /** * Generates a random ID. */ function GenerateRandomID() { // From http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } /** * Helper function. Checks if 'e' is defined. If so, it triggers the callback * with 'e' and returns false. Otherwise, returns true. */ function noError(e, cb) { if (e) { cb(e); return false; } return true; } /** * Helper function. Checks if 'e' is defined. If so, it aborts the transaction, * triggers the callback with 'e', and returns false. Otherwise, returns true. */ function noErrorTx(e, tx, cb) { if (e) { tx.abort(function () { cb(e); }); return false; } return true; } /** * A simple RW transaction for simple synchronous key-value stores. */ var SimpleSyncRWTransaction = (function () { function SimpleSyncRWTransaction(store) { this.store = store; /** * Stores data in the keys we modify prior to modifying them. * Allows us to roll back commits. */ this.originalData = {}; /** * List of keys modified in this transaction, if any. */ this.modifiedKeys = []; } /** * Stashes given key value pair into `originalData` if it doesn't already * exist. Allows us to stash values the program is requesting anyway to * prevent needless `get` requests if the program modifies the data later * on during the transaction. */ SimpleSyncRWTransaction.prototype.stashOldValue = function (key, value) { // Keep only the earliest value in the transaction. if (!this.originalData.hasOwnProperty(key)) { this.originalData[key] = value; } }; /** * Marks the given key as modified, and stashes its value if it has not been * stashed already. */ SimpleSyncRWTransaction.prototype.markModified = function (key) { if (this.modifiedKeys.indexOf(key) === -1) { this.modifiedKeys.push(key); if (!this.originalData.hasOwnProperty(key)) { this.originalData[key] = this.store.get(key); } } }; SimpleSyncRWTransaction.prototype.get = function (key) { var val = this.store.get(key); this.stashOldValue(key, val); return val; }; SimpleSyncRWTransaction.prototype.put = function (key, data, overwrite) { this.markModified(key); return this.store.put(key, data, overwrite); }; SimpleSyncRWTransaction.prototype.delete = function (key) { this.markModified(key); this.store.delete(key); }; SimpleSyncRWTransaction.prototype.commit = function () { }; SimpleSyncRWTransaction.prototype.abort = function () { // Rollback old values. var i, key, value; for (i = 0; i < this.modifiedKeys.length; i++) { key = this.modifiedKeys[i]; value = this.originalData[key]; if (value === null) { // Key didn't exist. this.store.delete(key); } else { // Key existed. Store old value. this.store.put(key, value, true); } } }; return SimpleSyncRWTransaction; })(); exports.SimpleSyncRWTransaction = SimpleSyncRWTransaction; var SyncKeyValueFile = (function (_super) { __extends(SyncKeyValueFile, _super); function SyncKeyValueFile(_fs, _path, _flag, _stat, contents) { _super.call(this, _fs, _path, _flag, _stat, contents); } SyncKeyValueFile.prototype.syncSync = function () { this._fs._syncSync(this._path, this._buffer, this._stat); }; SyncKeyValueFile.prototype.closeSync = function () { this.syncSync(); }; return SyncKeyValueFile; })(preload_file.PreloadFile); exports.SyncKeyValueFile = SyncKeyValueFile; /** * A "Synchronous key-value file system". Stores data to/retrieves data from an * underlying key-value store. * * We use a unique ID for each node in the file system. The root node has a * fixed ID. * @todo Introduce Node ID caching. * @todo Check modes. */ var SyncKeyValueFileSystem = (function (_super) { __extends(SyncKeyValueFileSystem, _super); function SyncKeyValueFileSystem(options) { _super.call(this); this.store = options.store; // INVARIANT: Ensure that the root exists. this.makeRootDirectory(); } SyncKeyValueFileSystem.isAvailable = function () { return true; }; SyncKeyValueFileSystem.prototype.getName = function () { return this.store.name(); }; SyncKeyValueFileSystem.prototype.isReadOnly = function () { return false; }; SyncKeyValueFileSystem.prototype.supportsSymlinks = function () { return false; }; SyncKeyValueFileSystem.prototype.supportsProps = function () { return false; }; SyncKeyValueFileSystem.prototype.supportsSynch = function () { return true; }; /** * Checks if the root directory exists. Creates it if it doesn't. */ SyncKeyValueFileSystem.prototype.makeRootDirectory = function () { var tx = this.store.beginTransaction('readwrite'); if (tx.get(ROOT_NODE_ID) === undefined) { // Create new inode. var currTime = (new Date()).getTime(), dirInode = new Inode(GenerateRandomID(), 4096, 511 | 16384 /* DIRECTORY */, currTime, currTime, currTime); // If the root doesn't exist, the first random ID shouldn't exist, // either. tx.put(dirInode.id, new Buffer("{}"), false); tx.put(ROOT_NODE_ID, dirInode.toBuffer(), false); tx.commit(); } }; /** * Helper function for findINode. * @param parent The parent directory of the file we are attempting to find. * @param filename The filename of the inode we are attempting to find, minus * the parent. * @return string The ID of the file's inode in the file system. */ SyncKeyValueFileSystem.prototype._findINode = function (tx, parent, filename) { var _this = this; var read_directory = function (inode) { // Get the root's directory listing. var dirList = _this.getDirListing(tx, parent, inode); // Get the file's ID. if (dirList[filename]) { return dirList[filename]; } else { throw ApiError.ENOENT(path.resolve(parent, filename)); } }; if (parent === '/') { if (filename === '') { // BASE CASE #1: Return the root's ID. return ROOT_NODE_ID; } else { // BASE CASE #2: Find the item in the root ndoe. return read_directory(this.getINode(tx, parent, ROOT_NODE_ID)); } } else { return read_directory(this.getINode(tx, parent + path.sep + filename, this._findINode(tx, path.dirname(parent), path.basename(parent)))); } }; /** * Finds the Inode of the given path. * @param p The path to look up. * @return The Inode of the path p. * @todo memoize/cache */ SyncKeyValueFileSystem.prototype.findINode = function (tx, p) { return this.getINode(tx, p, this._findINode(tx, path.dirname(p), path.basename(p))); }; /** * Given the ID of a node, retrieves the corresponding Inode. * @param tx The transaction to use. * @param p The corresponding path to the file (used for error messages). * @param id The ID to look up. */ SyncKeyValueFileSystem.prototype.getINode = function (tx, p, id) { var inode = tx.get(id); if (inode === undefined) { throw ApiError.ENOENT(p); } return Inode.fromBuffer(inode); }; /** * Given the Inode of a directory, retrieves the corresponding directory * listing. */ SyncKeyValueFileSystem.prototype.getDirListing = function (tx, p, inode) { if (!inode.isDirectory()) { throw ApiError.ENOTDIR(p); } var data = tx.get(inode.id); if (data === undefined) { throw ApiError.ENOENT(p); } return JSON.parse(data.toString()); }; /** * Creates a new node under a random ID. Retries 5 times before giving up in * the exceedingly unlikely chance that we try to reuse a random GUID. * @return The GUID that the data was stored under. */ SyncKeyValueFileSystem.prototype.addNewNode = function (tx, data) { var retries = 0, currId; while (retries < 5) { try { currId = GenerateRandomID(); tx.put(currId, data, false); return currId; } catch (e) { // Ignore and reroll. } } throw new ApiError(2 /* EIO */, 'Unable to commit data to key-value store.'); }; /** * Commits a new file (well, a FILE or a DIRECTORY) to the file system with * the given mode. * Note: This will commit the transaction. * @param p The path to the new file. * @param type The type of the new file. * @param mode The mode to create the new file with. * @param data The data to store at the file's data node. * @return The Inode for the new file. */ SyncKeyValueFileSystem.prototype.commitNewFile = function (tx, p, type, mode, data) { var parentDir = path.dirname(p), fname = path.basename(p), parentNode = this.findINode(tx, parentDir), dirListing = this.getDirListing(tx, parentDir, parentNode), currTime = (new Date()).getTime(); // Invariant: The root always exists. // If we don't check this prior to taking steps below, we will create a // file with name '' in root should p == '/'. if (p === '/') { throw ApiError.EEXIST(p); } // Check if file already exists. if (dirListing[fname]) { throw ApiError.EEXIST(p); } try { // Commit data. var dataId = this.addNewNode(tx, data), fileNode = new Inode(dataId, data.length, mode | type, currTime, currTime, currTime), fileNodeId = this.addNewNode(tx, fileNode.toBuffer()); // Update and commit parent directory listing. dirListing[fname] = fileNodeId; tx.put(parentNode.id, new Buffer(JSON.stringify(dirListing)), true); } catch (e) { tx.abort(); throw e; } tx.commit(); return fileNode; }; /** * Delete all contents stored in the file system. */ SyncKeyValueFileSystem.prototype.empty = function () { this.store.clear(); // INVARIANT: Root always exists. this.makeRootDirectory(); }; SyncKeyValueFileSystem.prototype.renameSync = function (oldPath, newPath) { var tx = this.store.beginTransaction('readwrite'), oldParent = path.dirname(oldPath), oldName = path.basename(oldPath), newParent = path.dirname(newPath), newName = path.basename(newPath), oldDirNode = this.findINode(tx, oldParent), oldDirList = this.getDirListing(tx, oldParent, oldDirNode); if (!oldDirList[oldName]) { throw ApiError.ENOENT(oldPath); } var nodeId = oldDirList[oldName]; delete oldDirList[oldName]; // Invariant: Can't move a folder inside itself. // This funny little hack ensures that the check passes only if oldPath // is a subpath of newParent. We append '/' to avoid matching folders that // are a substring of the bottom-most folder in the path. if ((newParent + '/').indexOf(oldPath + '/') === 0) { throw new ApiError(5 /* EBUSY */, oldParent); } // Add newPath to parent's directory listing. var newDirNode, newDirList; if (newParent === oldParent) { // Prevent us from re-grabbing the same directory listing, which still // contains oldName. newDirNode = oldDirNode; newDirList = oldDirList; } else { newDirNode = this.findINode(tx, newParent); newDirList = this.getDirListing(tx, newParent, newDirNode); } if (newDirList[newName]) { // If it's a file, delete it. var newNameNode = this.getINode(tx, newPath, newDirList[newName]); if (newNameNode.isFile()) { try { tx.delete(newNameNode.id); tx.delete(newDirList[newName]); } catch (e) { tx.abort(); throw e; } } else { throw ApiError.EPERM(newPath); } } newDirList[newName] = nodeId; try { tx.put(oldDirNode.id, new Buffer(JSON.stringify(oldDirList)), true); tx.put(newDirNode.id, new Buffer(JSON.stringify(newDirList)), true); } catch (e) { tx.abort(); throw e; } tx.commit(); }; SyncKeyValueFileSystem.prototype.statSync = function (p, isLstat) { // Get the inode to the item, convert it into a Stats object. return this.findINode(this.store.beginTransaction('readonly'), p).toStats(); }; SyncKeyValueFileSystem.prototype.createFileSync = function (p, flag, mode) { var tx = this.store.beginTransaction('readwrite'), data = new Buffer(0), newFile = this.commitNewFile(tx, p, 32768 /* FILE */, mode, data); // Open the file. return new SyncKeyValueFile(this, p, flag, newFile.toStats(), data); }; SyncKeyValueFileSystem.prototype.openFileSync = function (p, flag) { var tx = this.store.beginTransaction('readonly'), node = this.findINode(tx, p), data = tx.get(node.id); if (data === undefined) { throw ApiError.ENOENT(p); } return new SyncKeyValueFile(this, p, flag, node.toStats(), data); }; /** * Remove all traces of the given path from the file system. * @param p The path to remove from the file system. * @param isDir Does the path belong to a directory, or a file? * @todo Update mtime. */ SyncKeyValueFileSystem.prototype.removeEntry = function (p, isDir) { var tx = this.store.beginTransaction('readwrite'), parent = path.dirname(p), parentNode = this.findINode(tx, parent), parentListing = this.getDirListing(tx, parent, parentNode), fileName = path.basename(p); if (!parentListing[fileName]) { throw ApiError.ENOENT(p); } // Remove from directory listing of parent. var fileNodeId = parentListing[fileName]; delete parentListing[fileName]; // Get file inode. var fileNode = this.getINode(tx, p, fileNodeId); if (!isDir && fileNode.isDirectory()) { throw ApiError.EISDIR(p); } else if (isDir && !fileNode.isDirectory()) { throw ApiError.ENOTDIR(p); } try { // Delete data. tx.delete(fileNode.id); // Delete node. tx.delete(fileNodeId); // Update directory listing. tx.put(parentNode.id, new Buffer(JSON.stringify(parentListing)), true); } catch (e) { tx.abort(); throw e; } // Success. tx.commit(); }; SyncKeyValueFileSystem.prototype.unlinkSync = function (p) { this.removeEntry(p, false); }; SyncKeyValueFileSystem.prototype.rmdirSync = function (p) { this.removeEntry(p, true); }; SyncKeyValueFileSystem.prototype.mkdirSync = function (p, mode) { var tx = this.store.beginTransaction('readwrite'), data = new Buffer('{}'); this.commitNewFile(tx, p, 16384 /* DIRECTORY */, mode, data); }; SyncKeyValueFileSystem.prototype.readdirSync = function (p) { var tx = this.store.beginTransaction('readonly'); return Object.keys(this.getDirListing(tx, p, this.findINode(tx, p))); }; SyncKeyValueFileSystem.prototype._syncSync = function (p, data, stats) { // @todo Ensure mtime updates properly, and use that to determine if a data // update is required. var tx = this.store.beginTransaction('readwrite'), fileInodeId = this._findINode(tx, path.dirname(p), path.basename(p)), fileInode = this.getINode(tx, p, fileInodeId), inodeChanged = fileInode.update(stats); try { // Sync data. tx.put(fileInode.id, data, true); // Sync metadata. if (inodeChanged) { tx.put(fileInodeId, fileInode.toBuffer(), true); } } catch (e) { tx.abort(); throw e; } tx.commit(); }; return SyncKeyValueFileSystem; })(file_system.SynchronousFileSystem); exports.SyncKeyValueFileSystem = SyncKeyValueFileSystem; var AsyncKeyValueFile = (function (_super) { __extends(AsyncKeyValueFile, _super); function AsyncKeyValueFile(_fs, _path, _flag, _stat, contents) { _super.call(this, _fs, _path, _flag, _stat, contents); } AsyncKeyValueFile.prototype.sync = function (cb) { this._fs._sync(this._path, this._buffer, this._stat, cb); }; AsyncKeyValueFile.prototype.close = function (cb) { this.sync(cb); }; return AsyncKeyValueFile; })(preload_file.PreloadFile); exports.AsyncKeyValueFile = AsyncKeyValueFile; /** * An "Asynchronous key-value file system". Stores data to/retrieves data from * an underlying asynchronous key-value store. */ var AsyncKeyValueFileSystem = (function (_super) { __extends(AsyncKeyValueFileSystem, _super); function AsyncKeyValueFileSystem() { _super.apply(this, arguments); } /** * Initializes the file system. Typically called by subclasses' async * constructors. */ AsyncKeyValueFileSystem.prototype.init = function (store, cb) { this.store = store; // INVARIANT: Ensure that the root exists. this.makeRootDirectory(cb); }; AsyncKeyValueFileSystem.isAvailable = function () { return true; }; AsyncKeyValueFileSystem.prototype.getName = function () { return this.store.name(); }; AsyncKeyValueFileSystem.prototype.isReadOnly = function () { return false; }; AsyncKeyValueFileSystem.prototype.supportsSymlinks = function () { return false; }; AsyncKeyValueFileSystem.prototype.supportsProps = function () { return false; }; AsyncKeyValueFileSystem.prototype.supportsSynch = function () { return false; }; /** * Checks if the root directory exists. Creates it if it doesn't. */ AsyncKeyValueFileSystem.prototype.makeRootDirectory = function (cb) { var tx = this.store.beginTransaction('readwrite'); tx.get(ROOT_NODE_ID, function (e, data) { if (e || data === undefined) { // Create new inode. var currTime = (new Date()).getTime(), dirInode = new Inode(GenerateRandomID(), 4096, 511 | 16384 /* DIRECTORY */, currTime, currTime, currTime); // If the root doesn't exist, the first random ID shouldn't exist, // either. tx.put(dirInode.id, new Buffer("{}"), false, function (e) { if (noErrorTx(e, tx, cb)) { tx.put(ROOT_NODE_ID, dirInode.toBuffer(), false, function (e) { if (e) { tx.abort(function () { cb(e); }); } else { tx.commit(cb); } }); } }); } else { // We're good. tx.commit(cb); } }); }; /** * Helper function for findINode. * @param parent The parent directory of the file we are attempting to find. * @param filename The filename of the inode we are attempting to find, minus * the parent. * @param cb Passed an error or the ID of the file's inode in the file system. */ AsyncKeyValueFileSystem.prototype._findINode = function (tx, parent, filename, cb) { var _this = this; var handle_directory_listings = function (e, inode, dirList) { if (e) { cb(e); } else if (dirList[filename]) { cb(null, dirList[filename]); } else { cb(ApiError.ENOENT(path.resolve(parent, filename))); } }; if (parent === '/') { if (filename === '') { // BASE CASE #1: Return the root's ID. cb(null, ROOT_NODE_ID); } else { // BASE CASE #2: Find the item in the root node. this.getINode(tx, parent, ROOT_NODE_ID, function (e, inode) { if (noError(e, cb)) { _this.getDirListing(tx, parent, inode, function (e, dirList) { // handle_directory_listings will handle e for us. handle_directory_listings(e, inode, dirList); }); } }); } } else { // Get the parent directory's INode, and find the file in its directory // listing. this.findINodeAndDirListing(tx, parent, handle_directory_listings); } }; /** * Finds the Inode of the given path. * @param p The path to look up. * @param cb Passed an error or the Inode of the path p. * @todo memoize/cache */ AsyncKeyValueFileSystem.prototype.findINode = function (tx, p, cb) { var _this = this; this._findINode(tx, path.dirname(p), path.basename(p), function (e, id) { if (noError(e, cb)) { _this.getINode(tx, p, id, cb); } }); }; /** * Given the ID of a node, retrieves the corresponding Inode. * @param tx The transaction to use. * @param p The corresponding path to the file (used for error messages). * @param id The ID to look up. * @param cb Passed an error or the inode under the given id. */ AsyncKeyValueFileSystem.prototype.getINode = function (tx, p, id, cb) { tx.get(id, function (e, data) { if (noError(e, cb)) { if (data === undefined) { cb(ApiError.ENOENT(p)); } else { cb(null, Inode.fromBuffer(data)); } } }); }; /** * Given the Inode of a directory, retrieves the corresponding directory * listing. */ AsyncKeyValueFileSystem.prototype.getDirListing = function (tx, p, inode, cb) { if (!inode.isDirectory()) { cb(ApiError.ENOTDIR(p)); } else { tx.get(inode.id, function (e, data) { if (noError(e, cb)) { try { cb(null, JSON.parse(data.toString())); } catch (e) { // Occurs when data is undefined, or corresponds to something other // than a directory listing. The latter should never occur unless // the file system is corrupted. cb(ApiError.ENOENT(p)); } } }); } }; /** * Given a path to a directory, retrieves the corresponding INode and * directory listing. */ AsyncKeyValueFileSystem.prototype.findINodeAndDirListing = function (tx, p, cb) { var _this = this; this.findINode(tx, p, function (e, inode) { if (noError(e, cb)) { _this.getDirListing(tx, p, inode, function (e, listing) { if (noError(e, cb)) { cb(null, inode, listing); } }); } }); }; /** * Adds a new node under a random ID. Retries 5 times before giving up in * the exceedingly unlikely chance that we try to reuse a random GUID. * @param cb Passed an error or the GUID that the data was stored under. */ AsyncKeyValueFileSystem.prototype.addNewNode = function (tx, data, cb) { var retries = 0, currId, reroll = function () { if (++retries === 5) { // Max retries hit. Return with an error. cb(new ApiError(2 /* EIO */, 'Unable to commit data to key-value store.')); } else { // Try again. currId = GenerateRandomID(); tx.put(currId, data, false, function (e, committed) { if (e || !committed) { reroll(); } else { // Successfully stored under 'currId'. cb(null, currId); } }); } }; reroll(); }; /** * Commits a new file (well, a FILE or a DIRECTORY) to the file system with * the given mode. * Note: This will commit the transaction. * @param p The path to the new file. * @param type The type of the new file. * @param mode The mode to create the new file with. * @param data The data to store at the file's data node. * @param cb Passed an error or the Inode for the new file. */ AsyncKeyValueFileSystem.prototype.commitNewFile = function (tx, p, type, mode, data, cb) { var _this = this; var parentDir = path.dirname(p), fname = path.basename(p), currTime = (new Date()).getTime(); // Invariant: The root always exists. // If we don't check this prior to taking steps below, we will create a // file with name '' in root should p == '/'. if (p === '/') { return cb(ApiError.EEXIST(p)); } // Let's build a pyramid of code! // Step 1: Get the parent directory's inode and directory listing this.findINodeAndDirListing(tx, parentDir, function (e, parentNode, dirListing) { if (noErrorTx(e, tx, cb)) { if (dirListing[fname]) { // File already exists. tx.abort(function () { cb(ApiError.EEXIST(p)); }); } else { // Step 2: Commit data to store. _this.addNewNode(tx, data, function (e, dataId) { if (noErrorTx(e, tx, cb)) { // Step 3: Commit the file's inode to the store. var fileInode = new Inode(dataId, data.length, mode | type, currTime, currTime, currTime); _this.addNewNode(tx, fileInode.toBuffer(), function (e, fileInodeId) { if (noErrorTx(e, tx, cb)) { // Step 4: Update parent directory's listing. dirListing[fname] = fileInodeId; tx.put(parentNode.id, new Buffer(JSON.stringify(dirListing)), true, function (e) { if (noErrorTx(e, tx, cb)) { // Step 5: Commit and return the new inode. tx.commit(function (e) { if (noErrorTx(e, tx, cb)) { cb(null, fileInode); } }); } }); } }); } }); } } }); }; /** * Delete all contents stored in the file system. */ AsyncKeyValueFileSystem.prototype.empty = function (cb) { var _this = this; this.store.clear(function (e) { if (noError(e, cb)) { // INVARIANT: Root always exists. _this.makeRootDirectory(cb); } }); }; AsyncKeyValueFileSystem.prototype.rename = function (oldPath, newPath, cb) { var _this = this; var tx = this.store.beginTransaction('readwrite'), oldParent = path.dirname(oldPath), oldName = path.basename(oldPath), newParent = path.dirname(newPath), newName = path.basename(newPath), inodes = {}, lists = {}, errorOccurred = false; // Invariant: Can't move a folder inside itself. // This funny little hack ensures that the check passes only if oldPath // is a subpath of newParent. We append '/' to avoid matching folders that // are a substring of the bottom-most folder in the path. if ((newParent + '/').indexOf(oldPath + '/') === 0) { return cb(new ApiError(5 /* EBUSY */, oldParent)); } /** * Responsible for Phase 2 of the rename operation: Modifying and * committing the directory listings. Called once we have successfully * retrieved both the old and new parent's inodes and listings. */ var theOleSwitcharoo = function () { // Sanity check: Ensure both paths are present, and no error has occurred. if (errorOccurred || !lists.hasOwnProperty(oldParent) || !lists.hasOwnProperty(newParent)) { return; } var oldParentList = lists[oldParent], oldParentINode = inodes[oldParent], newParentList = lists[newParent], newParentINode = inodes[newParent]; // Delete file from old parent. if (!oldParentList[oldName]) { cb(ApiError.ENOENT(oldPath)); } else { var fileId = oldParentList[oldName]; delete oldParentList[oldName]; // Finishes off the renaming process by adding the file to the new // parent. var completeRename = function () { newParentList[newName] = fileId; // Commit old parent's list. tx.put(oldParentINode.id, new Buffer(JSON.stringify(oldParentList)), true, function (e) { if (noErrorTx(e, tx, cb)) { if (oldParent === newParent) { // DONE! tx.commit(cb); } else { // Commit new parent's list. tx.put(newParentINode.id, new Buffer(JSON.stringify(newParentList)), true, function (e) { if (noErrorTx(e, tx, cb)) { tx.commit(cb); } }); } } }); }; if (newParentList[newName]) { // 'newPath' already exists. Check if it's a file or a directory, and // act accordingly. _this.getINode(tx, newPath, newParentList[newName], function (e, inode) { if (noErrorTx(e, tx, cb)) { if (inode.isFile()) { // Delete the file and continue. tx.delete(inode.id, function (e) { if (noErrorTx(e, tx, cb)) { tx.delete(newParentList[newName], function (e) { if (noErrorTx(e, tx, cb)) { completeRename(); } }); } }); } else { // Can't overwrite a directory using rename. tx.abort(function (e) { cb(ApiError.EPERM(newPath)); }); } } }); } else { completeRename(); } } }; /** * Grabs a path's inode and directory listing, and shoves it into the * inodes and lists hashes. */ var processInodeAndListings = function (p) { _this.findINodeAndDirListing(tx, p, function (e, node, dirList) { if (e) { if (!errorOccurred) { errorOccurred = true; tx.abort(function () { cb(e); }); } // If error has occurred already, just stop here. } else { inodes[p] = node; lists[p] = dirList; theOleSwitcharoo(); } }); }; processInodeAndListings(oldParent); if (oldParent !== newParent) { processInodeAndListings(newParent); } }; AsyncKeyValueFileSystem.prototype.stat = function (p, isLstat, cb) { var tx = this.store.beginTransaction('readonly'); this.findINode(tx, p, function (e, inode) { if (noError(e, cb)) { cb(null, inode.toStats()); } }); }; AsyncKeyValueFileSystem.prototype.createFile = function (p, flag, mode, cb) { var _this = this; var tx = this.store.beginTransaction('readwrite'), data = new Buffer(0); this.commitNewFile(tx, p, 32768 /* FILE */, mode, data, function (e, newFile) { if (noError(e, cb)) { cb(null, new AsyncKeyValueFile(_this, p, flag, newFile.toStats(), data)); } }); }; AsyncKeyValueFileSystem.prototype.openFile = function (p, flag, cb) { var _this = this; var tx = this.store.beginTransaction('readonly'); // Step 1: Grab the file's inode. this.findINode(tx, p, function (e, inode) { if (noError(e, cb)) { // Step 2: Grab the file's data. tx.get(inode.id, function (e, data) { if (noError(e, cb)) { if (data === undefined) { cb(ApiError.ENOENT(p)); } else { cb(null, new AsyncKeyValueFile(_this, p, flag, inode.toStats(), data)); } } }); } }); }; /** * Remove all traces of the given path from the file system. * @param p The path to remove from the file system. * @param isDir Does the path belong to a directory, or a file? * @todo Update mtime. */ AsyncKeyValueFileSystem.prototype.removeEntry = function (p, isDir, cb) { var _this = this; var tx = this.store.beginTransaction('readwrite'), parent = path.dirname(p), fileName = path.basename(p); // Step 1: Get parent directory's node and directory listing. this.findINodeAndDirListing(tx, parent, function (e, parentNode, parentListing) { if (noErrorTx(e, tx, cb)) { if (!parentListing[fileName]) { tx.abort(function () { cb(ApiError.ENOENT(p)); }); } else { // Remove from directory listing of parent. var fileNodeId = parentListing[fileName]; delete parentListing[fileName]; // Step 2: Get file inode. _this.getINode(tx, p, fileNodeId, function (e, fileNode) { if (noErrorTx(e, tx, cb)) { if (!isDir && fileNode.isDirectory()) { tx.abort(function () { cb(ApiError.EISDIR(p)); }); } else if (isDir && !fileNode.isDirectory()) { tx.abort(function () { cb(ApiError.ENOTDIR(p)); }); } else { // Step 3: Delete data. tx.delete(fileNode.id, function (e) { if (noErrorTx(e, tx, cb)) { // Step 4: Delete node. tx.delete(fileNodeId, function (e) { if (noErrorTx(e, tx, cb)) { // Step 5: Update directory listing. tx.put(parentNode.id, new Buffer(JSON.stringify(parentListing)), true, function (e) { if (noErrorTx(e, tx, cb)) { tx.commit(cb); } }); } }); } }); } } }); } } }); }; AsyncKeyValueFileSystem.prototype.unlink = function (p, cb) { this.removeEntry(p, false, cb); }; AsyncKeyValueFileSystem.prototype.rmdir = function (p, cb) { this.removeEntry(p, true, cb); }; AsyncKeyValueFileSystem.prototype.mkdir = function (p, mode, cb) { var tx = this.store.beginTransaction('readwrite'), data = new Buffer('{}'); this.commitNewFile(tx, p, 16384 /* DIRECTORY */, mode, data, cb); }; AsyncKeyValueFileSystem.prototype.readdir = function (p, cb) { var _this = this; var tx = this.store.beginTransaction('readonly'); this.findINode(tx, p, function (e, inode) { if (noError(e, cb)) { _this.getDirListing(tx, p, inode, function (e, dirListing) { if (noError(e, cb)) { cb(null, Object.keys(dirListing)); } }); } }); }; AsyncKeyValueFileSystem.prototype._sync = function (p, data, stats, cb) { var _this = this; // @todo Ensure mtime updates properly, and use that to determine if a data // update is required. var tx = this.store.beginTransaction('readwrite'); // Step 1: Get the file node's ID. this._findINode(tx, path.dirname(p), path.basename(p), function (e, fileInodeId) { if (noErrorTx(e, tx, cb)) { // Step 2: Get the file inode. _this.getINode(tx, p, fileInodeId, function (e, fileInode) { if (noErrorTx(e, tx, cb)) { var inodeChanged = fileInode.update(stats); // Step 3: Sync the data. tx.put(fileInode.id, data, true, function (e) { if (noErrorTx(e, tx, cb)) { // Step 4: Sync the metadata (if it changed)! if (inodeChanged) { tx.put(fileInodeId, fileInode.toBuffer(), true, function (e) { if (noErrorTx(e, tx, cb)) { tx.commit(cb); } }); } else { // No need to sync metadata; return. tx.commit(cb); } } }); } }); } }); }; return AsyncKeyValueFileSystem; })(file_system.BaseFileSystem); exports.AsyncKeyValueFileSystem = AsyncKeyValueFileSystem; }); //# sourceMappingURL=key_value_filesystem.js.map ; define('core/global',["require", "exports"], function(require, exports) { /** * Exports the global scope variable. * In the main browser thread, this is "window". * In a WebWorker, this is "self". * In Node, this is "global". */ var toExport; if (typeof (window) !== 'undefined') { toExport = window; } else if (typeof (self) !== 'undefined') { toExport = self; } else { toExport = global; } return toExport; }); //# sourceMappingURL=global.js.map ; var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; define('backend/IndexedDB',["require", "exports", '../core/buffer', '../core/browserfs', '../generic/key_value_filesystem', '../core/api_error', '../core/buffer_core_arraybuffer', '../core/global'], function(require, exports, buffer, browserfs, kvfs, api_error, buffer_core_arraybuffer, global) { var Buffer = buffer.Buffer, ApiError = api_error.ApiError, ErrorCode = api_error.ErrorCode, indexedDB = global.indexedDB || global.mozIndexedDB || global.webkitIndexedDB || global.msIndexedDB; /** * Converts a DOMException or a DOMError from an IndexedDB event into a * standardized BrowserFS API error. */ function convertError(e, message) { if (typeof message === "undefined") { message = e.toString(); } switch (e.name) { case "NotFoundError": return new ApiError(1 /* ENOENT */, message); case "QuotaExceededError": return new ApiError(11 /* ENOSPC */, message); default: // The rest do not seem to map cleanly to standard error codes. return new ApiError(2 /* EIO */, message); } } /** * Produces a new onerror handler for IDB. Our errors are always fatal, so we * handle them generically: Call the user-supplied callback with a translated * version of the error, and let the error bubble up. */ function onErrorHandler(cb, code, message) { if (typeof code === "undefined") { code = 2 /* EIO */; } if (typeof message === "undefined") { message = null; } return function (e) { // Prevent the error from canceling the transaction. e.preventDefault(); cb(new ApiError(code, message)); }; } /** * Converts a NodeBuffer into an ArrayBuffer. */ function buffer2arraybuffer(buffer) { // XXX: Typing hack. var backing_mem = buffer.getBufferCore(); if (!(backing_mem instanceof buffer_core_arraybuffer.BufferCoreArrayBuffer)) { // Copy into an ArrayBuffer-backed Buffer. buffer = new Buffer(this._buffer.length); this._buffer.copy(buffer); backing_mem = buffer.getBufferCore(); } // Reach into the BC, grab the DV. var dv = backing_mem.getDataView(); return dv.buffer; } var IndexedDBROTransaction = (function () { function IndexedDBROTransaction(tx, store) { this.tx = tx; this.store = store; } IndexedDBROTransaction.prototype.get = function (key, cb) { try { var r = this.store.get(key); r.onerror = onErrorHandler(cb); r.onsuccess = function (event) { // IDB returns the value 'undefined' when you try to get keys that // don't exist. The caller expects this behavior. var result = event.target.result; if (result === undefined) { cb(null, result); } else { // IDB data is stored as an ArrayBuffer cb(null, new Buffer(result)); } }; } catch (e) { cb(convertError(e)); } }; return IndexedDBROTransaction; })(); exports.IndexedDBROTransaction = IndexedDBROTransaction; var IndexedDBRWTransaction = (function (_super) { __extends(IndexedDBRWTransaction, _super); function IndexedDBRWTransaction(tx, store) { _super.call(this, tx, store); } IndexedDBRWTransaction.prototype.put = function (key, data, overwrite, cb) { try { var arraybuffer = buffer2arraybuffer(data), r; if (overwrite) { r = this.store.put(arraybuffer, key); } else { // 'add' will never overwrite an existing key. r = this.store.add(arraybuffer, key); } // XXX: NEED TO RETURN FALSE WHEN ADD HAS A KEY CONFLICT. NO ERROR. r.onerror = onErrorHandler(cb); r.onsuccess = function (event) { cb(null, true); }; } catch (e) { cb(convertError(e)); } }; IndexedDBRWTransaction.prototype.delete = function (key, cb) { try { var r = this.store.delete(key); r.onerror = onErrorHandler(cb); r.onsuccess = function (event) { cb(); }; } catch (e) { cb(convertError(e)); } }; IndexedDBRWTransaction.prototype.commit = function (cb) { // Return to the event loop to commit the transaction. setTimeout(cb, 0); }; IndexedDBRWTransaction.prototype.abort = function (cb) { var _e; try { this.tx.abort(); } catch (e) { _e = convertError(e); } finally { cb(_e); } }; return IndexedDBRWTransaction; })(IndexedDBROTransaction); exports.IndexedDBRWTransaction = IndexedDBRWTransaction; var IndexedDBStore = (function () { /** * Constructs an IndexedDB file system. * @param cb Called once the database is instantiated and ready for use. * Passes an error if there was an issue instantiating the database. * @param objectStoreName The name of this file system. You can have * multiple IndexedDB file systems operating at once, but each must have * a different name. */ function IndexedDBStore(cb, storeName) { if (typeof storeName === "undefined") { storeName = 'browserfs'; } var _this = this; this.storeName = storeName; var openReq = indexedDB.open(this.storeName, 1); openReq.onupgradeneeded = function (event) { var db = event.target.result; // Huh. This should never happen; we're at version 1. Why does another // database exist? if (db.objectStoreNames.contains(_this.storeName)) { db.deleteObjectStore(_this.storeName); } db.createObjectStore(_this.storeName); }; openReq.onsuccess = function (event) { _this.db = event.target.result; cb(null, _this); }; openReq.onerror = onErrorHandler(cb, 4 /* EACCES */); } IndexedDBStore.prototype.name = function () { return "IndexedDB - " + this.storeName; }; IndexedDBStore.prototype.clear = function (cb) { try { var tx = this.db.transaction(this.storeName, 'readwrite'), objectStore = tx.objectStore(this.storeName), r = objectStore.clear(); r.onsuccess = function (event) { // Use setTimeout to commit transaction. setTimeout(cb, 0); }; r.onerror = onErrorHandler(cb); } catch (e) { cb(convertError(e)); } }; IndexedDBStore.prototype.beginTransaction = function (type) { if (typeof type === "undefined") { type = 'readonly'; } var tx = this.db.transaction(this.storeName, type), objectStore = tx.objectStore(this.storeName); if (type === 'readwrite') { return new IndexedDBRWTransaction(tx, objectStore); } else if (type === 'readonly') { return new IndexedDBROTransaction(tx, objectStore); } else { throw new ApiError(9 /* EINVAL */, 'Invalid transaction type.'); } }; return IndexedDBStore; })(); exports.IndexedDBStore = IndexedDBStore; /** * A file system that uses the IndexedDB key value file system. */ var IndexedDBFileSystem = (function (_super) { __extends(IndexedDBFileSystem, _super); function IndexedDBFileSystem(cb, storeName) { var _this = this; _super.call(this); new IndexedDBStore(function (e, store) { if (e) { cb(e); } else { _this.init(store, function (e) { cb(e, _this); }); } }, storeName); } IndexedDBFileSystem.isAvailable = function () { return typeof indexedDB !== 'undefined'; }; return IndexedDBFileSystem; })(kvfs.AsyncKeyValueFileSystem); exports.IndexedDBFileSystem = IndexedDBFileSystem; browserfs.registerFileSystem('IndexedDB', IndexedDBFileSystem); }); //# sourceMappingURL=IndexedDB.js.map ; define('generic/file_index',["require", "exports", '../core/node_fs_stats', '../core/node_path'], function(require, exports, node_fs_stats, node_path) { var Stats = node_fs_stats.Stats; var path = node_path.path; /** * A simple class for storing a filesystem index. Assumes that all paths passed * to it are *absolute* paths. * * Can be used as a partial or a full index, although care must be taken if used * for the former purpose, especially when directories are concerned. */ var FileIndex = (function () { /** * Constructs a new FileIndex. */ function FileIndex() { // _index is a single-level key,value store that maps *directory* paths to // DirInodes. File information is only contained in DirInodes themselves. this._index = {}; // Create the root directory. this.addPath('/', new DirInode()); } /** * Split into a (directory path, item name) pair */ FileIndex.prototype._split_path = function (p) { var dirpath = path.dirname(p); var itemname = p.substr(dirpath.length + (dirpath === "/" ? 0 : 1)); return [dirpath, itemname]; }; /** * Runs the given function over all files in the index. */ FileIndex.prototype.fileIterator = function (cb) { for (var path in this._index) { var dir = this._index[path]; var files = dir.getListing(); for (var i = 0; i < files.length; i++) { var item = dir.getItem(files[i]); if (item.isFile()) { cb(item.getData()); } } } }; /** * Adds the given absolute path to the index if it is not already in the index. * Creates any needed parent directories. * @param [String] path The path to add to the index. * @param [BrowserFS.FileInode | BrowserFS.DirInode] inode The inode for the * path to add. * @return [Boolean] 'True' if it was added or already exists, 'false' if there * was an issue adding it (e.g. item in path is a file, item exists but is * different). * @todo If adding fails and implicitly creates directories, we do not clean up * the new empty directories. */ FileIndex.prototype.addPath = function (path, inode) { if (inode == null) { throw new Error('Inode must be specified'); } if (path[0] !== '/') { throw new Error('Path must be absolute, got: ' + path); } // Check if it already exists. if (this._index.hasOwnProperty(path)) { return this._index[path] === inode; } var splitPath = this._split_path(path); var dirpath = splitPath[0]; var itemname = splitPath[1]; // Try to add to its parent directory first. var parent = this._index[dirpath]; if (parent === undefined && path !== '/') { // Create parent. parent = new DirInode(); if (!this.addPath(dirpath, parent)) { return false; } } // Add myself to my parent. if (path !== '/') { if (!parent.addItem(itemname, inode)) { return false; } } // If I'm a directory, add myself to the index. if (!inode.isFile()) { this._index[path] = inode; } return true; }; /** * Removes the given path. Can be a file or a directory. * @return [BrowserFS.FileInode | BrowserFS.DirInode | null] The removed item, * or null if it did not exist. */ FileIndex.prototype.removePath = function (path) { var splitPath = this._split_path(path); var dirpath = splitPath[0]; var itemname = splitPath[1]; // Try to remove it from its parent directory first. var parent = this._index[dirpath]; if (parent === undefined) { return null; } // Remove myself from my parent. var inode = parent.remItem(itemname); if (inode === null) { return null; } // If I'm a directory, remove myself from the index, and remove my children. if (!inode.isFile()) { var dirInode = inode; var children = dirInode.getListing(); for (var i = 0; i < children.length; i++) { this.removePath(path + '/' + children[i]); } // Remove the directory from the index, unless it's the root. if (path !== '/') { delete this._index[path]; } } return inode; }; /** * Retrieves the directory listing of the given path. * @return [String[]] An array of files in the given path, or 'null' if it does * not exist. */ FileIndex.prototype.ls = function (path) { var item = this._index[path]; if (item === undefined) { return null; } return item.getListing(); }; /** * Returns the inode of the given item. * @param [String] path * @return [BrowserFS.FileInode | BrowserFS.DirInode | null] Returns null if * the item does not exist. */ FileIndex.prototype.getInode = function (path) { var splitPath = this._split_path(path); var dirpath = splitPath[0]; var itemname = splitPath[1]; // Retrieve from its parent directory. var parent = this._index[dirpath]; if (parent === undefined) { return null; } // Root case if (dirpath === path) { return parent; } return parent.getItem(itemname); }; /** * Static method for constructing indices from a JSON listing. * @param [Object] listing Directory listing generated by tools/XHRIndexer.coffee * @return [BrowserFS.FileIndex] A new FileIndex object. */ FileIndex.from_listing = function (listing) { var idx = new FileIndex(); // Add a root DirNode. var rootInode = new DirInode(); idx._index['/'] = rootInode; var queue = [['', listing, rootInode]]; while (queue.length > 0) { var inode; var next = queue.pop(); var pwd = next[0]; var tree = next[1]; var parent = next[2]; for (var node in tree) { var children = tree[node]; var name = "" + pwd + "/" + node; if (children != null) { idx._index[name] = inode = new DirInode(); queue.push([name, children, inode]); } else { // This inode doesn't have correct size information, noted with -1. inode = new FileInode(new Stats(32768 /* FILE */, -1, 0x16D)); } if (parent != null) { parent._ls[node] = inode; } } } return idx; }; return FileIndex; })(); exports.FileIndex = FileIndex; /** * Inode for a file. Stores an arbitrary (filesystem-specific) data payload. */ var FileInode = (function () { function FileInode(data) { this.data = data; } FileInode.prototype.isFile = function () { return true; }; FileInode.prototype.isDir = function () { return false; }; FileInode.prototype.getData = function () { return this.data; }; FileInode.prototype.setData = function (data) { this.data = data; }; return FileInode; })(); exports.FileInode = FileInode; /** * Inode for a directory. Currently only contains the directory listing. */ var DirInode = (function () { /** * Constructs an inode for a directory. */ function DirInode() { this._ls = {}; } DirInode.prototype.isFile = function () { return false; }; DirInode.prototype.isDir = function () { return true; }; /** * Return a Stats object for this inode. * @todo Should probably remove this at some point. This isn't the * responsibility of the FileIndex. * @return [BrowserFS.node.fs.Stats] */ DirInode.prototype.getStats = function () { return new Stats(16384 /* DIRECTORY */, 4096, 0x16D); }; /** * Returns the directory listing for this directory. Paths in the directory are * relative to the directory's path. * @return [String[]] The directory listing for this directory. */ DirInode.prototype.getListing = function () { return Object.keys(this._ls); }; /** * Returns the inode for the indicated item, or null if it does not exist. * @param [String] p Name of item in this directory. * @return [BrowserFS.FileInode | BrowserFS.DirInode | null] */ DirInode.prototype.getItem = function (p) { var _ref; return (_ref = this._ls[p]) != null ? _ref : null; }; /** * Add the given item to the directory listing. Note that the given inode is * not copied, and will be mutated by the DirInode if it is a DirInode. * @param [String] p Item name to add to the directory listing. * @param [BrowserFS.FileInode | BrowserFS.DirInode] inode The inode for the * item to add to the directory inode. * @return [Boolean] True if it was added, false if it already existed. */ DirInode.prototype.addItem = function (p, inode) { if (p in this._ls) { return false; } this._ls[p] = inode; return true; }; /** * Removes the given item from the directory listing. * @param [String] p Name of item to remove from the directory listing. * @return [BrowserFS.FileInode | BrowserFS.DirInode | null] Returns the item * removed, or null if the item did not exist. */ DirInode.prototype.remItem = function (p) { var item = this._ls[p]; if (item === undefined) { return null; } delete this._ls[p]; return item; }; return DirInode; })(); exports.DirInode = DirInode; }); //# sourceMappingURL=file_index.js.map ; /** * Grab bag of utility functions used across the code. */ define('core/util',["require", "exports"], function(require, exports) { /** * Estimates the size of a JS object. * @param {Object} object - the object to measure. * @return {Number} estimated object size. * @see http://stackoverflow.com/a/11900218/10601 */ function roughSizeOfObject(object) { var bytes, key, objectList, prop, stack, value; objectList = []; stack = [object]; bytes = 0; while (stack.length !== 0) { value = stack.pop(); if (typeof value === 'boolean') { bytes += 4; } else if (typeof value === 'string') { bytes += value.length * 2; } else if (typeof value === 'number') { bytes += 8; } else if (typeof value === 'object' && objectList.indexOf(value) < 0) { objectList.push(value); bytes += 4; for (key in value) { prop = value[key]; bytes += key.length * 2; stack.push(prop); } } } return bytes; } exports.roughSizeOfObject = roughSizeOfObject; /** * Checks for any IE version, including IE11 which removed MSIE from the * userAgent string. */ exports.isIE = (/(msie) ([\w.]+)/.exec(navigator.userAgent.toLowerCase()) != null || navigator.userAgent.indexOf('Trident') !== -1); }); //# sourceMappingURL=util.js.map ; /** * Contains utility methods for performing a variety of tasks with * XmlHttpRequest across browsers. */ define('generic/xhr',["require", "exports", '../core/util', '../core/buffer', '../core/api_error'], function(require, exports, util, buffer, api_error) { var ApiError = api_error.ApiError; var ErrorCode = api_error.ErrorCode; var Buffer = buffer.Buffer; // Converts 'responseBody' in IE into the equivalent 'responseText' that other // browsers would generate. function getIEByteArray(IEByteArray) { var rawBytes = IEBinaryToArray_ByteStr(IEByteArray); var lastChr = IEBinaryToArray_ByteStr_Last(IEByteArray); var data_str = rawBytes.replace(/[\s\S]/g, function (match) { var v = match.charCodeAt(0); return String.fromCharCode(v & 0xff, v >> 8); }) + lastChr; var data_array = new Array(data_str.length); for (var i = 0; i < data_str.length; i++) { data_array[i] = data_str.charCodeAt(i); } return data_array; } function downloadFileIE(async, p, type, cb) { switch (type) { case 'buffer': case 'json': break; default: return cb(new ApiError(9 /* EINVAL */, "Invalid download type: " + type)); } var req = new XMLHttpRequest(); req.open('GET', p, async); req.setRequestHeader("Accept-Charset", "x-user-defined"); req.onreadystatechange = function (e) { var data_array; if (req.readyState === 4) { if (req.status === 200) { switch (type) { case 'buffer': data_array = getIEByteArray(req.responseBody); return cb(null, new Buffer(data_array)); case 'json': return cb(null, JSON.parse(req.responseText)); } } else { return cb(new ApiError(req.status, "XHR error.")); } } }; req.send(); } function asyncDownloadFileIE(p, type, cb) { downloadFileIE(true, p, type, cb); } function syncDownloadFileIE(p, type) { var rv; downloadFileIE(false, p, type, function (err, data) { if (err) throw err; rv = data; }); return rv; } function asyncDownloadFileModern(p, type, cb) { var req = new XMLHttpRequest(); req.open('GET', p, true); var jsonSupported = true; switch (type) { case 'buffer': req.responseType = 'arraybuffer'; break; case 'json': try { req.responseType = 'json'; jsonSupported = req.responseType === 'json'; } catch (e) { jsonSupported = false; } break; default: return cb(new ApiError(9 /* EINVAL */, "Invalid download type: " + type)); } req.onreadystatechange = function (e) { if (req.readyState === 4) { if (req.status === 200) { switch (type) { case 'buffer': // XXX: WebKit-based browsers return *null* when XHRing an empty file. return cb(null, new Buffer(req.response ? req.response : 0)); case 'json': if (jsonSupported) { return cb(null, req.response); } else { return cb(null, JSON.parse(req.responseText)); } } } else { return cb(new ApiError(req.status, "XHR error.")); } } }; req.send(); } function syncDownloadFileModern(p, type) { var req = new XMLHttpRequest(); req.open('GET', p, false); // On most platforms, we cannot set the responseType of synchronous downloads. // @todo Test for this; IE10 allows this, as do older versions of Chrome/FF. var data = null; var err = null; // Classic hack to download binary data as a string. req.overrideMimeType('text/plain; charset=x-user-defined'); req.onreadystatechange = function (e) { if (req.readyState === 4) { if (req.status === 200) { switch (type) { case 'buffer': // Convert the text into a buffer. var text = req.responseText; data = new Buffer(text.length); for (var i = 0; i < text.length; i++) { // This will automatically throw away the upper bit of each // character for us. data.writeUInt8(text.charCodeAt(i), i); } return; case 'json': data = JSON.parse(req.responseText); return; } } else { err = new ApiError(req.status, "XHR error."); return; } } }; req.send(); if (err) { throw err; } return data; } function syncDownloadFileIE10(p, type) { var req = new XMLHttpRequest(); req.open('GET', p, false); switch (type) { case 'buffer': req.responseType = 'arraybuffer'; break; case 'json': break; default: throw new ApiError(9 /* EINVAL */, "Invalid download type: " + type); } var data; var err; req.onreadystatechange = function (e) { if (req.readyState === 4) { if (req.status === 200) { switch (type) { case 'buffer': data = new Buffer(req.response); break; case 'json': data = JSON.parse(req.response); break; } } else { err = new ApiError(req.status, "XHR error."); } } }; req.send(); if (err) { throw err; } return data; } function getFileSize(async, p, cb) { var req = new XMLHttpRequest(); req.open('HEAD', p, async); req.onreadystatechange = function (e) { if (req.readyState === 4) { if (req.status == 200) { try { return cb(null, parseInt(req.getResponseHeader('Content-Length'), 10)); } catch (e) { // In the event that the header isn't present or there is an error... return cb(new ApiError(2 /* EIO */, "XHR HEAD error: Could not read content-length.")); } } else { return cb(new ApiError(req.status, "XHR HEAD error.")); } } }; req.send(); } /** * Asynchronously download a file as a buffer or a JSON object. * Note that the third function signature with a non-specialized type is * invalid, but TypeScript requires it when you specialize string arguments to * constants. */ exports.asyncDownloadFile = (util.isIE && typeof Blob === 'undefined') ? asyncDownloadFileIE : asyncDownloadFileModern; /** * Synchronously download a file as a buffer or a JSON object. * Note that the third function signature with a non-specialized type is * invalid, but TypeScript requires it when you specialize string arguments to * constants. */ exports.syncDownloadFile = (util.isIE && typeof Blob === 'undefined') ? syncDownloadFileIE : (util.isIE && typeof Blob !== 'undefined') ? syncDownloadFileIE10 : syncDownloadFileModern; /** * Synchronously retrieves the size of the given file in bytes. */ function getFileSizeSync(p) { var rv; getFileSize(false, p, function (err, size) { if (err) { throw err; } rv = size; }); return rv; } exports.getFileSizeSync = getFileSizeSync; /** * Asynchronously retrieves the size of the given file in bytes. */ function getFileSizeAsync(p, cb) { getFileSize(true, p, cb); } exports.getFileSizeAsync = getFileSizeAsync; }); //# sourceMappingURL=xhr.js.map ; var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; define('backend/XmlHttpRequest',["require", "exports", '../core/file_system', '../generic/file_index', '../core/buffer', '../core/api_error', '../core/file_flag', '../generic/preload_file', '../core/browserfs', '../generic/xhr'], function(require, exports, file_system, file_index, buffer, api_error, file_flag, preload_file, browserfs, xhr) { var Buffer = buffer.Buffer; var ApiError = api_error.ApiError; var ErrorCode = api_error.ErrorCode; var FileFlag = file_flag.FileFlag; var ActionType = file_flag.ActionType; /** * A simple filesystem backed by XmlHttpRequests. */ var XmlHttpRequest = (function (_super) { __extends(XmlHttpRequest, _super); /** * Constructs the file system. * @param [String] listing_url The path to the JSON file index generated by * tools/XHRIndexer.coffee. This can be relative to the current webpage URL * or absolutely specified. * @param [String] prefix_url The url prefix to use for all web-server requests. */ function XmlHttpRequest(listing_url, prefix_url) { if (typeof prefix_url === "undefined") { prefix_url = ''; } _super.call(this); this.prefix_url = prefix_url; if (listing_url == null) { listing_url = 'index.json'; } // prefix_url must end in a directory separator. if (prefix_url.length > 0 && prefix_url.charAt(prefix_url.length - 1) !== '/') { prefix_url = prefix_url + '/'; } var listing = this._requestFileSync(listing_url, 'json'); if (listing == null) { throw new Error("Unable to find listing at URL: " + listing_url); } this._index = file_index.FileIndex.from_listing(listing); } XmlHttpRequest.prototype.empty = function () { this._index.fileIterator(function (file) { file.file_data = null; }); }; XmlHttpRequest.prototype.getXhrPath = function (filePath) { if (filePath.charAt(0) === '/') { filePath = filePath.slice(1); } return this.prefix_url + filePath; }; /** * Only requests the HEAD content, for the file size. */ XmlHttpRequest.prototype._requestFileSizeAsync = function (path, cb) { xhr.getFileSizeAsync(this.getXhrPath(path), cb); }; XmlHttpRequest.prototype._requestFileSizeSync = function (path) { return xhr.getFileSizeSync(this.getXhrPath(path)); }; XmlHttpRequest.prototype._requestFileAsync = function (p, type, cb) { xhr.asyncDownloadFile(this.getXhrPath(p), type, cb); }; XmlHttpRequest.prototype._requestFileSync = function (p, type) { return xhr.syncDownloadFile(this.getXhrPath(p), type); }; XmlHttpRequest.prototype.getName = function () { return 'XmlHttpRequest'; }; XmlHttpRequest.isAvailable = function () { // @todo Older browsers use a different name for XHR, iirc. return typeof XMLHttpRequest !== "undefined" && XMLHttpRequest !== null; }; XmlHttpRequest.prototype.diskSpace = function (path, cb) { // Read-only file system. We could calculate the total space, but that's not // important right now. cb(0, 0); }; XmlHttpRequest.prototype.isReadOnly = function () { return true; }; XmlHttpRequest.prototype.supportsLinks = function () { return false; }; XmlHttpRequest.prototype.supportsProps = function () { return false; }; XmlHttpRequest.prototype.supportsSynch = function () { return true; }; /** * Special XHR function: Preload the given file into the index. * @param [String] path * @param [BrowserFS.Buffer] buffer */ XmlHttpRequest.prototype.preloadFile = function (path, buffer) { var inode = this._index.getInode(path); if (inode === null) { throw ApiError.ENOENT(path); } var stats = inode.getData(); stats.size = buffer.length; stats.file_data = buffer; }; XmlHttpRequest.prototype.stat = function (path, isLstat, cb) { var inode = this._index.getInode(path); if (inode === null) { return cb(ApiError.ENOENT(path)); } var stats; if (inode.isFile()) { stats = inode.getData(); // At this point, a non-opened file will still have default stats from the listing. if (stats.size < 0) { this._requestFileSizeAsync(path, function (e, size) { if (e) { return cb(e); } stats.size = size; cb(null, stats.clone()); }); } else { cb(null, stats.clone()); } } else { stats = inode.getStats(); cb(null, stats); } }; XmlHttpRequest.prototype.statSync = function (path, isLstat) { var inode = this._index.getInode(path); if (inode === null) { throw ApiError.ENOENT(path); } var stats; if (inode.isFile()) { stats = inode.getData(); // At this point, a non-opened file will still have default stats from the listing. if (stats.size < 0) { stats.size = this._requestFileSizeSync(path); } } else { stats = inode.getStats(); } return stats; }; XmlHttpRequest.prototype.open = function (path, flags, mode, cb) { // INVARIANT: You can't write to files on this file system. if (flags.isWriteable()) { return cb(new ApiError(0 /* EPERM */, path)); } var _this = this; // Check if the path exists, and is a file. var inode = this._index.getInode(path); if (inode === null) { return cb(ApiError.ENOENT(path)); } if (inode.isDir()) { return cb(ApiError.EISDIR(path)); } var stats = inode.getData(); switch (flags.pathExistsAction()) { case 1 /* THROW_EXCEPTION */: case 2 /* TRUNCATE_FILE */: return cb(ApiError.EEXIST(path)); case 0 /* NOP */: // Use existing file contents. // XXX: Uh, this maintains the previously-used flag. if (stats.file_data != null) { return cb(null, new preload_file.NoSyncFile(_this, path, flags, stats.clone(), stats.file_data)); } // @todo be lazier about actually requesting the file this._requestFileAsync(path, 'buffer', function (err, buffer) { if (err) { return cb(err); } // we don't initially have file sizes stats.size = buffer.length; stats.file_data = buffer; return cb(null, new preload_file.NoSyncFile(_this, path, flags, stats.clone(), buffer)); }); break; default: return cb(new ApiError(9 /* EINVAL */, 'Invalid FileMode object.')); } }; XmlHttpRequest.prototype.openSync = function (path, flags, mode) { // INVARIANT: You can't write to files on this file system. if (flags.isWriteable()) { throw new ApiError(0 /* EPERM */, path); } // Check if the path exists, and is a file. var inode = this._index.getInode(path); if (inode === null) { throw ApiError.ENOENT(path); } if (inode.isDir()) { throw ApiError.EISDIR(path); } var stats = inode.getData(); switch (flags.pathExistsAction()) { case 1 /* THROW_EXCEPTION */: case 2 /* TRUNCATE_FILE */: throw ApiError.EEXIST(path); case 0 /* NOP */: // Use existing file contents. // XXX: Uh, this maintains the previously-used flag. if (stats.file_data != null) { return new preload_file.NoSyncFile(this, path, flags, stats.clone(), stats.file_data); } // @todo be lazier about actually requesting the file var buffer = this._requestFileSync(path, 'buffer'); // we don't initially have file sizes stats.size = buffer.length; stats.file_data = buffer; return new preload_file.NoSyncFile(this, path, flags, stats.clone(), buffer); default: throw new ApiError(9 /* EINVAL */, 'Invalid FileMode object.'); } }; XmlHttpRequest.prototype.readdir = function (path, cb) { try { cb(null, this.readdirSync(path)); } catch (e) { cb(e); } }; XmlHttpRequest.prototype.readdirSync = function (path) { // Check if it exists. var inode = this._index.getInode(path); if (inode === null) { throw ApiError.ENOENT(path); } else if (inode.isFile()) { throw ApiError.ENOTDIR(path); } return inode.getListing(); }; /** * We have the entire file as a buffer; optimize readFile. */ XmlHttpRequest.prototype.readFile = function (fname, encoding, flag, cb) { // Wrap cb in file closing code. var oldCb = cb; // Get file. this.open(fname, flag, 0x1a4, function (err, fd) { if (err) { return cb(err); } cb = function (err, arg) { fd.close(function (err2) { if (err == null) { err = err2; } return oldCb(err, arg); }); }; var fdCast = fd; var fdBuff = fdCast._buffer; if (encoding === null) { if (fdBuff.length > 0) { return cb(err, fdBuff.sliceCopy()); } else { return cb(err, new buffer.Buffer(0)); } } try { cb(null, fdBuff.toString(encoding)); } catch (e) { cb(e); } }); }; /** * Specially-optimized readfile. */ XmlHttpRequest.prototype.readFileSync = function (fname, encoding, flag) { // Get file. var fd = this.openSync(fname, flag, 0x1a4); try { var fdCast = fd; var fdBuff = fdCast._buffer; if (encoding === null) { if (fdBuff.length > 0) { return fdBuff.sliceCopy(); } else { return new buffer.Buffer(0); } } return fdBuff.toString(encoding); } finally { fd.closeSync(); } }; return XmlHttpRequest; })(file_system.BaseFileSystem); exports.XmlHttpRequest = XmlHttpRequest; browserfs.registerFileSystem('XmlHttpRequest', XmlHttpRequest); }); //# sourceMappingURL=XmlHttpRequest.js.map ; /*global setImmediate: false, setTimeout: false, console: false */ (function () { var async = {}; // global on the server, window in the browser var root, previous_async; root = this; if (root != null) { previous_async = root.async; } async.noConflict = function () { root.async = previous_async; return async; }; function only_once(fn) { var called = false; return function() { if (called) throw new Error("Callback was already called."); called = true; fn.apply(root, arguments); } } //// cross-browser compatiblity functions //// var _each = function (arr, iterator) { if (arr.forEach) { return arr.forEach(iterator); } for (var i = 0; i < arr.length; i += 1) { iterator(arr[i], i, arr); } }; var _map = function (arr, iterator) { if (arr.map) { return arr.map(iterator); } var results = []; _each(arr, function (x, i, a) { results.push(iterator(x, i, a)); }); return results; }; var _reduce = function (arr, iterator, memo) { if (arr.reduce) { return arr.reduce(iterator, memo); } _each(arr, function (x, i, a) { memo = iterator(memo, x, i, a); }); return memo; }; var _keys = function (obj) { if (Object.keys) { return Object.keys(obj); } var keys = []; for (var k in obj) { if (obj.hasOwnProperty(k)) { keys.push(k); } } return keys; }; //// exported async module functions //// //// nextTick implementation with browser-compatible fallback //// if (typeof process === 'undefined' || !(process.nextTick)) { if (typeof setImmediate === 'function') { async.nextTick = function (fn) { // not a direct alias for IE10 compatibility setImmediate(fn); }; async.setImmediate = async.nextTick; } else { async.nextTick = function (fn) { setTimeout(fn, 0); }; async.setImmediate = async.nextTick; } } else { async.nextTick = process.nextTick; if (typeof setImmediate !== 'undefined') { async.setImmediate = function (fn) { // not a direct alias for IE10 compatibility setImmediate(fn); }; } else { async.setImmediate = async.nextTick; } } async.each = function (arr, iterator, callback) { callback = callback || function () {}; if (!arr.length) { return callback(); } var completed = 0; _each(arr, function (x) { iterator(x, only_once(function (err) { if (err) { callback(err); callback = function () {}; } else { completed += 1; if (completed >= arr.length) { callback(null); } } })); }); }; async.forEach = async.each; async.eachSeries = function (arr, iterator, callback) { callback = callback || function () {}; if (!arr.length) { return callback(); } var completed = 0; var iterate = function () { iterator(arr[completed], function (err) { if (err) { callback(err); callback = function () {}; } else { completed += 1; if (completed >= arr.length) { callback(null); } else { iterate(); } } }); }; iterate(); }; async.forEachSeries = async.eachSeries; async.eachLimit = function (arr, limit, iterator, callback) { var fn = _eachLimit(limit); fn.apply(null, [arr, iterator, callback]); }; async.forEachLimit = async.eachLimit; var _eachLimit = function (limit) { return function (arr, iterator, callback) { callback = callback || function () {}; if (!arr.length || limit <= 0) { return callback(); } var completed = 0; var started = 0; var running = 0; (function replenish () { if (completed >= arr.length) { return callback(); } while (running < limit && started < arr.length) { started += 1; running += 1; iterator(arr[started - 1], function (err) { if (err) { callback(err); callback = function () {}; } else { completed += 1; running -= 1; if (completed >= arr.length) { callback(); } else { replenish(); } } }); } })(); }; }; var doParallel = function (fn) { return function () { var args = Array.prototype.slice.call(arguments); return fn.apply(null, [async.each].concat(args)); }; }; var doParallelLimit = function(limit, fn) { return function () { var args = Array.prototype.slice.call(arguments); return fn.apply(null, [_eachLimit(limit)].concat(args)); }; }; var doSeries = function (fn) { return function () { var args = Array.prototype.slice.call(arguments); return fn.apply(null, [async.eachSeries].concat(args)); }; }; var _asyncMap = function (eachfn, arr, iterator, callback) { var results = []; arr = _map(arr, function (x, i) { return {index: i, value: x}; }); eachfn(arr, function (x, callback) { iterator(x.value, function (err, v) { results[x.index] = v; callback(err); }); }, function (err) { callback(err, results); }); }; async.map = doParallel(_asyncMap); async.mapSeries = doSeries(_asyncMap); async.mapLimit = function (arr, limit, iterator, callback) { return _mapLimit(limit)(arr, iterator, callback); }; var _mapLimit = function(limit) { return doParallelLimit(limit, _asyncMap); }; // reduce only has a series version, as doing reduce in parallel won't // work in many situations. async.reduce = function (arr, memo, iterator, callback) { async.eachSeries(arr, function (x, callback) { iterator(memo, x, function (err, v) { memo = v; callback(err); }); }, function (err) { callback(err, memo); }); }; // inject alias async.inject = async.reduce; // foldl alias async.foldl = async.reduce; async.reduceRight = function (arr, memo, iterator, callback) { var reversed = _map(arr, function (x) { return x; }).reverse(); async.reduce(reversed, memo, iterator, callback); }; // foldr alias async.foldr = async.reduceRight; var _filter = function (eachfn, arr, iterator, callback) { var results = []; arr = _map(arr, function (x, i) { return {index: i, value: x}; }); eachfn(arr, function (x, callback) { iterator(x.value, function (v) { if (v) { results.push(x); } callback(); }); }, function (err) { callback(_map(results.sort(function (a, b) { return a.index - b.index; }), function (x) { return x.value; })); }); }; async.filter = doParallel(_filter); async.filterSeries = doSeries(_filter); // select alias async.select = async.filter; async.selectSeries = async.filterSeries; var _reject = function (eachfn, arr, iterator, callback) { var results = []; arr = _map(arr, function (x, i) { return {index: i, value: x}; }); eachfn(arr, function (x, callback) { iterator(x.value, function (v) { if (!v) { results.push(x); } callback(); }); }, function (err) { callback(_map(results.sort(function (a, b) { return a.index - b.index; }), function (x) { return x.value; })); }); }; async.reject = doParallel(_reject); async.rejectSeries = doSeries(_reject); var _detect = function (eachfn, arr, iterator, main_callback) { eachfn(arr, function (x, callback) { iterator(x, function (result) { if (result) { main_callback(x); main_callback = function () {}; } else { callback(); } }); }, function (err) { main_callback(); }); }; async.detect = doParallel(_detect); async.detectSeries = doSeries(_detect); async.some = function (arr, iterator, main_callback) { async.each(arr, function (x, callback) { iterator(x, function (v) { if (v) { main_callback(true); main_callback = function () {}; } callback(); }); }, function (err) { main_callback(false); }); }; // any alias async.any = async.some; async.every = function (arr, iterator, main_callback) { async.each(arr, function (x, callback) { iterator(x, function (v) { if (!v) { main_callback(false); main_callback = function () {}; } callback(); }); }, function (err) { main_callback(true); }); }; // all alias async.all = async.every; async.sortBy = function (arr, iterator, callback) { async.map(arr, function (x, callback) { iterator(x, function (err, criteria) { if (err) { callback(err); } else { callback(null, {value: x, criteria: criteria}); } }); }, function (err, results) { if (err) { return callback(err); } else { var fn = function (left, right) { var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; }; callback(null, _map(results.sort(fn), function (x) { return x.value; })); } }); }; async.auto = function (tasks, callback) { callback = callback || function () {}; var keys = _keys(tasks); if (!keys.length) { return callback(null); } var results = {}; var listeners = []; var addListener = function (fn) { listeners.unshift(fn); }; var removeListener = function (fn) { for (var i = 0; i < listeners.length; i += 1) { if (listeners[i] === fn) { listeners.splice(i, 1); return; } } }; var taskComplete = function () { _each(listeners.slice(0), function (fn) { fn(); }); }; addListener(function () { if (_keys(results).length === keys.length) { callback(null, results); callback = function () {}; } }); _each(keys, function (k) { var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k]; var taskCallback = function (err) { var args = Array.prototype.slice.call(arguments, 1); if (args.length <= 1) { args = args[0]; } if (err) { var safeResults = {}; _each(_keys(results), function(rkey) { safeResults[rkey] = results[rkey]; }); safeResults[k] = args; callback(err, safeResults); // stop subsequent errors hitting callback multiple times callback = function () {}; } else { results[k] = args; async.setImmediate(taskComplete); } }; var requires = task.slice(0, Math.abs(task.length - 1)) || []; var ready = function () { return _reduce(requires, function (a, x) { return (a && results.hasOwnProperty(x)); }, true) && !results.hasOwnProperty(k); }; if (ready()) { task[task.length - 1](taskCallback, results); } else { var listener = function () { if (ready()) { removeListener(listener); task[task.length - 1](taskCallback, results); } }; addListener(listener); } }); }; async.waterfall = function (tasks, callback) { callback = callback || function () {}; if (tasks.constructor !== Array) { var err = new Error('First argument to waterfall must be an array of functions'); return callback(err); } if (!tasks.length) { return callback(); } var wrapIterator = function (iterator) { return function (err) { if (err) { callback.apply(null, arguments); callback = function () {}; } else { var args = Array.prototype.slice.call(arguments, 1); var next = iterator.next(); if (next) { args.push(wrapIterator(next)); } else { args.push(callback); } async.setImmediate(function () { iterator.apply(null, args); }); } }; }; wrapIterator(async.iterator(tasks))(); }; var _parallel = function(eachfn, tasks, callback) { callback = callback || function () {}; if (tasks.constructor === Array) { eachfn.map(tasks, function (fn, callback) { if (fn) { fn(function (err) { var args = Array.prototype.slice.call(arguments, 1); if (args.length <= 1) { args = args[0]; } callback.call(null, err, args); }); } }, callback); } else { var results = {}; eachfn.each(_keys(tasks), function (k, callback) { tasks[k](function (err) { var args = Array.prototype.slice.call(arguments, 1); if (args.length <= 1) { args = args[0]; } results[k] = args; callback(err); }); }, function (err) { callback(err, results); }); } }; async.parallel = function (tasks, callback) { _parallel({ map: async.map, each: async.each }, tasks, callback); }; async.parallelLimit = function(tasks, limit, callback) { _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback); }; async.series = function (tasks, callback) { callback = callback || function () {}; if (tasks.constructor === Array) { async.mapSeries(tasks, function (fn, callback) { if (fn) { fn(function (err) { var args = Array.prototype.slice.call(arguments, 1); if (args.length <= 1) { args = args[0]; } callback.call(null, err, args); }); } }, callback); } else { var results = {}; async.eachSeries(_keys(tasks), function (k, callback) { tasks[k](function (err) { var args = Array.prototype.slice.call(arguments, 1); if (args.length <= 1) { args = args[0]; } results[k] = args; callback(err); }); }, function (err) { callback(err, results); }); } }; async.iterator = function (tasks) { var makeCallback = function (index) { var fn = function () { if (tasks.length) { tasks[index].apply(null, arguments); } return fn.next(); }; fn.next = function () { return (index < tasks.length - 1) ? makeCallback(index + 1): null; }; return fn; }; return makeCallback(0); }; async.apply = function (fn) { var args = Array.prototype.slice.call(arguments, 1); return function () { return fn.apply( null, args.concat(Array.prototype.slice.call(arguments)) ); }; }; var _concat = function (eachfn, arr, fn, callback) { var r = []; eachfn(arr, function (x, cb) { fn(x, function (err, y) { r = r.concat(y || []); cb(err); }); }, function (err) { callback(err, r); }); }; async.concat = doParallel(_concat); async.concatSeries = doSeries(_concat); async.whilst = function (test, iterator, callback) { if (test()) { iterator(function (err) { if (err) { return callback(err); } async.whilst(test, iterator, callback); }); } else { callback(); } }; async.doWhilst = function (iterator, test, callback) { iterator(function (err) { if (err) { return callback(err); } if (test()) { async.doWhilst(iterator, test, callback); } else { callback(); } }); }; async.until = function (test, iterator, callback) { if (!test()) { iterator(function (err) { if (err) { return callback(err); } async.until(test, iterator, callback); }); } else { callback(); } }; async.doUntil = function (iterator, test, callback) { iterator(function (err) { if (err) { return callback(err); } if (!test()) { async.doUntil(iterator, test, callback); } else { callback(); } }); }; async.queue = function (worker, concurrency) { if (concurrency === undefined) { concurrency = 1; } function _insert(q, data, pos, callback) { if(data.constructor !== Array) { data = [data]; } _each(data, function(task) { var item = { data: task, callback: typeof callback === 'function' ? callback : null }; if (pos) { q.tasks.unshift(item); } else { q.tasks.push(item); } if (q.saturated && q.tasks.length === concurrency) { q.saturated(); } async.setImmediate(q.process); }); } var workers = 0; var q = { tasks: [], concurrency: concurrency, saturated: null, empty: null, drain: null, push: function (data, callback) { _insert(q, data, false, callback); }, unshift: function (data, callback) { _insert(q, data, true, callback); }, process: function () { if (workers < q.concurrency && q.tasks.length) { var task = q.tasks.shift(); if (q.empty && q.tasks.length === 0) { q.empty(); } workers += 1; var next = function () { workers -= 1; if (task.callback) { task.callback.apply(task, arguments); } if (q.drain && q.tasks.length + workers === 0) { q.drain(); } q.process(); }; var cb = only_once(next); worker(task.data, cb); } }, length: function () { return q.tasks.length; }, running: function () { return workers; } }; return q; }; async.cargo = function (worker, payload) { var working = false, tasks = []; var cargo = { tasks: tasks, payload: payload, saturated: null, empty: null, drain: null, push: function (data, callback) { if(data.constructor !== Array) { data = [data]; } _each(data, function(task) { tasks.push({ data: task, callback: typeof callback === 'function' ? callback : null }); if (cargo.saturated && tasks.length === payload) { cargo.saturated(); } }); async.setImmediate(cargo.process); }, process: function process() { if (working) return; if (tasks.length === 0) { if(cargo.drain) cargo.drain(); return; } var ts = typeof payload === 'number' ? tasks.splice(0, payload) : tasks.splice(0); var ds = _map(ts, function (task) { return task.data; }); if(cargo.empty) cargo.empty(); working = true; worker(ds, function () { working = false; var args = arguments; _each(ts, function (data) { if (data.callback) { data.callback.apply(null, args); } }); process(); }); }, length: function () { return tasks.length; }, running: function () { return working; } }; return cargo; }; var _console_fn = function (name) { return function (fn) { var args = Array.prototype.slice.call(arguments, 1); fn.apply(null, args.concat([function (err) { var args = Array.prototype.slice.call(arguments, 1); if (typeof console !== 'undefined') { if (err) { if (console.error) { console.error(err); } } else if (console[name]) { _each(args, function (x) { console[name](x); }); } } }])); }; }; async.log = _console_fn('log'); async.dir = _console_fn('dir'); /*async.info = _console_fn('info'); async.warn = _console_fn('warn'); async.error = _console_fn('error');*/ async.memoize = function (fn, hasher) { var memo = {}; var queues = {}; hasher = hasher || function (x) { return x; }; var memoized = function () { var args = Array.prototype.slice.call(arguments); var callback = args.pop(); var key = hasher.apply(null, args); if (key in memo) { callback.apply(null, memo[key]); } else if (key in queues) { queues[key].push(callback); } else { queues[key] = [callback]; fn.apply(null, args.concat([function () { memo[key] = arguments; var q = queues[key]; delete queues[key]; for (var i = 0, l = q.length; i < l; i++) { q[i].apply(null, arguments); } }])); } }; memoized.memo = memo; memoized.unmemoized = fn; return memoized; }; async.unmemoize = function (fn) { return function () { return (fn.unmemoized || fn).apply(null, arguments); }; }; async.times = function (count, iterator, callback) { var counter = []; for (var i = 0; i < count; i++) { counter.push(i); } return async.map(counter, iterator, callback); }; async.timesSeries = function (count, iterator, callback) { var counter = []; for (var i = 0; i < count; i++) { counter.push(i); } return async.mapSeries(counter, iterator, callback); }; async.compose = function (/* functions... */) { var fns = Array.prototype.reverse.call(arguments); return function () { var that = this; var args = Array.prototype.slice.call(arguments); var callback = args.pop(); async.reduce(fns, args, function (newargs, fn, cb) { fn.apply(that, newargs.concat([function () { var err = arguments[0]; var nextargs = Array.prototype.slice.call(arguments, 1); cb(err, nextargs); }])) }, function (err, results) { callback.apply(that, [err].concat(results)); }); }; }; var _applyEach = function (eachfn, fns /*args...*/) { var go = function () { var that = this; var args = Array.prototype.slice.call(arguments); var callback = args.pop(); return eachfn(fns, function (fn, cb) { fn.apply(that, args.concat([cb])); }, callback); }; if (arguments.length > 2) { var args = Array.prototype.slice.call(arguments, 2); return go.apply(this, args); } else { return go; } }; async.applyEach = doParallel(_applyEach); async.applyEachSeries = doSeries(_applyEach); async.forever = function (fn, callback) { function next(err) { if (err) { if (callback) { return callback(err); } throw err; } fn(next); } next(); }; // AMD / RequireJS if (typeof define !== 'undefined' && define.amd) { define('async',[], function () { return async; }); } // Node.js else if (typeof module !== 'undefined' && module.exports) { module.exports = async; } // included directly via