(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