!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.Filer=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ (function (process){ /*global setImmediate: false, setTimeout: false, console: false */ /** * async.js shim, based on https://raw.github.com/caolan/async/master/lib/async.js Feb 18, 2014 * Used under MIT - https://github.com/caolan/async/blob/master/LICENSE */ (function () { var async = {}; // async.js functions used in Filer //// 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.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(); } else { iterate(); } } }); }; iterate(); }; async.forEachSeries = async.eachSeries; // AMD / RequireJS if (typeof define !== 'undefined' && define.amd) { define([], function () { return async; }); } // Node.js else if (typeof module !== 'undefined' && module.exports) { module.exports = async; } // included directly via <script> tag else { root.async = async; } }()); }).call(this,_dereq_("FWaASH")) },{"FWaASH":10}],2:[function(_dereq_,module,exports){ // Based on https://github.com/diy/intercom.js/blob/master/lib/events.js // Copyright 2012 DIY Co Apache License, Version 2.0 // http://www.apache.org/licenses/LICENSE-2.0 function removeItem(item, array) { for (var i = array.length - 1; i >= 0; i--) { if (array[i] === item) { array.splice(i, 1); } } return array; } var EventEmitter = function() {}; EventEmitter.createInterface = function(space) { var methods = {}; methods.on = function(name, fn) { if (typeof this[space] === 'undefined') { this[space] = {}; } if (!this[space].hasOwnProperty(name)) { this[space][name] = []; } this[space][name].push(fn); }; methods.off = function(name, fn) { if (typeof this[space] === 'undefined') return; if (this[space].hasOwnProperty(name)) { removeItem(fn, this[space][name]); } }; methods.trigger = function(name) { if (typeof this[space] !== 'undefined' && this[space].hasOwnProperty(name)) { var args = Array.prototype.slice.call(arguments, 1); for (var i = 0; i < this[space][name].length; i++) { this[space][name][i].apply(this[space][name][i], args); } } }; methods.removeAllListeners = function(name) { if (typeof this[space] === 'undefined') return; var self = this; self[space][name].forEach(function(fn) { self.off(name, fn); }); }; return methods; }; var pvt = EventEmitter.createInterface('_handlers'); EventEmitter.prototype._on = pvt.on; EventEmitter.prototype._off = pvt.off; EventEmitter.prototype._trigger = pvt.trigger; var pub = EventEmitter.createInterface('handlers'); EventEmitter.prototype.on = function() { pub.on.apply(this, arguments); Array.prototype.unshift.call(arguments, 'on'); this._trigger.apply(this, arguments); }; EventEmitter.prototype.off = pub.off; EventEmitter.prototype.trigger = pub.trigger; EventEmitter.prototype.removeAllListeners = pub.removeAllListeners; module.exports = EventEmitter; },{}],3:[function(_dereq_,module,exports){ (function (global){ // Based on https://github.com/diy/intercom.js/blob/master/lib/intercom.js // Copyright 2012 DIY Co Apache License, Version 2.0 // http://www.apache.org/licenses/LICENSE-2.0 var EventEmitter = _dereq_('./eventemitter.js'); var guid = _dereq_('../src/shared.js').guid; function throttle(delay, fn) { var last = 0; return function() { var now = Date.now(); if (now - last > delay) { last = now; fn.apply(this, arguments); } }; } function extend(a, b) { if (typeof a === 'undefined' || !a) { a = {}; } if (typeof b === 'object') { for (var key in b) { if (b.hasOwnProperty(key)) { a[key] = b[key]; } } } return a; } var localStorage = (function(window) { if (typeof window === 'undefined' || typeof window.localStorage === 'undefined') { return { getItem : function() {}, setItem : function() {}, removeItem : function() {} }; } return window.localStorage; }(global)); function Intercom() { var self = this; var now = Date.now(); this.origin = guid(); this.lastMessage = now; this.receivedIDs = {}; this.previousValues = {}; var storageHandler = function() { self._onStorageEvent.apply(self, arguments); }; // If we're in node.js, skip event registration if (typeof document === 'undefined') { return; } if (document.attachEvent) { document.attachEvent('onstorage', storageHandler); } else { global.addEventListener('storage', storageHandler, false); } } Intercom.prototype._transaction = function(fn) { var TIMEOUT = 1000; var WAIT = 20; var self = this; var executed = false; var listening = false; var waitTimer = null; function lock() { if (executed) { return; } var now = Date.now(); var activeLock = localStorage.getItem(INDEX_LOCK)|0; if (activeLock && now - activeLock < TIMEOUT) { if (!listening) { self._on('storage', lock); listening = true; } waitTimer = setTimeout(lock, WAIT); return; } executed = true; localStorage.setItem(INDEX_LOCK, now); fn(); unlock(); } function unlock() { if (listening) { self._off('storage', lock); } if (waitTimer) { clearTimeout(waitTimer); } localStorage.removeItem(INDEX_LOCK); } lock(); }; Intercom.prototype._cleanup_emit = throttle(100, function() { var self = this; self._transaction(function() { var now = Date.now(); var threshold = now - THRESHOLD_TTL_EMIT; var changed = 0; var messages; try { messages = JSON.parse(localStorage.getItem(INDEX_EMIT) || '[]'); } catch(e) { messages = []; } for (var i = messages.length - 1; i >= 0; i--) { if (messages[i].timestamp < threshold) { messages.splice(i, 1); changed++; } } if (changed > 0) { localStorage.setItem(INDEX_EMIT, JSON.stringify(messages)); } }); }); Intercom.prototype._cleanup_once = throttle(100, function() { var self = this; self._transaction(function() { var timestamp, ttl, key; var table; var now = Date.now(); var changed = 0; try { table = JSON.parse(localStorage.getItem(INDEX_ONCE) || '{}'); } catch(e) { table = {}; } for (key in table) { if (self._once_expired(key, table)) { delete table[key]; changed++; } } if (changed > 0) { localStorage.setItem(INDEX_ONCE, JSON.stringify(table)); } }); }); Intercom.prototype._once_expired = function(key, table) { if (!table) { return true; } if (!table.hasOwnProperty(key)) { return true; } if (typeof table[key] !== 'object') { return true; } var ttl = table[key].ttl || THRESHOLD_TTL_ONCE; var now = Date.now(); var timestamp = table[key].timestamp; return timestamp < now - ttl; }; Intercom.prototype._localStorageChanged = function(event, field) { if (event && event.key) { return event.key === field; } var currentValue = localStorage.getItem(field); if (currentValue === this.previousValues[field]) { return false; } this.previousValues[field] = currentValue; return true; }; Intercom.prototype._onStorageEvent = function(event) { event = event || global.event; var self = this; if (this._localStorageChanged(event, INDEX_EMIT)) { this._transaction(function() { var now = Date.now(); var data = localStorage.getItem(INDEX_EMIT); var messages; try { messages = JSON.parse(data || '[]'); } catch(e) { messages = []; } for (var i = 0; i < messages.length; i++) { if (messages[i].origin === self.origin) continue; if (messages[i].timestamp < self.lastMessage) continue; if (messages[i].id) { if (self.receivedIDs.hasOwnProperty(messages[i].id)) continue; self.receivedIDs[messages[i].id] = true; } self.trigger(messages[i].name, messages[i].payload); } self.lastMessage = now; }); } this._trigger('storage', event); }; Intercom.prototype._emit = function(name, message, id) { id = (typeof id === 'string' || typeof id === 'number') ? String(id) : null; if (id && id.length) { if (this.receivedIDs.hasOwnProperty(id)) return; this.receivedIDs[id] = true; } var packet = { id : id, name : name, origin : this.origin, timestamp : Date.now(), payload : message }; var self = this; this._transaction(function() { var data = localStorage.getItem(INDEX_EMIT) || '[]'; var delimiter = (data === '[]') ? '' : ','; data = [data.substring(0, data.length - 1), delimiter, JSON.stringify(packet), ']'].join(''); localStorage.setItem(INDEX_EMIT, data); self.trigger(name, message); setTimeout(function() { self._cleanup_emit(); }, 50); }); }; Intercom.prototype.emit = function(name, message) { this._emit.apply(this, arguments); this._trigger('emit', name, message); }; Intercom.prototype.once = function(key, fn, ttl) { if (!Intercom.supported) { return; } var self = this; this._transaction(function() { var data; try { data = JSON.parse(localStorage.getItem(INDEX_ONCE) || '{}'); } catch(e) { data = {}; } if (!self._once_expired(key, data)) { return; } data[key] = {}; data[key].timestamp = Date.now(); if (typeof ttl === 'number') { data[key].ttl = ttl * 1000; } localStorage.setItem(INDEX_ONCE, JSON.stringify(data)); fn(); setTimeout(function() { self._cleanup_once(); }, 50); }); }; extend(Intercom.prototype, EventEmitter.prototype); Intercom.supported = (typeof localStorage !== 'undefined'); var INDEX_EMIT = 'intercom'; var INDEX_ONCE = 'intercom_once'; var INDEX_LOCK = 'intercom_lock'; var THRESHOLD_TTL_EMIT = 50000; var THRESHOLD_TTL_ONCE = 1000 * 3600; Intercom.destroy = function() { localStorage.removeItem(INDEX_LOCK); localStorage.removeItem(INDEX_EMIT); localStorage.removeItem(INDEX_ONCE); }; Intercom.getInstance = (function() { var intercom; return function() { if (!intercom) { intercom = new Intercom(); } return intercom; }; })(); module.exports = Intercom; }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"../src/shared.js":30,"./eventemitter.js":2}],4:[function(_dereq_,module,exports){ // Cherry-picked bits of underscore.js, lodash.js /** * Lo-Dash 2.4.0 <http://lodash.com/> * Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/> * Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE> * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Available under MIT license <http://lodash.com/license> */ var ArrayProto = Array.prototype; var nativeForEach = ArrayProto.forEach; var nativeIndexOf = ArrayProto.indexOf; var nativeSome = ArrayProto.some; var ObjProto = Object.prototype; var hasOwnProperty = ObjProto.hasOwnProperty; var nativeKeys = Object.keys; var breaker = {}; function has(obj, key) { return hasOwnProperty.call(obj, key); } var keys = nativeKeys || function(obj) { if (obj !== Object(obj)) throw new TypeError('Invalid object'); var keys = []; for (var key in obj) if (has(obj, key)) keys.push(key); return keys; }; function size(obj) { if (obj == null) return 0; return (obj.length === +obj.length) ? obj.length : keys(obj).length; } function identity(value) { return value; } function each(obj, iterator, context) { var i, length; if (obj == null) return; if (nativeForEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context); } else if (obj.length === +obj.length) { for (i = 0, length = obj.length; i < length; i++) { if (iterator.call(context, obj[i], i, obj) === breaker) return; } } else { var keys = keys(obj); for (i = 0, length = keys.length; i < length; i++) { if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return; } } }; function any(obj, iterator, context) { iterator || (iterator = identity); var result = false; if (obj == null) return result; if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); each(obj, function(value, index, list) { if (result || (result = iterator.call(context, value, index, list))) return breaker; }); return !!result; }; function contains(obj, target) { if (obj == null) return false; if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; return any(obj, function(value) { return value === target; }); }; function Wrapped(value) { this.value = value; } Wrapped.prototype.has = function(key) { return has(this.value, key); }; Wrapped.prototype.contains = function(target) { return contains(this.value, target); }; Wrapped.prototype.size = function() { return size(this.value); }; function nodash(value) { // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor return (value && typeof value == 'object' && !Array.isArray(value) && hasOwnProperty.call(value, '__wrapped__')) ? value : new Wrapped(value); } module.exports = nodash; },{}],5:[function(_dereq_,module,exports){ /* * base64-arraybuffer * https://github.com/niklasvh/base64-arraybuffer * * Copyright (c) 2012 Niklas von Hertzen * Licensed under the MIT license. */ (function(chars){ "use strict"; exports.encode = function(arraybuffer) { var bytes = new Uint8Array(arraybuffer), i, len = bytes.length, base64 = ""; for (i = 0; i < len; i+=3) { base64 += chars[bytes[i] >> 2]; base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)]; base64 += chars[bytes[i + 2] & 63]; } if ((len % 3) === 2) { base64 = base64.substring(0, base64.length - 1) + "="; } else if (len % 3 === 1) { base64 = base64.substring(0, base64.length - 2) + "=="; } return base64; }; exports.decode = function(base64) { var bufferLength = base64.length * 0.75, len = base64.length, i, p = 0, encoded1, encoded2, encoded3, encoded4; if (base64[base64.length - 1] === "=") { bufferLength--; if (base64[base64.length - 2] === "=") { bufferLength--; } } var arraybuffer = new ArrayBuffer(bufferLength), bytes = new Uint8Array(arraybuffer); for (i = 0; i < len; i+=4) { encoded1 = chars.indexOf(base64[i]); encoded2 = chars.indexOf(base64[i+1]); encoded3 = chars.indexOf(base64[i+2]); encoded4 = chars.indexOf(base64[i+3]); bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63); } return arraybuffer; }; })("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); },{}],6:[function(_dereq_,module,exports){ /*! * The buffer module from node.js, for the browser. * * @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org> * @license MIT */ var base64 = _dereq_('base64-js') var ieee754 = _dereq_('ieee754') exports.Buffer = Buffer exports.SlowBuffer = Buffer exports.INSPECT_MAX_BYTES = 50 Buffer.poolSize = 8192 /** * If `Buffer._useTypedArrays`: * === true Use Uint8Array implementation (fastest) * === false Use Object implementation (compatible down to IE6) */ Buffer._useTypedArrays = (function () { // Detect if browser supports Typed Arrays. Supported browsers are IE 10+, Firefox 4+, // Chrome 7+, Safari 5.1+, Opera 11.6+, iOS 4.2+. If the browser does not support adding // properties to `Uint8Array` instances, then that's the same as no `Uint8Array` support // because we need to be able to add all the node Buffer API methods. This is an issue // in Firefox 4-29. Now fixed: https://bugzilla.mozilla.org/show_bug.cgi?id=695438 try { var buf = new ArrayBuffer(0) var arr = new Uint8Array(buf) arr.foo = function () { return 42 } return 42 === arr.foo() && typeof arr.subarray === 'function' // Chrome 9-10 lack `subarray` } catch (e) { return false } })() /** * Class: Buffer * ============= * * The Buffer constructor returns instances of `Uint8Array` that are augmented * with function properties for all the node `Buffer` API functions. We use * `Uint8Array` so that square bracket notation works as expected -- it returns * a single octet. * * By augmenting the instances, we can avoid modifying the `Uint8Array` * prototype. */ function Buffer (subject, encoding, noZero) { if (!(this instanceof Buffer)) return new Buffer(subject, encoding, noZero) var type = typeof subject // Workaround: node's base64 implementation allows for non-padded strings // while base64-js does not. if (encoding === 'base64' && type === 'string') { subject = stringtrim(subject) while (subject.length % 4 !== 0) { subject = subject + '=' } } // Find the length var length if (type === 'number') length = coerce(subject) else if (type === 'string') length = Buffer.byteLength(subject, encoding) else if (type === 'object') length = coerce(subject.length) // assume that object is array-like else throw new Error('First argument needs to be a number, array or string.') var buf if (Buffer._useTypedArrays) { // Preferred: Return an augmented `Uint8Array` instance for best performance buf = Buffer._augment(new Uint8Array(length)) } else { // Fallback: Return THIS instance of Buffer (created by `new`) buf = this buf.length = length buf._isBuffer = true } var i if (Buffer._useTypedArrays && typeof subject.byteLength === 'number') { // Speed optimization -- use set if we're copying from a typed array buf._set(subject) } else if (isArrayish(subject)) { // Treat array-ish objects as a byte array if (Buffer.isBuffer(subject)) { for (i = 0; i < length; i++) buf[i] = subject.readUInt8(i) } else { for (i = 0; i < length; i++) buf[i] = ((subject[i] % 256) + 256) % 256 } } else if (type === 'string') { buf.write(subject, 0, encoding) } else if (type === 'number' && !Buffer._useTypedArrays && !noZero) { for (i = 0; i < length; i++) { buf[i] = 0 } } return buf } // STATIC METHODS // ============== Buffer.isEncoding = function (encoding) { switch (String(encoding).toLowerCase()) { case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'raw': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': return true default: return false } } Buffer.isBuffer = function (b) { return !!(b !== null && b !== undefined && b._isBuffer) } Buffer.byteLength = function (str, encoding) { var ret str = str.toString() switch (encoding || 'utf8') { case 'hex': ret = str.length / 2 break case 'utf8': case 'utf-8': ret = utf8ToBytes(str).length break case 'ascii': case 'binary': case 'raw': ret = str.length break case 'base64': ret = base64ToBytes(str).length break case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': ret = str.length * 2 break default: throw new Error('Unknown encoding') } return ret } Buffer.concat = function (list, totalLength) { assert(isArray(list), 'Usage: Buffer.concat(list[, length])') if (list.length === 0) { return new Buffer(0) } else if (list.length === 1) { return list[0] } var i if (totalLength === undefined) { totalLength = 0 for (i = 0; i < list.length; i++) { totalLength += list[i].length } } var buf = new Buffer(totalLength) var pos = 0 for (i = 0; i < list.length; i++) { var item = list[i] item.copy(buf, pos) pos += item.length } return buf } Buffer.compare = function (a, b) { assert(Buffer.isBuffer(a) && Buffer.isBuffer(b), 'Arguments must be Buffers') var x = a.length var y = b.length for (var i = 0, len = Math.min(x, y); i < len && a[i] === b[i]; i++) {} if (i !== len) { x = a[i] y = b[i] } if (x < y) { return -1 } if (y < x) { return 1 } return 0 } // BUFFER INSTANCE METHODS // ======================= function hexWrite (buf, string, offset, length) { offset = Number(offset) || 0 var remaining = buf.length - offset if (!length) { length = remaining } else { length = Number(length) if (length > remaining) { length = remaining } } // must be an even number of digits var strLen = string.length assert(strLen % 2 === 0, 'Invalid hex string') if (length > strLen / 2) { length = strLen / 2 } for (var i = 0; i < length; i++) { var byte = parseInt(string.substr(i * 2, 2), 16) assert(!isNaN(byte), 'Invalid hex string') buf[offset + i] = byte } return i } function utf8Write (buf, string, offset, length) { var charsWritten = blitBuffer(utf8ToBytes(string), buf, offset, length) return charsWritten } function asciiWrite (buf, string, offset, length) { var charsWritten = blitBuffer(asciiToBytes(string), buf, offset, length) return charsWritten } function binaryWrite (buf, string, offset, length) { return asciiWrite(buf, string, offset, length) } function base64Write (buf, string, offset, length) { var charsWritten = blitBuffer(base64ToBytes(string), buf, offset, length) return charsWritten } function utf16leWrite (buf, string, offset, length) { var charsWritten = blitBuffer(utf16leToBytes(string), buf, offset, length) return charsWritten } Buffer.prototype.write = function (string, offset, length, encoding) { // Support both (string, offset, length, encoding) // and the legacy (string, encoding, offset, length) if (isFinite(offset)) { if (!isFinite(length)) { encoding = length length = undefined } } else { // legacy var swap = encoding encoding = offset offset = length length = swap } offset = Number(offset) || 0 var remaining = this.length - offset if (!length) { length = remaining } else { length = Number(length) if (length > remaining) { length = remaining } } encoding = String(encoding || 'utf8').toLowerCase() var ret switch (encoding) { case 'hex': ret = hexWrite(this, string, offset, length) break case 'utf8': case 'utf-8': ret = utf8Write(this, string, offset, length) break case 'ascii': ret = asciiWrite(this, string, offset, length) break case 'binary': ret = binaryWrite(this, string, offset, length) break case 'base64': ret = base64Write(this, string, offset, length) break case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': ret = utf16leWrite(this, string, offset, length) break default: throw new Error('Unknown encoding') } return ret } Buffer.prototype.toString = function (encoding, start, end) { var self = this encoding = String(encoding || 'utf8').toLowerCase() start = Number(start) || 0 end = (end === undefined) ? self.length : Number(end) // Fastpath empty strings if (end === start) return '' var ret switch (encoding) { case 'hex': ret = hexSlice(self, start, end) break case 'utf8': case 'utf-8': ret = utf8Slice(self, start, end) break case 'ascii': ret = asciiSlice(self, start, end) break case 'binary': ret = binarySlice(self, start, end) break case 'base64': ret = base64Slice(self, start, end) break case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': ret = utf16leSlice(self, start, end) break default: throw new Error('Unknown encoding') } return ret } Buffer.prototype.toJSON = function () { return { type: 'Buffer', data: Array.prototype.slice.call(this._arr || this, 0) } } Buffer.prototype.equals = function (b) { assert(Buffer.isBuffer(b), 'Argument must be a Buffer') return Buffer.compare(this, b) === 0 } Buffer.prototype.compare = function (b) { assert(Buffer.isBuffer(b), 'Argument must be a Buffer') return Buffer.compare(this, b) } // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) Buffer.prototype.copy = function (target, target_start, start, end) { var source = this if (!start) start = 0 if (!end && end !== 0) end = this.length if (!target_start) target_start = 0 // Copy 0 bytes; we're done if (end === start) return if (target.length === 0 || source.length === 0) return // Fatal error conditions assert(end >= start, 'sourceEnd < sourceStart') assert(target_start >= 0 && target_start < target.length, 'targetStart out of bounds') assert(start >= 0 && start < source.length, 'sourceStart out of bounds') assert(end >= 0 && end <= source.length, 'sourceEnd out of bounds') // Are we oob? if (end > this.length) end = this.length if (target.length - target_start < end - start) end = target.length - target_start + start var len = end - start if (len < 100 || !Buffer._useTypedArrays) { for (var i = 0; i < len; i++) { target[i + target_start] = this[i + start] } } else { target._set(this.subarray(start, start + len), target_start) } } function base64Slice (buf, start, end) { if (start === 0 && end === buf.length) { return base64.fromByteArray(buf) } else { return base64.fromByteArray(buf.slice(start, end)) } } function utf8Slice (buf, start, end) { var res = '' var tmp = '' end = Math.min(buf.length, end) for (var i = start; i < end; i++) { if (buf[i] <= 0x7F) { res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i]) tmp = '' } else { tmp += '%' + buf[i].toString(16) } } return res + decodeUtf8Char(tmp) } function asciiSlice (buf, start, end) { var ret = '' end = Math.min(buf.length, end) for (var i = start; i < end; i++) { ret += String.fromCharCode(buf[i]) } return ret } function binarySlice (buf, start, end) { return asciiSlice(buf, start, end) } function hexSlice (buf, start, end) { var len = buf.length if (!start || start < 0) start = 0 if (!end || end < 0 || end > len) end = len var out = '' for (var i = start; i < end; i++) { out += toHex(buf[i]) } return out } function utf16leSlice (buf, start, end) { var bytes = buf.slice(start, end) var res = '' for (var i = 0; i < bytes.length; i += 2) { res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) } return res } Buffer.prototype.slice = function (start, end) { var len = this.length start = clamp(start, len, 0) end = clamp(end, len, len) if (Buffer._useTypedArrays) { return Buffer._augment(this.subarray(start, end)) } else { var sliceLen = end - start var newBuf = new Buffer(sliceLen, undefined, true) for (var i = 0; i < sliceLen; i++) { newBuf[i] = this[i + start] } return newBuf } } // `get` will be removed in Node 0.13+ Buffer.prototype.get = function (offset) { console.log('.get() is deprecated. Access using array indexes instead.') return this.readUInt8(offset) } // `set` will be removed in Node 0.13+ Buffer.prototype.set = function (v, offset) { console.log('.set() is deprecated. Access using array indexes instead.') return this.writeUInt8(v, offset) } Buffer.prototype.readUInt8 = function (offset, noAssert) { if (!noAssert) { assert(offset !== undefined && offset !== null, 'missing offset') assert(offset < this.length, 'Trying to read beyond buffer length') } if (offset >= this.length) return return this[offset] } function readUInt16 (buf, offset, littleEndian, noAssert) { if (!noAssert) { assert(typeof littleEndian === 'boolean', 'missing or invalid endian') assert(offset !== undefined && offset !== null, 'missing offset') assert(offset + 1 < buf.length, 'Trying to read beyond buffer length') } var len = buf.length if (offset >= len) return var val if (littleEndian) { val = buf[offset] if (offset + 1 < len) val |= buf[offset + 1] << 8 } else { val = buf[offset] << 8 if (offset + 1 < len) val |= buf[offset + 1] } return val } Buffer.prototype.readUInt16LE = function (offset, noAssert) { return readUInt16(this, offset, true, noAssert) } Buffer.prototype.readUInt16BE = function (offset, noAssert) { return readUInt16(this, offset, false, noAssert) } function readUInt32 (buf, offset, littleEndian, noAssert) { if (!noAssert) { assert(typeof littleEndian === 'boolean', 'missing or invalid endian') assert(offset !== undefined && offset !== null, 'missing offset') assert(offset + 3 < buf.length, 'Trying to read beyond buffer length') } var len = buf.length if (offset >= len) return var val if (littleEndian) { if (offset + 2 < len) val = buf[offset + 2] << 16 if (offset + 1 < len) val |= buf[offset + 1] << 8 val |= buf[offset] if (offset + 3 < len) val = val + (buf[offset + 3] << 24 >>> 0) } else { if (offset + 1 < len) val = buf[offset + 1] << 16 if (offset + 2 < len) val |= buf[offset + 2] << 8 if (offset + 3 < len) val |= buf[offset + 3] val = val + (buf[offset] << 24 >>> 0) } return val } Buffer.prototype.readUInt32LE = function (offset, noAssert) { return readUInt32(this, offset, true, noAssert) } Buffer.prototype.readUInt32BE = function (offset, noAssert) { return readUInt32(this, offset, false, noAssert) } Buffer.prototype.readInt8 = function (offset, noAssert) { if (!noAssert) { assert(offset !== undefined && offset !== null, 'missing offset') assert(offset < this.length, 'Trying to read beyond buffer length') } if (offset >= this.length) return var neg = this[offset] & 0x80 if (neg) return (0xff - this[offset] + 1) * -1 else return this[offset] } function readInt16 (buf, offset, littleEndian, noAssert) { if (!noAssert) { assert(typeof littleEndian === 'boolean', 'missing or invalid endian') assert(offset !== undefined && offset !== null, 'missing offset') assert(offset + 1 < buf.length, 'Trying to read beyond buffer length') } var len = buf.length if (offset >= len) return var val = readUInt16(buf, offset, littleEndian, true) var neg = val & 0x8000 if (neg) return (0xffff - val + 1) * -1 else return val } Buffer.prototype.readInt16LE = function (offset, noAssert) { return readInt16(this, offset, true, noAssert) } Buffer.prototype.readInt16BE = function (offset, noAssert) { return readInt16(this, offset, false, noAssert) } function readInt32 (buf, offset, littleEndian, noAssert) { if (!noAssert) { assert(typeof littleEndian === 'boolean', 'missing or invalid endian') assert(offset !== undefined && offset !== null, 'missing offset') assert(offset + 3 < buf.length, 'Trying to read beyond buffer length') } var len = buf.length if (offset >= len) return var val = readUInt32(buf, offset, littleEndian, true) var neg = val & 0x80000000 if (neg) return (0xffffffff - val + 1) * -1 else return val } Buffer.prototype.readInt32LE = function (offset, noAssert) { return readInt32(this, offset, true, noAssert) } Buffer.prototype.readInt32BE = function (offset, noAssert) { return readInt32(this, offset, false, noAssert) } function readFloat (buf, offset, littleEndian, noAssert) { if (!noAssert) { assert(typeof littleEndian === 'boolean', 'missing or invalid endian') assert(offset + 3 < buf.length, 'Trying to read beyond buffer length') } return ieee754.read(buf, offset, littleEndian, 23, 4) } Buffer.prototype.readFloatLE = function (offset, noAssert) { return readFloat(this, offset, true, noAssert) } Buffer.prototype.readFloatBE = function (offset, noAssert) { return readFloat(this, offset, false, noAssert) } function readDouble (buf, offset, littleEndian, noAssert) { if (!noAssert) { assert(typeof littleEndian === 'boolean', 'missing or invalid endian') assert(offset + 7 < buf.length, 'Trying to read beyond buffer length') } return ieee754.read(buf, offset, littleEndian, 52, 8) } Buffer.prototype.readDoubleLE = function (offset, noAssert) { return readDouble(this, offset, true, noAssert) } Buffer.prototype.readDoubleBE = function (offset, noAssert) { return readDouble(this, offset, false, noAssert) } Buffer.prototype.writeUInt8 = function (value, offset, noAssert) { if (!noAssert) { assert(value !== undefined && value !== null, 'missing value') assert(offset !== undefined && offset !== null, 'missing offset') assert(offset < this.length, 'trying to write beyond buffer length') verifuint(value, 0xff) } if (offset >= this.length) return this[offset] = value return offset + 1 } function writeUInt16 (buf, value, offset, littleEndian, noAssert) { if (!noAssert) { assert(value !== undefined && value !== null, 'missing value') assert(typeof littleEndian === 'boolean', 'missing or invalid endian') assert(offset !== undefined && offset !== null, 'missing offset') assert(offset + 1 < buf.length, 'trying to write beyond buffer length') verifuint(value, 0xffff) } var len = buf.length if (offset >= len) return for (var i = 0, j = Math.min(len - offset, 2); i < j; i++) { buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> (littleEndian ? i : 1 - i) * 8 } return offset + 2 } Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) { return writeUInt16(this, value, offset, true, noAssert) } Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) { return writeUInt16(this, value, offset, false, noAssert) } function writeUInt32 (buf, value, offset, littleEndian, noAssert) { if (!noAssert) { assert(value !== undefined && value !== null, 'missing value') assert(typeof littleEndian === 'boolean', 'missing or invalid endian') assert(offset !== undefined && offset !== null, 'missing offset') assert(offset + 3 < buf.length, 'trying to write beyond buffer length') verifuint(value, 0xffffffff) } var len = buf.length if (offset >= len) return for (var i = 0, j = Math.min(len - offset, 4); i < j; i++) { buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff } return offset + 4 } Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) { return writeUInt32(this, value, offset, true, noAssert) } Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) { return writeUInt32(this, value, offset, false, noAssert) } Buffer.prototype.writeInt8 = function (value, offset, noAssert) { if (!noAssert) { assert(value !== undefined && value !== null, 'missing value') assert(offset !== undefined && offset !== null, 'missing offset') assert(offset < this.length, 'Trying to write beyond buffer length') verifsint(value, 0x7f, -0x80) } if (offset >= this.length) return if (value >= 0) this.writeUInt8(value, offset, noAssert) else this.writeUInt8(0xff + value + 1, offset, noAssert) return offset + 1 } function writeInt16 (buf, value, offset, littleEndian, noAssert) { if (!noAssert) { assert(value !== undefined && value !== null, 'missing value') assert(typeof littleEndian === 'boolean', 'missing or invalid endian') assert(offset !== undefined && offset !== null, 'missing offset') assert(offset + 1 < buf.length, 'Trying to write beyond buffer length') verifsint(value, 0x7fff, -0x8000) } var len = buf.length if (offset >= len) return if (value >= 0) writeUInt16(buf, value, offset, littleEndian, noAssert) else writeUInt16(buf, 0xffff + value + 1, offset, littleEndian, noAssert) return offset + 2 } Buffer.prototype.writeInt16LE = function (value, offset, noAssert) { return writeInt16(this, value, offset, true, noAssert) } Buffer.prototype.writeInt16BE = function (value, offset, noAssert) { return writeInt16(this, value, offset, false, noAssert) } function writeInt32 (buf, value, offset, littleEndian, noAssert) { if (!noAssert) { assert(value !== undefined && value !== null, 'missing value') assert(typeof littleEndian === 'boolean', 'missing or invalid endian') assert(offset !== undefined && offset !== null, 'missing offset') assert(offset + 3 < buf.length, 'Trying to write beyond buffer length') verifsint(value, 0x7fffffff, -0x80000000) } var len = buf.length if (offset >= len) return if (value >= 0) writeUInt32(buf, value, offset, littleEndian, noAssert) else writeUInt32(buf, 0xffffffff + value + 1, offset, littleEndian, noAssert) return offset + 4 } Buffer.prototype.writeInt32LE = function (value, offset, noAssert) { return writeInt32(this, value, offset, true, noAssert) } Buffer.prototype.writeInt32BE = function (value, offset, noAssert) { return writeInt32(this, value, offset, false, noAssert) } function writeFloat (buf, value, offset, littleEndian, noAssert) { if (!noAssert) { assert(value !== undefined && value !== null, 'missing value') assert(typeof littleEndian === 'boolean', 'missing or invalid endian') assert(offset !== undefined && offset !== null, 'missing offset') assert(offset + 3 < buf.length, 'Trying to write beyond buffer length') verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38) } var len = buf.length if (offset >= len) return ieee754.write(buf, value, offset, littleEndian, 23, 4) return offset + 4 } Buffer.prototype.writeFloatLE = function (value, offset, noAssert) { return writeFloat(this, value, offset, true, noAssert) } Buffer.prototype.writeFloatBE = function (value, offset, noAssert) { return writeFloat(this, value, offset, false, noAssert) } function writeDouble (buf, value, offset, littleEndian, noAssert) { if (!noAssert) { assert(value !== undefined && value !== null, 'missing value') assert(typeof littleEndian === 'boolean', 'missing or invalid endian') assert(offset !== undefined && offset !== null, 'missing offset') assert(offset + 7 < buf.length, 'Trying to write beyond buffer length') verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308) } var len = buf.length if (offset >= len) return ieee754.write(buf, value, offset, littleEndian, 52, 8) return offset + 8 } Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) { return writeDouble(this, value, offset, true, noAssert) } Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) { return writeDouble(this, value, offset, false, noAssert) } // fill(value, start=0, end=buffer.length) Buffer.prototype.fill = function (value, start, end) { if (!value) value = 0 if (!start) start = 0 if (!end) end = this.length assert(end >= start, 'end < start') // Fill 0 bytes; we're done if (end === start) return if (this.length === 0) return assert(start >= 0 && start < this.length, 'start out of bounds') assert(end >= 0 && end <= this.length, 'end out of bounds') var i if (typeof value === 'number') { for (i = start; i < end; i++) { this[i] = value } } else { var bytes = utf8ToBytes(value.toString()) var len = bytes.length for (i = start; i < end; i++) { this[i] = bytes[i % len] } } return this } Buffer.prototype.inspect = function () { var out = [] var len = this.length for (var i = 0; i < len; i++) { out[i] = toHex(this[i]) if (i === exports.INSPECT_MAX_BYTES) { out[i + 1] = '...' break } } return '<Buffer ' + out.join(' ') + '>' } /** * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance. * Added in Node 0.12. Only available in browsers that support ArrayBuffer. */ Buffer.prototype.toArrayBuffer = function () { if (typeof Uint8Array !== 'undefined') { if (Buffer._useTypedArrays) { return (new Buffer(this)).buffer } else { var buf = new Uint8Array(this.length) for (var i = 0, len = buf.length; i < len; i += 1) { buf[i] = this[i] } return buf.buffer } } else { throw new Error('Buffer.toArrayBuffer not supported in this browser') } } // HELPER FUNCTIONS // ================ var BP = Buffer.prototype /** * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods */ Buffer._augment = function (arr) { arr._isBuffer = true // save reference to original Uint8Array get/set methods before overwriting arr._get = arr.get arr._set = arr.set // deprecated, will be removed in node 0.13+ arr.get = BP.get arr.set = BP.set arr.write = BP.write arr.toString = BP.toString arr.toLocaleString = BP.toString arr.toJSON = BP.toJSON arr.equals = BP.equals arr.compare = BP.compare arr.copy = BP.copy arr.slice = BP.slice arr.readUInt8 = BP.readUInt8 arr.readUInt16LE = BP.readUInt16LE arr.readUInt16BE = BP.readUInt16BE arr.readUInt32LE = BP.readUInt32LE arr.readUInt32BE = BP.readUInt32BE arr.readInt8 = BP.readInt8 arr.readInt16LE = BP.readInt16LE arr.readInt16BE = BP.readInt16BE arr.readInt32LE = BP.readInt32LE arr.readInt32BE = BP.readInt32BE arr.readFloatLE = BP.readFloatLE arr.readFloatBE = BP.readFloatBE arr.readDoubleLE = BP.readDoubleLE arr.readDoubleBE = BP.readDoubleBE arr.writeUInt8 = BP.writeUInt8 arr.writeUInt16LE = BP.writeUInt16LE arr.writeUInt16BE = BP.writeUInt16BE arr.writeUInt32LE = BP.writeUInt32LE arr.writeUInt32BE = BP.writeUInt32BE arr.writeInt8 = BP.writeInt8 arr.writeInt16LE = BP.writeInt16LE arr.writeInt16BE = BP.writeInt16BE arr.writeInt32LE = BP.writeInt32LE arr.writeInt32BE = BP.writeInt32BE arr.writeFloatLE = BP.writeFloatLE arr.writeFloatBE = BP.writeFloatBE arr.writeDoubleLE = BP.writeDoubleLE arr.writeDoubleBE = BP.writeDoubleBE arr.fill = BP.fill arr.inspect = BP.inspect arr.toArrayBuffer = BP.toArrayBuffer return arr } function stringtrim (str) { if (str.trim) return str.trim() return str.replace(/^\s+|\s+$/g, '') } // slice(start, end) function clamp (index, len, defaultValue) { if (typeof index !== 'number') return defaultValue index = ~~index; // Coerce to integer. if (index >= len) return len if (index >= 0) return index index += len if (index >= 0) return index return 0 } function coerce (length) { // Coerce length to a number (possibly NaN), round up // in case it's fractional (e.g. 123.456) then do a // double negate to coerce a NaN to 0. Easy, right? length = ~~Math.ceil(+length) return length < 0 ? 0 : length } function isArray (subject) { return (Array.isArray || function (subject) { return Object.prototype.toString.call(subject) === '[object Array]' })(subject) } function isArrayish (subject) { return isArray(subject) || Buffer.isBuffer(subject) || subject && typeof subject === 'object' && typeof subject.length === 'number' } function toHex (n) { if (n < 16) return '0' + n.toString(16) return n.toString(16) } function utf8ToBytes (str) { var byteArray = [] for (var i = 0; i < str.length; i++) { var b = str.charCodeAt(i) if (b <= 0x7F) { byteArray.push(b) } else { var start = i if (b >= 0xD800 && b <= 0xDFFF) i++ var h = encodeURIComponent(str.slice(start, i+1)).substr(1).split('%') for (var j = 0; j < h.length; j++) { byteArray.push(parseInt(h[j], 16)) } } } return byteArray } function asciiToBytes (str) { var byteArray = [] for (var i = 0; i < str.length; i++) { // Node's code seems to be doing this and not & 0x7F.. byteArray.push(str.charCodeAt(i) & 0xFF) } return byteArray } function utf16leToBytes (str) { var c, hi, lo var byteArray = [] for (var i = 0; i < str.length; i++) { c = str.charCodeAt(i) hi = c >> 8 lo = c % 256 byteArray.push(lo) byteArray.push(hi) } return byteArray } function base64ToBytes (str) { return base64.toByteArray(str) } function blitBuffer (src, dst, offset, length) { for (var i = 0; i < length; i++) { if ((i + offset >= dst.length) || (i >= src.length)) break dst[i + offset] = src[i] } return i } function decodeUtf8Char (str) { try { return decodeURIComponent(str) } catch (err) { return String.fromCharCode(0xFFFD) // UTF 8 invalid char } } /* * We have to make sure that the value is a valid integer. This means that it * is non-negative. It has no fractional component and that it does not * exceed the maximum allowed value. */ function verifuint (value, max) { assert(typeof value === 'number', 'cannot write a non-number as a number') assert(value >= 0, 'specified a negative value for writing an unsigned value') assert(value <= max, 'value is larger than maximum value for type') assert(Math.floor(value) === value, 'value has a fractional component') } function verifsint (value, max, min) { assert(typeof value === 'number', 'cannot write a non-number as a number') assert(value <= max, 'value larger than maximum allowed value') assert(value >= min, 'value smaller than minimum allowed value') assert(Math.floor(value) === value, 'value has a fractional component') } function verifIEEE754 (value, max, min) { assert(typeof value === 'number', 'cannot write a non-number as a number') assert(value <= max, 'value larger than maximum allowed value') assert(value >= min, 'value smaller than minimum allowed value') } function assert (test, message) { if (!test) throw new Error(message || 'Failed assertion') } },{"base64-js":7,"ieee754":8}],7:[function(_dereq_,module,exports){ var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; ;(function (exports) { 'use strict'; var Arr = (typeof Uint8Array !== 'undefined') ? Uint8Array : Array var PLUS = '+'.charCodeAt(0) var SLASH = '/'.charCodeAt(0) var NUMBER = '0'.charCodeAt(0) var LOWER = 'a'.charCodeAt(0) var UPPER = 'A'.charCodeAt(0) function decode (elt) { var code = elt.charCodeAt(0) if (code === PLUS) return 62 // '+' if (code === SLASH) return 63 // '/' if (code < NUMBER) return -1 //no match if (code < NUMBER + 10) return code - NUMBER + 26 + 26 if (code < UPPER + 26) return code - UPPER if (code < LOWER + 26) return code - LOWER + 26 } function b64ToByteArray (b64) { var i, j, l, tmp, placeHolders, arr if (b64.length % 4 > 0) { throw new Error('Invalid string. Length must be a multiple of 4') } // the number of equal signs (place holders) // if there are two placeholders, than the two characters before it // represent one byte // if there is only one, then the three characters before it represent 2 bytes // this is just a cheap hack to not do indexOf twice var len = b64.length placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 // base64 is 4/3 + up to two characters of the original data arr = new Arr(b64.length * 3 / 4 - placeHolders) // if there are placeholders, only get up to the last complete 4 chars l = placeHolders > 0 ? b64.length - 4 : b64.length var L = 0 function push (v) { arr[L++] = v } for (i = 0, j = 0; i < l; i += 4, j += 3) { tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) push((tmp & 0xFF0000) >> 16) push((tmp & 0xFF00) >> 8) push(tmp & 0xFF) } if (placeHolders === 2) { tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) push(tmp & 0xFF) } else if (placeHolders === 1) { tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) push((tmp >> 8) & 0xFF) push(tmp & 0xFF) } return arr } function uint8ToBase64 (uint8) { var i, extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes output = "", temp, length function encode (num) { return lookup.charAt(num) } function tripletToBase64 (num) { return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) } // go through the array every three bytes, we'll deal with trailing stuff later for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) output += tripletToBase64(temp) } // pad the end with zeros, but make sure to not forget the extra bytes switch (extraBytes) { case 1: temp = uint8[uint8.length - 1] output += encode(temp >> 2) output += encode((temp << 4) & 0x3F) output += '==' break case 2: temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) output += encode(temp >> 10) output += encode((temp >> 4) & 0x3F) output += encode((temp << 2) & 0x3F) output += '=' break } return output } exports.toByteArray = b64ToByteArray exports.fromByteArray = uint8ToBase64 }(typeof exports === 'undefined' ? (this.base64js = {}) : exports)) },{}],8:[function(_dereq_,module,exports){ exports.read = function(buffer, offset, isLE, mLen, nBytes) { var e, m, eLen = nBytes * 8 - mLen - 1, eMax = (1 << eLen) - 1, eBias = eMax >> 1, nBits = -7, i = isLE ? (nBytes - 1) : 0, d = isLE ? -1 : 1, s = buffer[offset + i]; i += d; e = s & ((1 << (-nBits)) - 1); s >>= (-nBits); nBits += eLen; for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8); m = e & ((1 << (-nBits)) - 1); e >>= (-nBits); nBits += mLen; for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8); if (e === 0) { e = 1 - eBias; } else if (e === eMax) { return m ? NaN : ((s ? -1 : 1) * Infinity); } else { m = m + Math.pow(2, mLen); e = e - eBias; } return (s ? -1 : 1) * m * Math.pow(2, e - mLen); }; exports.write = function(buffer, value, offset, isLE, mLen, nBytes) { var e, m, c, eLen = nBytes * 8 - mLen - 1, eMax = (1 << eLen) - 1, eBias = eMax >> 1, rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0), i = isLE ? 0 : (nBytes - 1), d = isLE ? 1 : -1, s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; value = Math.abs(value); if (isNaN(value) || value === Infinity) { m = isNaN(value) ? 1 : 0; e = eMax; } else { e = Math.floor(Math.log(value) / Math.LN2); if (value * (c = Math.pow(2, -e)) < 1) { e--; c *= 2; } if (e + eBias >= 1) { value += rt / c; } else { value += rt * Math.pow(2, 1 - eBias); } if (value * c >= 2) { e++; c /= 2; } if (e + eBias >= eMax) { m = 0; e = eMax; } else if (e + eBias >= 1) { m = (value * c - 1) * Math.pow(2, mLen); e = e + eBias; } else { m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); e = 0; } } for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8); e = (e << mLen) | m; eLen += mLen; for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8); buffer[offset + i - d] |= s * 128; }; },{}],9:[function(_dereq_,module,exports){ (function (process){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. // resolves . and .. elements in a path array with directory names there // must be no slashes, empty elements, or device names (c:\) in the array // (so also no leading and trailing slashes - it does not distinguish // relative and absolute paths) function normalizeArray(parts, allowAboveRoot) { // if the path tries to go above the root, `up` ends up > 0 var up = 0; for (var i = parts.length - 1; i >= 0; i--) { var last = parts[i]; if (last === '.') { parts.splice(i, 1); } else if (last === '..') { parts.splice(i, 1); up++; } else if (up) { parts.splice(i, 1); up--; } } // if the path is allowed to go above the root, restore leading ..s if (allowAboveRoot) { for (; up--; up) { parts.unshift('..'); } } return parts; } // Split a filename into [root, dir, basename, ext], unix version // 'root' is just a slash, or nothing. var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; var splitPath = function(filename) { return splitPathRe.exec(filename).slice(1); }; // path.resolve([from ...], to) // posix version exports.resolve = function() { var resolvedPath = '', resolvedAbsolute = false; for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { var path = (i >= 0) ? arguments[i] : process.cwd(); // Skip empty and invalid entries if (typeof path !== 'string') { throw new TypeError('Arguments to path.resolve must be strings'); } else if (!path) { continue; } resolvedPath = path + '/' + resolvedPath; resolvedAbsolute = path.charAt(0) === '/'; } // At this point the path should be resolved to a full absolute path, but // handle relative paths to be safe (might happen when process.cwd() fails) // Normalize the path resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { return !!p; }), !resolvedAbsolute).join('/'); return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; }; // path.normalize(path) // posix version exports.normalize = function(path) { var isAbsolute = exports.isAbsolute(path), trailingSlash = substr(path, -1) === '/'; // Normalize the path path = normalizeArray(filter(path.split('/'), function(p) { return !!p; }), !isAbsolute).join('/'); if (!path && !isAbsolute) { path = '.'; } if (path && trailingSlash) { path += '/'; } return (isAbsolute ? '/' : '') + path; }; // posix version exports.isAbsolute = function(path) { return path.charAt(0) === '/'; }; // posix version exports.join = function() { var paths = Array.prototype.slice.call(arguments, 0); return exports.normalize(filter(paths, function(p, index) { if (typeof p !== 'string') { throw new TypeError('Arguments to path.join must be strings'); } return p; }).join('/')); }; // path.relative(from, to) // posix version exports.relative = function(from, to) { from = exports.resolve(from).substr(1); to = exports.resolve(to).substr(1); function trim(arr) { var start = 0; for (; start < arr.length; start++) { if (arr[start] !== '') break; } var end = arr.length - 1; for (; end >= 0; end--) { if (arr[end] !== '') break; } if (start > end) return []; return arr.slice(start, end - start + 1); } var fromParts = trim(from.split('/')); var toParts = trim(to.split('/')); var length = Math.min(fromParts.length, toParts.length); var samePartsLength = length; for (var i = 0; i < length; i++) { if (fromParts[i] !== toParts[i]) { samePartsLength = i; break; } } var outputParts = []; for (var i = samePartsLength; i < fromParts.length; i++) { outputParts.push('..'); } outputParts = outputParts.concat(toParts.slice(samePartsLength)); return outputParts.join('/'); }; exports.sep = '/'; exports.delimiter = ':'; exports.dirname = function(path) { var result = splitPath(path), root = result[0], dir = result[1]; if (!root && !dir) { // No dirname whatsoever return '.'; } if (dir) { // It has a dirname, strip trailing slash dir = dir.substr(0, dir.length - 1); } return root + dir; }; exports.basename = function(path, ext) { var f = splitPath(path)[2]; // TODO: make this comparison case-insensitive on windows? if (ext && f.substr(-1 * ext.length) === ext) { f = f.substr(0, f.length - ext.length); } return f; }; exports.extname = function(path) { return splitPath(path)[3]; }; function filter (xs, f) { if (xs.filter) return xs.filter(f); var res = []; for (var i = 0; i < xs.length; i++) { if (f(xs[i], i, xs)) res.push(xs[i]); } return res; } // String.prototype.substr - negative index don't work in IE8 var substr = 'ab'.substr(-1) === 'b' ? function (str, start, len) { return str.substr(start, len) } : function (str, start, len) { if (start < 0) start = str.length + start; return str.substr(start, len); } ; }).call(this,_dereq_("FWaASH")) },{"FWaASH":10}],10:[function(_dereq_,module,exports){ // shim for using process in browser var process = module.exports = {}; process.nextTick = (function () { var canSetImmediate = typeof window !== 'undefined' && window.setImmediate; var canPost = typeof window !== 'undefined' && window.postMessage && window.addEventListener ; if (canSetImmediate) { return function (f) { return window.setImmediate(f) }; } if (canPost) { var queue = []; window.addEventListener('message', function (ev) { var source = ev.source; if ((source === window || source === null) && ev.data === 'process-tick') { ev.stopPropagation(); if (queue.length > 0) { var fn = queue.shift(); fn(); } } }, true); return function nextTick(fn) { queue.push(fn); window.postMessage('process-tick', '*'); }; } return function nextTick(fn) { setTimeout(fn, 0); }; })(); process.title = 'browser'; process.browser = true; process.env = {}; process.argv = []; function noop() {} process.on = noop; process.addListener = noop; process.once = noop; process.off = noop; process.removeListener = noop; process.removeAllListeners = noop; process.emit = noop; process.binding = function (name) { throw new Error('process.binding is not supported'); } // TODO(shtylman) process.cwd = function () { return '/' }; process.chdir = function (dir) { throw new Error('process.chdir is not supported'); }; },{}],11:[function(_dereq_,module,exports){ (function (process){ ;(function (_dereq_, exports, module, platform) { if (module) module.exports = minimatch else exports.minimatch = minimatch if (!_dereq_) { _dereq_ = function (id) { switch (id) { case "sigmund": return function sigmund (obj) { return JSON.stringify(obj) } case "path": return { basename: function (f) { f = f.split(/[\/\\]/) var e = f.pop() if (!e) e = f.pop() return e }} case "lru-cache": return function LRUCache () { // not quite an LRU, but still space-limited. var cache = {} var cnt = 0 this.set = function (k, v) { cnt ++ if (cnt >= 100) cache = {} cache[k] = v } this.get = function (k) { return cache[k] } } } } } minimatch.Minimatch = Minimatch var LRU = _dereq_("lru-cache") , cache = minimatch.cache = new LRU({max: 100}) , GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} , sigmund = _dereq_("sigmund") var path = _dereq_("path") // any single thing other than / // don't need to escape / when using new RegExp() , qmark = "[^/]" // * => any number of characters , star = qmark + "*?" // ** when dots are allowed. Anything goes, except .. and . // not (^ or / followed by one or two dots followed by $ or /), // followed by anything, any number of times. , twoStarDot = "(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?" // not a ^ or / followed by a dot, // followed by anything, any number of times. , twoStarNoDot = "(?:(?!(?:\\\/|^)\\.).)*?" // characters that need to be escaped in RegExp. , reSpecials = charSet("().*{}+?[]^$\\!") // "abc" -> { a:true, b:true, c:true } function charSet (s) { return s.split("").reduce(function (set, c) { set[c] = true return set }, {}) } // normalizes slashes. var slashSplit = /\/+/ minimatch.filter = filter function filter (pattern, options) { options = options || {} return function (p, i, list) { return minimatch(p, pattern, options) } } function ext (a, b) { a = a || {} b = b || {} var t = {} Object.keys(b).forEach(function (k) { t[k] = b[k] }) Object.keys(a).forEach(function (k) { t[k] = a[k] }) return t } minimatch.defaults = function (def) { if (!def || !Object.keys(def).length) return minimatch var orig = minimatch var m = function minimatch (p, pattern, options) { return orig.minimatch(p, pattern, ext(def, options)) } m.Minimatch = function Minimatch (pattern, options) { return new orig.Minimatch(pattern, ext(def, options)) } return m } Minimatch.defaults = function (def) { if (!def || !Object.keys(def).length) return Minimatch return minimatch.defaults(def).Minimatch } function minimatch (p, pattern, options) { if (typeof pattern !== "string") { throw new TypeError("glob pattern string required") } if (!options) options = {} // shortcut: comments match nothing. if (!options.nocomment && pattern.charAt(0) === "#") { return false } // "" only matches "" if (pattern.trim() === "") return p === "" return new Minimatch(pattern, options).match(p) } function Minimatch (pattern, options) { if (!(this instanceof Minimatch)) { return new Minimatch(pattern, options, cache) } if (typeof pattern !== "string") { throw new TypeError("glob pattern string required") } if (!options) options = {} pattern = pattern.trim() // windows: need to use /, not \ // On other platforms, \ is a valid (albeit bad) filename char. if (platform === "win32") { pattern = pattern.split("\\").join("/") } // lru storage. // these things aren't particularly big, but walking down the string // and turning it into a regexp can get pretty costly. var cacheKey = pattern + "\n" + sigmund(options) var cached = minimatch.cache.get(cacheKey) if (cached) return cached minimatch.cache.set(cacheKey, this) this.options = options this.set = [] this.pattern = pattern this.regexp = null this.negate = false this.comment = false this.empty = false // make the set of regexps etc. this.make() } Minimatch.prototype.debug = function() {} Minimatch.prototype.make = make function make () { // don't do it more than once. if (this._made) return var pattern = this.pattern var options = this.options // empty patterns and comments match nothing. if (!options.nocomment && pattern.charAt(0) === "#") { this.comment = true return } if (!pattern) { this.empty = true return } // step 1: figure out negation, etc. this.parseNegate() // step 2: expand braces var set = this.globSet = this.braceExpand() if (options.debug) this.debug = console.error this.debug(this.pattern, set) // step 3: now we have a set, so turn each one into a series of path-portion // matching patterns. // These will be regexps, except in the case of "**", which is // set to the GLOBSTAR object for globstar behavior, // and will not contain any / characters set = this.globParts = set.map(function (s) { return s.split(slashSplit) }) this.debug(this.pattern, set) // glob --> regexps set = set.map(function (s, si, set) { return s.map(this.parse, this) }, this) this.debug(this.pattern, set) // filter out everything that didn't compile properly. set = set.filter(function (s) { return -1 === s.indexOf(false) }) this.debug(this.pattern, set) this.set = set } Minimatch.prototype.parseNegate = parseNegate function parseNegate () { var pattern = this.pattern , negate = false , options = this.options , negateOffset = 0 if (options.nonegate) return for ( var i = 0, l = pattern.length ; i < l && pattern.charAt(i) === "!" ; i ++) { negate = !negate negateOffset ++ } if (negateOffset) this.pattern = pattern.substr(negateOffset) this.negate = negate } // Brace expansion: // a{b,c}d -> abd acd // a{b,}c -> abc ac // a{0..3}d -> a0d a1d a2d a3d // a{b,c{d,e}f}g -> abg acdfg acefg // a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg // // Invalid sets are not expanded. // a{2..}b -> a{2..}b // a{b}c -> a{b}c minimatch.braceExpand = function (pattern, options) { return new Minimatch(pattern, options).braceExpand() } Minimatch.prototype.braceExpand = braceExpand function pad(n, width, z) { z = z || '0'; n = n + ''; return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n; } function braceExpand (pattern, options) { options = options || this.options pattern = typeof pattern === "undefined" ? this.pattern : pattern if (typeof pattern === "undefined") { throw new Error("undefined pattern") } if (options.nobrace || !pattern.match(/\{.*\}/)) { // shortcut. no need to expand. return [pattern] } var escaping = false // examples and comments refer to this crazy pattern: // a{b,c{d,e},{f,g}h}x{y,z} // expected: // abxy // abxz // acdxy // acdxz // acexy // acexz // afhxy // afhxz // aghxy // aghxz // everything before the first \{ is just a prefix. // So, we pluck that off, and work with the rest, // and then prepend it to everything we find. if (pattern.charAt(0) !== "{") { this.debug(pattern) var prefix = null for (var i = 0, l = pattern.length; i < l; i ++) { var c = pattern.charAt(i) this.debug(i, c) if (c === "\\") { escaping = !escaping } else if (c === "{" && !escaping) { prefix = pattern.substr(0, i) break } } // actually no sets, all { were escaped. if (prefix === null) { this.debug("no sets") return [pattern] } var tail = braceExpand.call(this, pattern.substr(i), options) return tail.map(function (t) { return prefix + t }) } // now we have something like: // {b,c{d,e},{f,g}h}x{y,z} // walk through the set, expanding each part, until // the set ends. then, we'll expand the suffix. // If the set only has a single member, then'll put the {} back // first, handle numeric sets, since they're easier var numset = pattern.match(/^\{(-?[0-9]+)\.\.(-?[0-9]+)\}/) if (numset) { this.debug("numset", numset[1], numset[2]) var suf = braceExpand.call(this, pattern.substr(numset[0].length), options) , start = +numset[1] , needPadding = numset[1][0] === '0' , startWidth = numset[1].length , padded , end = +numset[2] , inc = start > end ? -1 : 1 , set = [] for (var i = start; i != (end + inc); i += inc) { padded = needPadding ? pad(i, startWidth) : i + '' // append all the suffixes for (var ii = 0, ll = suf.length; ii < ll; ii ++) { set.push(padded + suf[ii]) } } return set } // ok, walk through the set // We hope, somewhat optimistically, that there // will be a } at the end. // If the closing brace isn't found, then the pattern is // interpreted as braceExpand("\\" + pattern) so that // the leading \{ will be interpreted literally. var i = 1 // skip the \{ , depth = 1 , set = [] , member = "" , sawEnd = false , escaping = false function addMember () { set.push(member) member = "" } this.debug("Entering for") FOR: for (i = 1, l = pattern.length; i < l; i ++) { var c = pattern.charAt(i) this.debug("", i, c) if (escaping) { escaping = false member += "\\" + c } else { switch (c) { case "\\": escaping = true continue case "{": depth ++ member += "{" continue case "}": depth -- // if this closes the actual set, then we're done if (depth === 0) { addMember() // pluck off the close-brace i ++ break FOR } else { member += c continue } case ",": if (depth === 1) { addMember() } else { member += c } continue default: member += c continue } // switch } // else } // for // now we've either finished the set, and the suffix is // pattern.substr(i), or we have *not* closed the set, // and need to escape the leading brace if (depth !== 0) { this.debug("didn't close", pattern) return braceExpand.call(this, "\\" + pattern, options) } // x{y,z} -> ["xy", "xz"] this.debug("set", set) this.debug("suffix", pattern.substr(i)) var suf = braceExpand.call(this, pattern.substr(i), options) // ["b", "c{d,e}","{f,g}h"] -> // [["b"], ["cd", "ce"], ["fh", "gh"]] var addBraces = set.length === 1 this.debug("set pre-expanded", set) set = set.map(function (p) { return braceExpand.call(this, p, options) }, this) this.debug("set expanded", set) // [["b"], ["cd", "ce"], ["fh", "gh"]] -> // ["b", "cd", "ce", "fh", "gh"] set = set.reduce(function (l, r) { return l.concat(r) }) if (addBraces) { set = set.map(function (s) { return "{" + s + "}" }) } // now attach the suffixes. var ret = [] for (var i = 0, l = set.length; i < l; i ++) { for (var ii = 0, ll = suf.length; ii < ll; ii ++) { ret.push(set[i] + suf[ii]) } } return ret } // parse a component of the expanded set. // At this point, no pattern may contain "/" in it // so we're going to return a 2d array, where each entry is the full // pattern, split on '/', and then turned into a regular expression. // A regexp is made at the end which joins each array with an // escaped /, and another full one which joins each regexp with |. // // Following the lead of Bash 4.1, note that "**" only has special meaning // when it is the *only* thing in a path portion. Otherwise, any series // of * is equivalent to a single *. Globstar behavior is enabled by // default, and can be disabled by setting options.noglobstar. Minimatch.prototype.parse = parse var SUBPARSE = {} function parse (pattern, isSub) { var options = this.options // shortcuts if (!options.noglobstar && pattern === "**") return GLOBSTAR if (pattern === "") return "" var re = "" , hasMagic = !!options.nocase , escaping = false // ? => one single character , patternListStack = [] , plType , stateChar , inClass = false , reClassStart = -1 , classStart = -1 // . and .. never match anything that doesn't start with ., // even when options.dot is set. , patternStart = pattern.charAt(0) === "." ? "" // anything // not (start or / followed by . or .. followed by / or end) : options.dot ? "(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))" : "(?!\\.)" , self = this function clearStateChar () { if (stateChar) { // we had some state-tracking character // that wasn't consumed by this pass. switch (stateChar) { case "*": re += star hasMagic = true break case "?": re += qmark hasMagic = true break default: re += "\\"+stateChar break } self.debug('clearStateChar %j %j', stateChar, re) stateChar = false } } for ( var i = 0, len = pattern.length, c ; (i < len) && (c = pattern.charAt(i)) ; i ++ ) { this.debug("%s\t%s %s %j", pattern, i, re, c) // skip over any that are escaped. if (escaping && reSpecials[c]) { re += "\\" + c escaping = false continue } SWITCH: switch (c) { case "/": // completely not allowed, even escaped. // Should already be path-split by now. return false case "\\": clearStateChar() escaping = true continue // the various stateChar values // for the "extglob" stuff. case "?": case "*": case "+": case "@": case "!": this.debug("%s\t%s %s %j <-- stateChar", pattern, i, re, c) // all of those are literals inside a class, except that // the glob [!a] means [^a] in regexp if (inClass) { this.debug(' in class') if (c === "!" && i === classStart + 1) c = "^" re += c continue } // if we already have a stateChar, then it means // that there was something like ** or +? in there. // Handle the stateChar, then proceed with this one. self.debug('call clearStateChar %j', stateChar) clearStateChar() stateChar = c // if extglob is disabled, then +(asdf|foo) isn't a thing. // just clear the statechar *now*, rather than even diving into // the patternList stuff. if (options.noext) clearStateChar() continue case "(": if (inClass) { re += "(" continue } if (!stateChar) { re += "\\(" continue } plType = stateChar patternListStack.push({ type: plType , start: i - 1 , reStart: re.length }) // negation is (?:(?!js)[^/]*) re += stateChar === "!" ? "(?:(?!" : "(?:" this.debug('plType %j %j', stateChar, re) stateChar = false continue case ")": if (inClass || !patternListStack.length) { re += "\\)" continue } clearStateChar() hasMagic = true re += ")" plType = patternListStack.pop().type // negation is (?:(?!js)[^/]*) // The others are (?:<pattern>)<type> switch (plType) { case "!": re += "[^/]*?)" break case "?": case "+": case "*": re += plType case "@": break // the default anyway } continue case "|": if (inClass || !patternListStack.length || escaping) { re += "\\|" escaping = false continue } clearStateChar() re += "|" continue // these are mostly the same in regexp and glob case "[": // swallow any state-tracking char before the [ clearStateChar() if (inClass) { re += "\\" + c continue } inClass = true classStart = i reClassStart = re.length re += c continue case "]": // a right bracket shall lose its special // meaning and represent itself in // a bracket expression if it occurs // first in the list. -- POSIX.2 2.8.3.2 if (i === classStart + 1 || !inClass) { re += "\\" + c escaping = false continue } // finish up the class. hasMagic = true inClass = false re += c continue default: // swallow any state char that wasn't consumed clearStateChar() if (escaping) { // no need escaping = false } else if (reSpecials[c] && !(c === "^" && inClass)) { re += "\\" } re += c } // switch } // for // handle the case where we left a class open. // "[abc" is valid, equivalent to "\[abc" if (inClass) { // split where the last [ was, and escape it // this is a huge pita. We now have to re-walk // the contents of the would-be class to re-translate // any characters that were passed through as-is var cs = pattern.substr(classStart + 1) , sp = this.parse(cs, SUBPARSE) re = re.substr(0, reClassStart) + "\\[" + sp[0] hasMagic = hasMagic || sp[1] } // handle the case where we had a +( thing at the *end* // of the pattern. // each pattern list stack adds 3 chars, and we need to go through // and escape any | chars that were passed through as-is for the regexp. // Go through and escape them, taking care not to double-escape any // | chars that were already escaped. var pl while (pl = patternListStack.pop()) { var tail = re.slice(pl.reStart + 3) // maybe some even number of \, then maybe 1 \, followed by a | tail = tail.replace(/((?:\\{2})*)(\\?)\|/g, function (_, $1, $2) { if (!$2) { // the | isn't already escaped, so escape it. $2 = "\\" } // need to escape all those slashes *again*, without escaping the // one that we need for escaping the | character. As it works out, // escaping an even number of slashes can be done by simply repeating // it exactly after itself. That's why this trick works. // // I am sorry that you have to see this. return $1 + $1 + $2 + "|" }) this.debug("tail=%j\n %s", tail, tail) var t = pl.type === "*" ? star : pl.type === "?" ? qmark : "\\" + pl.type hasMagic = true re = re.slice(0, pl.reStart) + t + "\\(" + tail } // handle trailing things that only matter at the very end. clearStateChar() if (escaping) { // trailing \\ re += "\\\\" } // only need to apply the nodot start if the re starts with // something that could conceivably capture a dot var addPatternStart = false switch (re.charAt(0)) { case ".": case "[": case "(": addPatternStart = true } // if the re is not "" at this point, then we need to make sure // it doesn't match against an empty path part. // Otherwise a/* will match a/, which it should not. if (re !== "" && hasMagic) re = "(?=.)" + re if (addPatternStart) re = patternStart + re // parsing just a piece of a larger pattern. if (isSub === SUBPARSE) { return [ re, hasMagic ] } // skip the regexp for non-magical patterns // unescape anything in it, though, so that it'll be // an exact match against a file etc. if (!hasMagic) { return globUnescape(pattern) } var flags = options.nocase ? "i" : "" , regExp = new RegExp("^" + re + "$", flags) regExp._glob = pattern regExp._src = re return regExp } minimatch.makeRe = function (pattern, options) { return new Minimatch(pattern, options || {}).makeRe() } Minimatch.prototype.makeRe = makeRe function makeRe () { if (this.regexp || this.regexp === false) return this.regexp // at this point, this.set is a 2d array of partial // pattern strings, or "**". // // It's better to use .match(). This function shouldn't // be used, really, but it's pretty convenient sometimes, // when you just want to work with a regex. var set = this.set if (!set.length) return this.regexp = false var options = this.options var twoStar = options.noglobstar ? star : options.dot ? twoStarDot : twoStarNoDot , flags = options.nocase ? "i" : "" var re = set.map(function (pattern) { return pattern.map(function (p) { return (p === GLOBSTAR) ? twoStar : (typeof p === "string") ? regExpEscape(p) : p._src }).join("\\\/") }).join("|") // must match entire pattern // ending in a * or ** will make it less strict. re = "^(?:" + re + ")$" // can match anything, as long as it's not this. if (this.negate) re = "^(?!" + re + ").*$" try { return this.regexp = new RegExp(re, flags) } catch (ex) { return this.regexp = false } } minimatch.match = function (list, pattern, options) { options = options || {} var mm = new Minimatch(pattern, options) list = list.filter(function (f) { return mm.match(f) }) if (mm.options.nonull && !list.length) { list.push(pattern) } return list } Minimatch.prototype.match = match function match (f, partial) { this.debug("match", f, this.pattern) // short-circuit in the case of busted things. // comments, etc. if (this.comment) return false if (this.empty) return f === "" if (f === "/" && partial) return true var options = this.options // windows: need to use /, not \ // On other platforms, \ is a valid (albeit bad) filename char. if (platform === "win32") { f = f.split("\\").join("/") } // treat the test path as a set of pathparts. f = f.split(slashSplit) this.debug(this.pattern, "split", f) // just ONE of the pattern sets in this.set needs to match // in order for it to be valid. If negating, then just one // match means that we have failed. // Either way, return on the first hit. var set = this.set this.debug(this.pattern, "set", set) // Find the basename of the path by looking for the last non-empty segment var filename; for (var i = f.length - 1; i >= 0; i--) { filename = f[i] if (filename) break } for (var i = 0, l = set.length; i < l; i ++) { var pattern = set[i], file = f if (options.matchBase && pattern.length === 1) { file = [filename] } var hit = this.matchOne(file, pattern, partial) if (hit) { if (options.flipNegate) return true return !this.negate } } // didn't get any hits. this is success if it's a negative // pattern, failure otherwise. if (options.flipNegate) return false return this.negate } // set partial to true to test if, for example, // "/a/b" matches the start of "/*/b/*/d" // Partial means, if you run out of file before you run // out of pattern, then that's fine, as long as all // the parts match. Minimatch.prototype.matchOne = function (file, pattern, partial) { var options = this.options this.debug("matchOne", { "this": this , file: file , pattern: pattern }) this.debug("matchOne", file.length, pattern.length) for ( var fi = 0 , pi = 0 , fl = file.length , pl = pattern.length ; (fi < fl) && (pi < pl) ; fi ++, pi ++ ) { this.debug("matchOne loop") var p = pattern[pi] , f = file[fi] this.debug(pattern, p, f) // should be impossible. // some invalid regexp stuff in the set. if (p === false) return false if (p === GLOBSTAR) { this.debug('GLOBSTAR', [pattern, p, f]) // "**" // a/**/b/**/c would match the following: // a/b/x/y/z/c // a/x/y/z/b/c // a/b/x/b/x/c // a/b/c // To do this, take the rest of the pattern after // the **, and see if it would match the file remainder. // If so, return success. // If not, the ** "swallows" a segment, and try again. // This is recursively awful. // // a/**/b/**/c matching a/b/x/y/z/c // - a matches a // - doublestar // - matchOne(b/x/y/z/c, b/**/c) // - b matches b // - doublestar // - matchOne(x/y/z/c, c) -> no // - matchOne(y/z/c, c) -> no // - matchOne(z/c, c) -> no // - matchOne(c, c) yes, hit var fr = fi , pr = pi + 1 if (pr === pl) { this.debug('** at the end') // a ** at the end will just swallow the rest. // We have found a match. // however, it will not swallow /.x, unless // options.dot is set. // . and .. are *never* matched by **, for explosively // exponential reasons. for ( ; fi < fl; fi ++) { if (file[fi] === "." || file[fi] === ".." || (!options.dot && file[fi].charAt(0) === ".")) return false } return true } // ok, let's see if we can swallow whatever we can. WHILE: while (fr < fl) { var swallowee = file[fr] this.debug('\nglobstar while', file, fr, pattern, pr, swallowee) // XXX remove this slice. Just pass the start index. if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { this.debug('globstar found match!', fr, fl, swallowee) // found a match. return true } else { // can't swallow "." or ".." ever. // can only swallow ".foo" when explicitly asked. if (swallowee === "." || swallowee === ".." || (!options.dot && swallowee.charAt(0) === ".")) { this.debug("dot detected!", file, fr, pattern, pr) break WHILE } // ** swallows a segment, and continue. this.debug('globstar swallow a segment, and continue') fr ++ } } // no match was found. // However, in partial mode, we can't say this is necessarily over. // If there's more *pattern* left, then if (partial) { // ran out of file this.debug("\n>>> no match, partial?", file, fr, pattern, pr) if (fr === fl) return true } return false } // something other than ** // non-magic patterns just have to match exactly // patterns with magic have been turned into regexps. var hit if (typeof p === "string") { if (options.nocase) { hit = f.toLowerCase() === p.toLowerCase() } else { hit = f === p } this.debug("string match", p, f, hit) } else { hit = f.match(p) this.debug("pattern match", p, f, hit) } if (!hit) return false } // Note: ending in / means that we'll get a final "" // at the end of the pattern. This can only match a // corresponding "" at the end of the file. // If the file ends in /, then it can only match a // a pattern that ends in /, unless the pattern just // doesn't have any more for it. But, a/b/ should *not* // match "a/b/*", even though "" matches against the // [^/]*? pattern, except in partial mode, where it might // simply not be reached yet. // However, a/b/ should still satisfy a/* // now either we fell off the end of the pattern, or we're done. if (fi === fl && pi === pl) { // ran out of pattern and filename at the same time. // an exact hit! return true } else if (fi === fl) { // ran out of file, but still had pattern left. // this is ok if we're doing the match as part of // a glob fs traversal. return partial } else if (pi === pl) { // ran out of pattern, still have file left. // this is only acceptable if we're on the very last // empty segment of a file with a trailing slash. // a/* should match a/b/ var emptyFileEnd = (fi === fl - 1) && (file[fi] === "") return emptyFileEnd } // should be unreachable. throw new Error("wtf?") } // replace stuff like \* with * function globUnescape (s) { return s.replace(/\\(.)/g, "$1") } function regExpEscape (s) { return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") } })( typeof _dereq_ === "function" ? _dereq_ : null, this, typeof module === "object" ? module : null, typeof process === "object" ? process.platform : "win32" ) }).call(this,_dereq_("FWaASH")) },{"FWaASH":10,"lru-cache":12,"path":9,"sigmund":13}],12:[function(_dereq_,module,exports){ ;(function () { // closure for web browsers if (typeof module === 'object' && module.exports) { module.exports = LRUCache } else { // just set the global for non-node platforms. this.LRUCache = LRUCache } function hOP (obj, key) { return Object.prototype.hasOwnProperty.call(obj, key) } function naiveLength () { return 1 } function LRUCache (options) { if (!(this instanceof LRUCache)) return new LRUCache(options) if (typeof options === 'number') options = { max: options } if (!options) options = {} this._max = options.max // Kind of weird to have a default max of Infinity, but oh well. if (!this._max || !(typeof this._max === "number") || this._max <= 0 ) this._max = Infinity this._lengthCalculator = options.length || naiveLength if (typeof this._lengthCalculator !== "function") this._lengthCalculator = naiveLength this._allowStale = options.stale || false this._maxAge = options.maxAge || null this._dispose = options.dispose this.reset() } // resize the cache when the max changes. Object.defineProperty(LRUCache.prototype, "max", { set : function (mL) { if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity this._max = mL if (this._length > this._max) trim(this) } , get : function () { return this._max } , enumerable : true }) // resize the cache when the lengthCalculator changes. Object.defineProperty(LRUCache.prototype, "lengthCalculator", { set : function (lC) { if (typeof lC !== "function") { this._lengthCalculator = naiveLength this._length = this._itemCount for (var key in this._cache) { this._cache[key].length = 1 } } else { this._lengthCalculator = lC this._length = 0 for (var key in this._cache) { this._cache[key].length = this._lengthCalculator(this._cache[key].value) this._length += this._cache[key].length } } if (this._length > this._max) trim(this) } , get : function () { return this._lengthCalculator } , enumerable : true }) Object.defineProperty(LRUCache.prototype, "length", { get : function () { return this._length } , enumerable : true }) Object.defineProperty(LRUCache.prototype, "itemCount", { get : function () { return this._itemCount } , enumerable : true }) LRUCache.prototype.forEach = function (fn, thisp) { thisp = thisp || this var i = 0; for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) { i++ var hit = this._lruList[k] if (this._maxAge && (Date.now() - hit.now > this._maxAge)) { del(this, hit) if (!this._allowStale) hit = undefined } if (hit) { fn.call(thisp, hit.value, hit.key, this) } } } LRUCache.prototype.keys = function () { var keys = new Array(this._itemCount) var i = 0 for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) { var hit = this._lruList[k] keys[i++] = hit.key } return keys } LRUCache.prototype.values = function () { var values = new Array(this._itemCount) var i = 0 for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) { var hit = this._lruList[k] values[i++] = hit.value } return values } LRUCache.prototype.reset = function () { if (this._dispose && this._cache) { for (var k in this._cache) { this._dispose(k, this._cache[k].value) } } this._cache = Object.create(null) // hash of items by key this._lruList = Object.create(null) // list of items in order of use recency this._mru = 0 // most recently used this._lru = 0 // least recently used this._length = 0 // number of items in the list this._itemCount = 0 } // Provided for debugging/dev purposes only. No promises whatsoever that // this API stays stable. LRUCache.prototype.dump = function () { return this._cache } LRUCache.prototype.dumpLru = function () { return this._lruList } LRUCache.prototype.set = function (key, value) { if (hOP(this._cache, key)) { // dispose of the old one before overwriting if (this._dispose) this._dispose(key, this._cache[key].value) if (this._maxAge) this._cache[key].now = Date.now() this._cache[key].value = value this.get(key) return true } var len = this._lengthCalculator(value) var age = this._maxAge ? Date.now() : 0 var hit = new Entry(key, value, this._mru++, len, age) // oversized objects fall out of cache automatically. if (hit.length > this._max) { if (this._dispose) this._dispose(key, value) return false } this._length += hit.length this._lruList[hit.lu] = this._cache[key] = hit this._itemCount ++ if (this._length > this._max) trim(this) return true } LRUCache.prototype.has = function (key) { if (!hOP(this._cache, key)) return false var hit = this._cache[key] if (this._maxAge && (Date.now() - hit.now > this._maxAge)) { return false } return true } LRUCache.prototype.get = function (key) { return get(this, key, true) } LRUCache.prototype.peek = function (key) { return get(this, key, false) } LRUCache.prototype.pop = function () { var hit = this._lruList[this._lru] del(this, hit) return hit || null } LRUCache.prototype.del = function (key) { del(this, this._cache[key]) } function get (self, key, doUse) { var hit = self._cache[key] if (hit) { if (self._maxAge && (Date.now() - hit.now > self._maxAge)) { del(self, hit) if (!self._allowStale) hit = undefined } else { if (doUse) use(self, hit) } if (hit) hit = hit.value } return hit } function use (self, hit) { shiftLU(self, hit) hit.lu = self._mru ++ self._lruList[hit.lu] = hit } function trim (self) { while (self._lru < self._mru && self._length > self._max) del(self, self._lruList[self._lru]) } function shiftLU (self, hit) { delete self._lruList[ hit.lu ] while (self._lru < self._mru && !self._lruList[self._lru]) self._lru ++ } function del (self, hit) { if (hit) { if (self._dispose) self._dispose(hit.key, hit.value) self._length -= hit.length self._itemCount -- delete self._cache[ hit.key ] shiftLU(self, hit) } } // classy, since V8 prefers predictable objects. function Entry (key, value, lu, length, now) { this.key = key this.value = value this.lu = lu this.length = length this.now = now } })() },{}],13:[function(_dereq_,module,exports){ module.exports = sigmund function sigmund (subject, maxSessions) { maxSessions = maxSessions || 10; var notes = []; var analysis = ''; var RE = RegExp; function psychoAnalyze (subject, session) { if (session > maxSessions) return; if (typeof subject === 'function' || typeof subject === 'undefined') { return; } if (typeof subject !== 'object' || !subject || (subject instanceof RE)) { analysis += subject; return; } if (notes.indexOf(subject) !== -1 || session === maxSessions) return; notes.push(subject); analysis += '{'; Object.keys(subject).forEach(function (issue, _, __) { // pseudo-private values. skip those. if (issue.charAt(0) === '_') return; var to = typeof subject[issue]; if (to === 'function' || to === 'undefined') return; analysis += issue; psychoAnalyze(subject[issue], session + 1); }); } psychoAnalyze(subject, 0); return analysis; } // vim: set softtabstop=4 shiftwidth=4: },{}],14:[function(_dereq_,module,exports){ (function (Buffer){ function FilerBuffer (subject, encoding, nonZero) { // Automatically turn ArrayBuffer into Uint8Array so that underlying // Buffer code doesn't just throw away and ignore ArrayBuffer data. if (subject instanceof ArrayBuffer) { subject = new Uint8Array(subject); } return new Buffer(subject, encoding, nonZero); }; // Inherit prototype from Buffer FilerBuffer.prototype = Object.create(Buffer.prototype); FilerBuffer.prototype.constructor = FilerBuffer; // Also copy static methods onto FilerBuffer ctor Object.keys(Buffer).forEach(function (p) { if (Buffer.hasOwnProperty(p)) { FilerBuffer[p] = Buffer[p]; } }); module.exports = FilerBuffer; }).call(this,_dereq_("buffer").Buffer) },{"buffer":6}],15:[function(_dereq_,module,exports){ var O_READ = 'READ'; var O_WRITE = 'WRITE'; var O_CREATE = 'CREATE'; var O_EXCLUSIVE = 'EXCLUSIVE'; var O_TRUNCATE = 'TRUNCATE'; var O_APPEND = 'APPEND'; var XATTR_CREATE = 'CREATE'; var XATTR_REPLACE = 'REPLACE'; module.exports = { FILE_SYSTEM_NAME: 'local', FILE_STORE_NAME: 'files', IDB_RO: 'readonly', IDB_RW: 'readwrite', WSQL_VERSION: "1", WSQL_SIZE: 5 * 1024 * 1024, WSQL_DESC: "FileSystem Storage", MODE_FILE: 'FILE', MODE_DIRECTORY: 'DIRECTORY', MODE_SYMBOLIC_LINK: 'SYMLINK', MODE_META: 'META', SYMLOOP_MAX: 10, BINARY_MIME_TYPE: 'application/octet-stream', JSON_MIME_TYPE: 'application/json', ROOT_DIRECTORY_NAME: '/', // basename(normalize(path)) // FS Mount Flags FS_FORMAT: 'FORMAT', FS_NOCTIME: 'NOCTIME', FS_NOMTIME: 'NOMTIME', FS_NODUPEIDCHECK: 'FS_NODUPEIDCHECK', // FS File Open Flags O_READ: O_READ, O_WRITE: O_WRITE, O_CREATE: O_CREATE, O_EXCLUSIVE: O_EXCLUSIVE, O_TRUNCATE: O_TRUNCATE, O_APPEND: O_APPEND, O_FLAGS: { 'r': [O_READ], 'r+': [O_READ, O_WRITE], 'w': [O_WRITE, O_CREATE, O_TRUNCATE], 'w+': [O_WRITE, O_READ, O_CREATE, O_TRUNCATE], 'wx': [O_WRITE, O_CREATE, O_EXCLUSIVE, O_TRUNCATE], 'wx+': [O_WRITE, O_READ, O_CREATE, O_EXCLUSIVE, O_TRUNCATE], 'a': [O_WRITE, O_CREATE, O_APPEND], 'a+': [O_WRITE, O_READ, O_CREATE, O_APPEND], 'ax': [O_WRITE, O_CREATE, O_EXCLUSIVE, O_APPEND], 'ax+': [O_WRITE, O_READ, O_CREATE, O_EXCLUSIVE, O_APPEND] }, XATTR_CREATE: XATTR_CREATE, XATTR_REPLACE: XATTR_REPLACE, FS_READY: 'READY', FS_PENDING: 'PENDING', FS_ERROR: 'ERROR', SUPER_NODE_ID: '00000000-0000-0000-0000-000000000000', // Reserved File Descriptors for streams STDIN: 0, STDOUT: 1, STDERR: 2, FIRST_DESCRIPTOR: 3, ENVIRONMENT: { TMP: '/tmp', PATH: '' } }; },{}],16:[function(_dereq_,module,exports){ var MODE_FILE = _dereq_('./constants.js').MODE_FILE; module.exports = function DirectoryEntry(id, type) { this.id = id; this.type = type || MODE_FILE; }; },{"./constants.js":15}],17:[function(_dereq_,module,exports){ (function (Buffer){ // Adapt encodings to work with Buffer or Uint8Array, they expect the latter function decode(buf) { return buf.toString('utf8'); } function encode(string) { return new Buffer(string, 'utf8'); } module.exports = { encode: encode, decode: decode }; }).call(this,_dereq_("buffer").Buffer) },{"buffer":6}],18:[function(_dereq_,module,exports){ var errors = {}; [ /** * node.js errors - we only use some of these, add as needed. */ //'-1:UNKNOWN:unknown error', //'0:OK:success', //'1:EOF:end of file', //'2:EADDRINFO:getaddrinfo error', //'3:EACCES:permission denied', //'4:EAGAIN:resource temporarily unavailable', //'5:EADDRINUSE:address already in use', //'6:EADDRNOTAVAIL:address not available', //'7:EAFNOSUPPORT:address family not supported', //'8:EALREADY:connection already in progress', '9:EBADF:bad file descriptor', '10:EBUSY:resource busy or locked', //'11:ECONNABORTED:software caused connection abort', //'12:ECONNREFUSED:connection refused', //'13:ECONNRESET:connection reset by peer', //'14:EDESTADDRREQ:destination address required', //'15:EFAULT:bad address in system call argument', //'16:EHOSTUNREACH:host is unreachable', //'17:EINTR:interrupted system call', '18:EINVAL:invalid argument', //'19:EISCONN:socket is already connected', //'20:EMFILE:too many open files', //'21:EMSGSIZE:message too long', //'22:ENETDOWN:network is down', //'23:ENETUNREACH:network is unreachable', //'24:ENFILE:file table overflow', //'25:ENOBUFS:no buffer space available', //'26:ENOMEM:not enough memory', '27:ENOTDIR:not a directory', '28:EISDIR:illegal operation on a directory', //'29:ENONET:machine is not on the network', // errno 30 skipped, as per https://github.com/rvagg/node-errno/blob/master/errno.js //'31:ENOTCONN:socket is not connected', //'32:ENOTSOCK:socket operation on non-socket', //'33:ENOTSUP:operation not supported on socket', '34:ENOENT:no such file or directory', //'35:ENOSYS:function not implemented', //'36:EPIPE:broken pipe', //'37:EPROTO:protocol error', //'38:EPROTONOSUPPORT:protocol not supported', //'39:EPROTOTYPE:protocol wrong type for socket', //'40:ETIMEDOUT:connection timed out', //'41:ECHARSET:invalid Unicode character', //'42:EAIFAMNOSUPPORT:address family for hostname not supported', // errno 43 skipped, as per https://github.com/rvagg/node-errno/blob/master/errno.js //'44:EAISERVICE:servname not supported for ai_socktype', //'45:EAISOCKTYPE:ai_socktype not supported', //'46:ESHUTDOWN:cannot send after transport endpoint shutdown', '47:EEXIST:file already exists', //'48:ESRCH:no such process', //'49:ENAMETOOLONG:name too long', '50:EPERM:operation not permitted', '51:ELOOP:too many symbolic links encountered', //'52:EXDEV:cross-device link not permitted', '53:ENOTEMPTY:directory not empty', //'54:ENOSPC:no space left on device', '55:EIO:i/o error', //'56:EROFS:read-only file system', //'57:ENODEV:no such device', //'58:ESPIPE:invalid seek', //'59:ECANCELED:operation canceled', /** * Filer specific errors */ '1000:ENOTMOUNTED:not mounted', '1001:EFILESYSTEMERROR:missing super node, use \'FORMAT\' flag to format filesystem.', '1002:ENOATTR:attribute does not exist' ].forEach(function(e) { e = e.split(':'); var errno = +e[0]; var errName = e[1]; var defaultMessage = e[2]; function FilerError(msg, path) { Error.call(this); this.name = errName; this.code = errName; this.errno = errno; this.message = msg || defaultMessage; if(path) { this.path = path; } this.stack = (new Error(this.message)).stack; } FilerError.prototype = Object.create(Error.prototype); FilerError.prototype.constructor = FilerError; FilerError.prototype.toString = function() { var pathInfo = this.path ? (', \'' + this.path + '\'') : ''; return this.name + ': ' + this.message + pathInfo; }; // We expose the error as both Errors.EINVAL and Errors[18] errors[errName] = errors[errno] = FilerError; }); module.exports = errors; },{}],19:[function(_dereq_,module,exports){ var _ = _dereq_('../../lib/nodash.js'); var Path = _dereq_('../path.js'); var normalize = Path.normalize; var dirname = Path.dirname; var basename = Path.basename; var isAbsolutePath = Path.isAbsolute; var isNullPath = Path.isNull; var Constants = _dereq_('../constants.js'); var MODE_FILE = Constants.MODE_FILE; var MODE_DIRECTORY = Constants.MODE_DIRECTORY; var MODE_SYMBOLIC_LINK = Constants.MODE_SYMBOLIC_LINK; var MODE_META = Constants.MODE_META; var ROOT_DIRECTORY_NAME = Constants.ROOT_DIRECTORY_NAME; var SUPER_NODE_ID = Constants.SUPER_NODE_ID; var SYMLOOP_MAX = Constants.SYMLOOP_MAX; var O_READ = Constants.O_READ; var O_WRITE = Constants.O_WRITE; var O_CREATE = Constants.O_CREATE; var O_EXCLUSIVE = Constants.O_EXCLUSIVE; var O_TRUNCATE = Constants.O_TRUNCATE; var O_APPEND = Constants.O_APPEND; var O_FLAGS = Constants.O_FLAGS; var XATTR_CREATE = Constants.XATTR_CREATE; var XATTR_REPLACE = Constants.XATTR_REPLACE; var FS_NOMTIME = Constants.FS_NOMTIME; var FS_NOCTIME = Constants.FS_NOCTIME; var Encoding = _dereq_('../encoding.js'); var Errors = _dereq_('../errors.js'); var DirectoryEntry = _dereq_('../directory-entry.js'); var OpenFileDescription = _dereq_('../open-file-description.js'); var SuperNode = _dereq_('../super-node.js'); var Node = _dereq_('../node.js'); var Stats = _dereq_('../stats.js'); var Buffer = _dereq_('../buffer.js'); /** * Update node times. Only passed times are modified (undefined times are ignored) * and filesystem flags are examined in order to override update logic. */ function update_node_times(context, path, node, times, callback) { // Honour mount flags for how we update times var flags = context.flags; if(_(flags).contains(FS_NOCTIME)) { delete times.ctime; } if(_(flags).contains(FS_NOMTIME)) { delete times.mtime; } // Only do the update if required (i.e., times are still present) var update = false; if(times.ctime) { node.ctime = times.ctime; // We don't do atime tracking for perf reasons, but do mirror ctime node.atime = times.ctime; update = true; } if(times.atime) { // The only time we explicitly pass atime is when utimes(), futimes() is called. // Override ctime mirror here if so node.atime = times.atime; update = true; } if(times.mtime) { node.mtime = times.mtime; update = true; } function complete(error) { // Queue this change so we can send watch events. // Unlike node.js, we send the full path vs. basename/dirname only. context.changes.push({ event: 'change', path: path }); callback(error); } if(update) { context.putObject(node.id, node, complete); } else { complete(); } } /** * make_node() */ // in: file or directory path // out: new node representing file/directory function make_node(context, path, mode, callback) { if(mode !== MODE_DIRECTORY && mode !== MODE_FILE) { return callback(new Errors.EINVAL('mode must be a directory or file', path)); } path = normalize(path); var name = basename(path); var parentPath = dirname(path); var parentNode; var parentNodeData; var node; // Check if the parent node exists function create_node_in_parent(error, parentDirectoryNode) { if(error) { callback(error); } else if(parentDirectoryNode.mode !== MODE_DIRECTORY) { callback(new Errors.ENOTDIR('a component of the path prefix is not a directory', path)); } else { parentNode = parentDirectoryNode; find_node(context, path, check_if_node_exists); } } // Check if the node to be created already exists function check_if_node_exists(error, result) { if(!error && result) { callback(new Errors.EEXIST('path name already exists', path)); } else if(error && !(error instanceof Errors.ENOENT)) { callback(error); } else { context.getObject(parentNode.data, create_node); } } // Create the new node function create_node(error, result) { if(error) { callback(error); } else { parentNodeData = result; Node.create({guid: context.guid, mode: mode}, function(error, result) { if(error) { callback(error); return; } node = result; node.nlinks += 1; context.putObject(node.id, node, update_parent_node_data); }); } } // Update parent node time function update_time(error) { if(error) { callback(error); } else { var now = Date.now(); update_node_times(context, parentPath, node, { mtime: now, ctime: now }, callback); } } // Update the parent nodes data function update_parent_node_data(error) { if(error) { callback(error); } else { parentNodeData[name] = new DirectoryEntry(node.id, mode); context.putObject(parentNode.data, parentNodeData, update_time); } } // Find the parent node find_node(context, parentPath, create_node_in_parent); } /** * find_node */ // in: file or directory path // out: node structure, or error function find_node(context, path, callback) { path = normalize(path); if(!path) { return callback(new Errors.ENOENT('path is an empty string')); } var name = basename(path); var parentPath = dirname(path); var followedCount = 0; function read_root_directory_node(error, superNode) { if(error) { callback(error); } else if(!superNode || superNode.mode !== MODE_META || !superNode.rnode) { callback(new Errors.EFILESYSTEMERROR()); } else { context.getObject(superNode.rnode, check_root_directory_node); } } function check_root_directory_node(error, rootDirectoryNode) { if(error) { callback(error); } else if(!rootDirectoryNode) { callback(new Errors.ENOENT()); } else { callback(null, rootDirectoryNode); } } // in: parent directory node // out: parent directory data function read_parent_directory_data(error, parentDirectoryNode) { if(error) { callback(error); } else if(parentDirectoryNode.mode !== MODE_DIRECTORY || !parentDirectoryNode.data) { callback(new Errors.ENOTDIR('a component of the path prefix is not a directory', path)); } else { context.getObject(parentDirectoryNode.data, get_node_from_parent_directory_data); } } // in: parent directory data // out: searched node function get_node_from_parent_directory_data(error, parentDirectoryData) { if(error) { callback(error); } else { if(!_(parentDirectoryData).has(name)) { callback(new Errors.ENOENT(null, path)); } else { var nodeId = parentDirectoryData[name].id; context.getObject(nodeId, is_symbolic_link); } } } function is_symbolic_link(error, node) { if(error) { callback(error); } else { if(node.mode == MODE_SYMBOLIC_LINK) { followedCount++; if(followedCount > SYMLOOP_MAX){ callback(new Errors.ELOOP(null, path)); } else { follow_symbolic_link(node.data); } } else { callback(null, node); } } } function follow_symbolic_link(data) { data = normalize(data); parentPath = dirname(data); name = basename(data); if(ROOT_DIRECTORY_NAME == name) { context.getObject(SUPER_NODE_ID, read_root_directory_node); } else { find_node(context, parentPath, read_parent_directory_data); } } if(ROOT_DIRECTORY_NAME == name) { context.getObject(SUPER_NODE_ID, read_root_directory_node); } else { find_node(context, parentPath, read_parent_directory_data); } } /** * set extended attribute (refactor) */ function set_extended_attribute (context, path, node, name, value, flag, callback) { function update_time(error) { if(error) { callback(error); } else { update_node_times(context, path, node, { ctime: Date.now() }, callback); } } var xattrs = node.xattrs; if (flag === XATTR_CREATE && xattrs.hasOwnProperty(name)) { callback(new Errors.EEXIST('attribute already exists', path)); } else if (flag === XATTR_REPLACE && !xattrs.hasOwnProperty(name)) { callback(new Errors.ENOATTR(null, path)); } else { xattrs[name] = value; context.putObject(node.id, node, update_time); } } /** * ensure_root_directory. Creates a root node if necessary. * * Note: this should only be invoked when formatting a new file system. * Multiple invocations of this by separate instances will still result * in only a single super node. */ function ensure_root_directory(context, callback) { var superNode; var directoryNode; var directoryData; function ensure_super_node(error, existingNode) { if(!error && existingNode) { // Another instance has beat us and already created the super node. callback(); } else if(error && !(error instanceof Errors.ENOENT)) { callback(error); } else { SuperNode.create({guid: context.guid}, function(error, result) { if(error) { callback(error); return; } superNode = result; context.putObject(superNode.id, superNode, write_directory_node); }); } } function write_directory_node(error) { if(error) { callback(error); } else { Node.create({guid: context.guid, id: superNode.rnode, mode: MODE_DIRECTORY}, function(error, result) { if(error) { callback(error); return; } directoryNode = result; directoryNode.nlinks += 1; context.putObject(directoryNode.id, directoryNode, write_directory_data); }); } } function write_directory_data(error) { if(error) { callback(error); } else { directoryData = {}; context.putObject(directoryNode.data, directoryData, callback); } } context.getObject(SUPER_NODE_ID, ensure_super_node); } /** * make_directory */ function make_directory(context, path, callback) { path = normalize(path); var name = basename(path); var parentPath = dirname(path); var directoryNode; var directoryData; var parentDirectoryNode; var parentDirectoryData; function check_if_directory_exists(error, result) { if(!error && result) { callback(new Errors.EEXIST(null, path)); } else if(error && !(error instanceof Errors.ENOENT)) { callback(error); } else { find_node(context, parentPath, read_parent_directory_data); } } function read_parent_directory_data(error, result) { if(error) { callback(error); } else { parentDirectoryNode = result; context.getObject(parentDirectoryNode.data, write_directory_node); } } function write_directory_node(error, result) { if(error) { callback(error); } else { parentDirectoryData = result; Node.create({guid: context.guid, mode: MODE_DIRECTORY}, function(error, result) { if(error) { callback(error); return; } directoryNode = result; directoryNode.nlinks += 1; context.putObject(directoryNode.id, directoryNode, write_directory_data); }); } } function write_directory_data(error) { if(error) { callback(error); } else { directoryData = {}; context.putObject(directoryNode.data, directoryData, update_parent_directory_data); } } function update_time(error) { if(error) { callback(error); } else { var now = Date.now(); update_node_times(context, parentPath, parentDirectoryNode, { mtime: now, ctime: now }, callback); } } function update_parent_directory_data(error) { if(error) { callback(error); } else { parentDirectoryData[name] = new DirectoryEntry(directoryNode.id, MODE_DIRECTORY); context.putObject(parentDirectoryNode.data, parentDirectoryData, update_time); } } find_node(context, path, check_if_directory_exists); } /** * remove_directory */ function remove_directory(context, path, callback) { path = normalize(path); var name = basename(path); var parentPath = dirname(path); var directoryNode; var directoryData; var parentDirectoryNode; var parentDirectoryData; function read_parent_directory_data(error, result) { if(error) { callback(error); } else { parentDirectoryNode = result; context.getObject(parentDirectoryNode.data, check_if_node_exists); } } function check_if_node_exists(error, result) { if(error) { callback(error); } else if(ROOT_DIRECTORY_NAME == name) { callback(new Errors.EBUSY(null, path)); } else if(!_(result).has(name)) { callback(new Errors.ENOENT(null, path)); } else { parentDirectoryData = result; directoryNode = parentDirectoryData[name].id; context.getObject(directoryNode, check_if_node_is_directory); } } function check_if_node_is_directory(error, result) { if(error) { callback(error); } else if(result.mode != MODE_DIRECTORY) { callback(new Errors.ENOTDIR(null, path)); } else { directoryNode = result; context.getObject(directoryNode.data, check_if_directory_is_empty); } } function check_if_directory_is_empty(error, result) { if(error) { callback(error); } else { directoryData = result; if(_(directoryData).size() > 0) { callback(new Errors.ENOTEMPTY(null, path)); } else { remove_directory_entry_from_parent_directory_node(); } } } function update_time(error) { if(error) { callback(error); } else { var now = Date.now(); update_node_times(context, parentPath, parentDirectoryNode, { mtime: now, ctime: now }, remove_directory_node); } } function remove_directory_entry_from_parent_directory_node() { delete parentDirectoryData[name]; context.putObject(parentDirectoryNode.data, parentDirectoryData, update_time); } function remove_directory_node(error) { if(error) { callback(error); } else { context.delete(directoryNode.id, remove_directory_data); } } function remove_directory_data(error) { if(error) { callback(error); } else { context.delete(directoryNode.data, callback); } } find_node(context, parentPath, read_parent_directory_data); } function open_file(context, path, flags, callback) { path = normalize(path); var name = basename(path); var parentPath = dirname(path); var directoryNode; var directoryData; var directoryEntry; var fileNode; var fileData; var followedCount = 0; if(ROOT_DIRECTORY_NAME == name) { if(_(flags).contains(O_WRITE)) { callback(new Errors.EISDIR('the named file is a directory and O_WRITE is set', path)); } else { find_node(context, path, set_file_node); } } else { find_node(context, parentPath, read_directory_data); } function read_directory_data(error, result) { if(error) { callback(error); } else if(result.mode !== MODE_DIRECTORY) { callback(new Errors.ENOENT(null, path)); } else { directoryNode = result; context.getObject(directoryNode.data, check_if_file_exists); } } function check_if_file_exists(error, result) { if(error) { callback(error); } else { directoryData = result; if(_(directoryData).has(name)) { if(_(flags).contains(O_EXCLUSIVE)) { callback(new Errors.ENOENT('O_CREATE and O_EXCLUSIVE are set, and the named file exists', path)); } else { directoryEntry = directoryData[name]; if(directoryEntry.type == MODE_DIRECTORY && _(flags).contains(O_WRITE)) { callback(new Errors.EISDIR('the named file is a directory and O_WRITE is set', path)); } else { context.getObject(directoryEntry.id, check_if_symbolic_link); } } } else { if(!_(flags).contains(O_CREATE)) { callback(new Errors.ENOENT('O_CREATE is not set and the named file does not exist', path)); } else { write_file_node(); } } } } function check_if_symbolic_link(error, result) { if(error) { callback(error); } else { var node = result; if(node.mode == MODE_SYMBOLIC_LINK) { followedCount++; if(followedCount > SYMLOOP_MAX){ callback(new Errors.ELOOP(null, path)); } else { follow_symbolic_link(node.data); } } else { set_file_node(undefined, node); } } } function follow_symbolic_link(data) { data = normalize(data); parentPath = dirname(data); name = basename(data); if(ROOT_DIRECTORY_NAME == name) { if(_(flags).contains(O_WRITE)) { callback(new Errors.EISDIR('the named file is a directory and O_WRITE is set', path)); } else { find_node(context, path, set_file_node); } } find_node(context, parentPath, read_directory_data); } function set_file_node(error, result) { if(error) { callback(error); } else { fileNode = result; callback(null, fileNode); } } function write_file_node() { Node.create({guid: context.guid, mode: MODE_FILE}, function(error, result) { if(error) { callback(error); return; } fileNode = result; fileNode.nlinks += 1; context.putObject(fileNode.id, fileNode, write_file_data); }); } function write_file_data(error) { if(error) { callback(error); } else { fileData = new Buffer(0); fileData.fill(0); context.putBuffer(fileNode.data, fileData, update_directory_data); } } function update_time(error) { if(error) { callback(error); } else { var now = Date.now(); update_node_times(context, parentPath, directoryNode, { mtime: now, ctime: now }, handle_update_result); } } function update_directory_data(error) { if(error) { callback(error); } else { directoryData[name] = new DirectoryEntry(fileNode.id, MODE_FILE); context.putObject(directoryNode.data, directoryData, update_time); } } function handle_update_result(error) { if(error) { callback(error); } else { callback(null, fileNode); } } } function replace_data(context, ofd, buffer, offset, length, callback) { var fileNode; function return_nbytes(error) { if(error) { callback(error); } else { callback(null, length); } } function update_time(error) { if(error) { callback(error); } else { var now = Date.now(); update_node_times(context, ofd.path, fileNode, { mtime: now, ctime: now }, return_nbytes); } } function update_file_node(error) { if(error) { callback(error); } else { context.putObject(fileNode.id, fileNode, update_time); } } function write_file_data(error, result) { if(error) { callback(error); } else { fileNode = result; var newData = new Buffer(length); newData.fill(0); buffer.copy(newData, 0, offset, offset + length); ofd.position = length; fileNode.size = length; fileNode.version += 1; context.putBuffer(fileNode.data, newData, update_file_node); } } context.getObject(ofd.id, write_file_data); } function write_data(context, ofd, buffer, offset, length, position, callback) { var fileNode; var fileData; function return_nbytes(error) { if(error) { callback(error); } else { callback(null, length); } } function update_time(error) { if(error) { callback(error); } else { var now = Date.now(); update_node_times(context, ofd.path, fileNode, { mtime: now, ctime: now }, return_nbytes); } } function update_file_node(error) { if(error) { callback(error); } else { context.putObject(fileNode.id, fileNode, update_time); } } function update_file_data(error, result) { if(error) { callback(error); } else { fileData = result; if(!fileData) { return callback(new Errors.EIO('Expected Buffer')); } var _position = (!(undefined === position || null === position)) ? position : ofd.position; var newSize = Math.max(fileData.length, _position + length); var newData = new Buffer(newSize); newData.fill(0); if(fileData) { fileData.copy(newData); } buffer.copy(newData, _position, offset, offset + length); if(undefined === position) { ofd.position += length; } fileNode.size = newSize; fileNode.version += 1; context.putBuffer(fileNode.data, newData, update_file_node); } } function read_file_data(error, result) { if(error) { callback(error); } else { fileNode = result; context.getBuffer(fileNode.data, update_file_data); } } context.getObject(ofd.id, read_file_data); } function read_data(context, ofd, buffer, offset, length, position, callback) { var fileNode; var fileData; function handle_file_data(error, result) { if(error) { callback(error); } else { fileData = result; if(!fileData) { return callback(new Errors.EIO('Expected Buffer')); } var _position = (!(undefined === position || null === position)) ? position : ofd.position; length = (_position + length > buffer.length) ? length - _position : length; fileData.copy(buffer, offset, _position, _position + length); if(undefined === position) { ofd.position += length; } callback(null, length); } } function read_file_data(error, result) { if(error) { callback(error); } else if(result.mode === 'DIRECTORY') { callback(new Errors.EISDIR('the named file is a directory', ofd.path)); } else { fileNode = result; context.getBuffer(fileNode.data, handle_file_data); } } context.getObject(ofd.id, read_file_data); } function stat_file(context, path, callback) { path = normalize(path); var name = basename(path); find_node(context, path, callback); } function fstat_file(context, ofd, callback) { ofd.getNode(context, callback); } function lstat_file(context, path, callback) { path = normalize(path); var name = basename(path); var parentPath = dirname(path); var directoryNode; var directoryData; if(ROOT_DIRECTORY_NAME == name) { find_node(context, path, callback); } else { find_node(context, parentPath, read_directory_data); } function read_directory_data(error, result) { if(error) { callback(error); } else { directoryNode = result; context.getObject(directoryNode.data, check_if_file_exists); } } function check_if_file_exists(error, result) { if(error) { callback(error); } else { directoryData = result; if(!_(directoryData).has(name)) { callback(new Errors.ENOENT('a component of the path does not name an existing file', path)); } else { context.getObject(directoryData[name].id, callback); } } } } function link_node(context, oldpath, newpath, callback) { oldpath = normalize(oldpath); var oldname = basename(oldpath); var oldParentPath = dirname(oldpath); newpath = normalize(newpath); var newname = basename(newpath); var newParentPath = dirname(newpath); var oldDirectoryNode; var oldDirectoryData; var newDirectoryNode; var newDirectoryData; var fileNode; function update_time(error) { if(error) { callback(error); } else { update_node_times(context, newpath, fileNode, { ctime: Date.now() }, callback); } } function update_file_node(error, result) { if(error) { callback(error); } else { fileNode = result; fileNode.nlinks += 1; context.putObject(fileNode.id, fileNode, update_time); } } function read_directory_entry(error, result) { if(error) { callback(error); } else { context.getObject(newDirectoryData[newname].id, update_file_node); } } function check_if_new_file_exists(error, result) { if(error) { callback(error); } else { newDirectoryData = result; if(_(newDirectoryData).has(newname)) { callback(new Errors.EEXIST('newpath resolves to an existing file', newname)); } else { newDirectoryData[newname] = oldDirectoryData[oldname]; context.putObject(newDirectoryNode.data, newDirectoryData, read_directory_entry); } } } function read_new_directory_data(error, result) { if(error) { callback(error); } else { newDirectoryNode = result; context.getObject(newDirectoryNode.data, check_if_new_file_exists); } } function check_if_old_file_exists(error, result) { if(error) { callback(error); } else { oldDirectoryData = result; if(!_(oldDirectoryData).has(oldname)) { callback(new Errors.ENOENT('a component of either path prefix does not exist', oldname)); } else if(oldDirectoryData[oldname].type === 'DIRECTORY') { callback(new Errors.EPERM('oldpath refers to a directory')); } else { find_node(context, newParentPath, read_new_directory_data); } } } function read_old_directory_data(error, result) { if(error) { callback(error); } else { oldDirectoryNode = result; context.getObject(oldDirectoryNode.data, check_if_old_file_exists); } } find_node(context, oldParentPath, read_old_directory_data); } function unlink_node(context, path, callback) { path = normalize(path); var name = basename(path); var parentPath = dirname(path); var directoryNode; var directoryData; var fileNode; function update_directory_data(error) { if(error) { callback(error); } else { delete directoryData[name]; context.putObject(directoryNode.data, directoryData, function(error) { var now = Date.now(); update_node_times(context, parentPath, directoryNode, { mtime: now, ctime: now }, callback); }); } } function delete_file_data(error) { if(error) { callback(error); } else { context.delete(fileNode.data, update_directory_data); } } function update_file_node(error, result) { if(error) { callback(error); } else { fileNode = result; fileNode.nlinks -= 1; if(fileNode.nlinks < 1) { context.delete(fileNode.id, delete_file_data); } else { context.putObject(fileNode.id, fileNode, function(error) { update_node_times(context, path, fileNode, { ctime: Date.now() }, update_directory_data); }); } } } function check_if_node_is_directory(error, result) { if(error) { callback(error); } else if(result.mode === 'DIRECTORY') { callback(new Errors.EPERM('unlink not permitted on directories', name)); } else { update_file_node(null, result); } } function check_if_file_exists(error, result) { if(error) { callback(error); } else { directoryData = result; if(!_(directoryData).has(name)) { callback(new Errors.ENOENT('a component of the path does not name an existing file', name)); } else { context.getObject(directoryData[name].id, check_if_node_is_directory); } } } function read_directory_data(error, result) { if(error) { callback(error); } else { directoryNode = result; context.getObject(directoryNode.data, check_if_file_exists); } } find_node(context, parentPath, read_directory_data); } function read_directory(context, path, callback) { path = normalize(path); var name = basename(path); var directoryNode; var directoryData; function handle_directory_data(error, result) { if(error) { callback(error); } else { directoryData = result; var files = Object.keys(directoryData); callback(null, files); } } function read_directory_data(error, result) { if(error) { callback(error); } else if(result.mode !== MODE_DIRECTORY) { callback(new Errors.ENOTDIR(null, path)); } else { directoryNode = result; context.getObject(directoryNode.data, handle_directory_data); } } find_node(context, path, read_directory_data); } function make_symbolic_link(context, srcpath, dstpath, callback) { dstpath = normalize(dstpath); var name = basename(dstpath); var parentPath = dirname(dstpath); var directoryNode; var directoryData; var fileNode; if(ROOT_DIRECTORY_NAME == name) { callback(new Errors.EEXIST(null, name)); } else { find_node(context, parentPath, read_directory_data); } function read_directory_data(error, result) { if(error) { callback(error); } else { directoryNode = result; context.getObject(directoryNode.data, check_if_file_exists); } } function check_if_file_exists(error, result) { if(error) { callback(error); } else { directoryData = result; if(_(directoryData).has(name)) { callback(new Errors.EEXIST(null, name)); } else { write_file_node(); } } } function write_file_node() { Node.create({guid: context.guid, mode: MODE_SYMBOLIC_LINK}, function(error, result) { if(error) { callback(error); return; } fileNode = result; fileNode.nlinks += 1; fileNode.size = srcpath.length; fileNode.data = srcpath; context.putObject(fileNode.id, fileNode, update_directory_data); }); } function update_time(error) { if(error) { callback(error); } else { var now = Date.now(); update_node_times(context, parentPath, directoryNode, { mtime: now, ctime: now }, callback); } } function update_directory_data(error) { if(error) { callback(error); } else { directoryData[name] = new DirectoryEntry(fileNode.id, MODE_SYMBOLIC_LINK); context.putObject(directoryNode.data, directoryData, update_time); } } } function read_link(context, path, callback) { path = normalize(path); var name = basename(path); var parentPath = dirname(path); var directoryNode; var directoryData; find_node(context, parentPath, read_directory_data); function read_directory_data(error, result) { if(error) { callback(error); } else { directoryNode = result; context.getObject(directoryNode.data, check_if_file_exists); } } function check_if_file_exists(error, result) { if(error) { callback(error); } else { directoryData = result; if(!_(directoryData).has(name)) { callback(new Errors.ENOENT('a component of the path does not name an existing file', name)); } else { context.getObject(directoryData[name].id, check_if_symbolic); } } } function check_if_symbolic(error, result) { if(error) { callback(error); } else { if(result.mode != MODE_SYMBOLIC_LINK) { callback(new Errors.EINVAL('path not a symbolic link', path)); } else { callback(null, result.data); } } } } function truncate_file(context, path, length, callback) { path = normalize(path); var fileNode; function read_file_data (error, node) { if (error) { callback(error); } else if(node.mode == MODE_DIRECTORY ) { callback(new Errors.EISDIR(null, path)); } else{ fileNode = node; context.getBuffer(fileNode.data, truncate_file_data); } } function truncate_file_data(error, fileData) { if (error) { callback(error); } else { if(!fileData) { return callback(new Errors.EIO('Expected Buffer')); } var data = new Buffer(length); data.fill(0); if(fileData) { fileData.copy(data); } context.putBuffer(fileNode.data, data, update_file_node); } } function update_time(error) { if(error) { callback(error); } else { var now = Date.now(); update_node_times(context, path, fileNode, { mtime: now, ctime: now }, callback); } } function update_file_node (error) { if(error) { callback(error); } else { fileNode.size = length; fileNode.version += 1; context.putObject(fileNode.id, fileNode, update_time); } } if(length < 0) { callback(new Errors.EINVAL('length cannot be negative')); } else { find_node(context, path, read_file_data); } } function ftruncate_file(context, ofd, length, callback) { var fileNode; function read_file_data (error, node) { if (error) { callback(error); } else if(node.mode == MODE_DIRECTORY ) { callback(new Errors.EISDIR()); } else{ fileNode = node; context.getBuffer(fileNode.data, truncate_file_data); } } function truncate_file_data(error, fileData) { if (error) { callback(error); } else { var data; if(!fileData) { return callback(new Errors.EIO('Expected Buffer')); } if(fileData) { data = fileData.slice(0, length); } else { data = new Buffer(length); data.fill(0); } context.putBuffer(fileNode.data, data, update_file_node); } } function update_time(error) { if(error) { callback(error); } else { var now = Date.now(); update_node_times(context, ofd.path, fileNode, { mtime: now, ctime: now }, callback); } } function update_file_node (error) { if(error) { callback(error); } else { fileNode.size = length; fileNode.version += 1; context.putObject(fileNode.id, fileNode, update_time); } } if(length < 0) { callback(new Errors.EINVAL('length cannot be negative')); } else { ofd.getNode(context, read_file_data); } } function utimes_file(context, path, atime, mtime, callback) { path = normalize(path); function update_times(error, node) { if (error) { callback(error); } else { update_node_times(context, path, node, { atime: atime, ctime: mtime, mtime: mtime }, callback); } } if (typeof atime != 'number' || typeof mtime != 'number') { callback(new Errors.EINVAL('atime and mtime must be number', path)); } else if (atime < 0 || mtime < 0) { callback(new Errors.EINVAL('atime and mtime must be positive integers', path)); } else { find_node(context, path, update_times); } } function futimes_file(context, ofd, atime, mtime, callback) { function update_times (error, node) { if (error) { callback(error); } else { update_node_times(context, ofd.path, node, { atime: atime, ctime: mtime, mtime: mtime }, callback); } } if (typeof atime != 'number' || typeof mtime != 'number') { callback(new Errors.EINVAL('atime and mtime must be a number')); } else if (atime < 0 || mtime < 0) { callback(new Errors.EINVAL('atime and mtime must be positive integers')); } else { ofd.getNode(context, update_times); } } function setxattr_file(context, path, name, value, flag, callback) { path = normalize(path); function setxattr(error, node) { if(error) { return callback(error); } set_extended_attribute(context, path, node, name, value, flag, callback); } if (typeof name != 'string') { callback(new Errors.EINVAL('attribute name must be a string', path)); } else if (!name) { callback(new Errors.EINVAL('attribute name cannot be an empty string', path)); } else if (flag !== null && flag !== XATTR_CREATE && flag !== XATTR_REPLACE) { callback(new Errors.EINVAL('invalid flag, must be null, XATTR_CREATE or XATTR_REPLACE', path)); } else { find_node(context, path, setxattr); } } function fsetxattr_file (context, ofd, name, value, flag, callback) { function setxattr(error, node) { if(error) { return callback(error); } set_extended_attribute(context, ofd.path, node, name, value, flag, callback); } if (typeof name !== 'string') { callback(new Errors.EINVAL('attribute name must be a string')); } else if (!name) { callback(new Errors.EINVAL('attribute name cannot be an empty string')); } else if (flag !== null && flag !== XATTR_CREATE && flag !== XATTR_REPLACE) { callback(new Errors.EINVAL('invalid flag, must be null, XATTR_CREATE or XATTR_REPLACE')); } else { ofd.getNode(context, setxattr); } } function getxattr_file (context, path, name, callback) { path = normalize(path); function get_xattr(error, node) { if(error) { return callback(error); } var xattrs = node.xattrs; if (!xattrs.hasOwnProperty(name)) { callback(new Errors.ENOATTR(null, path)); } else { callback(null, xattrs[name]); } } if (typeof name != 'string') { callback(new Errors.EINVAL('attribute name must be a string', path)); } else if (!name) { callback(new Errors.EINVAL('attribute name cannot be an empty string', path)); } else { find_node(context, path, get_xattr); } } function fgetxattr_file (context, ofd, name, callback) { function get_xattr (error, node) { if (error) { return callback(error); } var xattrs = node.xattrs; if (!xattrs.hasOwnProperty(name)) { callback(new Errors.ENOATTR()); } else { callback(null, xattrs[name]); } } if (typeof name != 'string') { callback(new Errors.EINVAL()); } else if (!name) { callback(new Errors.EINVAL('attribute name cannot be an empty string')); } else { ofd.getNode(context, get_xattr); } } function removexattr_file (context, path, name, callback) { path = normalize(path); function remove_xattr (error, node) { if (error) { return callback(error); } function update_time(error) { if(error) { callback(error); } else { update_node_times(context, path, node, { ctime: Date.now() }, callback); } } var xattrs = node.xattrs; if (!xattrs.hasOwnProperty(name)) { callback(new Errors.ENOATTR(null, path)); } else { delete xattrs[name]; context.putObject(node.id, node, update_time); } } if (typeof name !== 'string') { callback(new Errors.EINVAL('attribute name must be a string', path)); } else if (!name) { callback(new Errors.EINVAL('attribute name cannot be an empty string', path)); } else { find_node(context, path, remove_xattr); } } function fremovexattr_file (context, ofd, name, callback) { function remove_xattr (error, node) { if (error) { return callback(error); } function update_time(error) { if(error) { callback(error); } else { update_node_times(context, ofd.path, node, { ctime: Date.now() }, callback); } } var xattrs = node.xattrs; if (!xattrs.hasOwnProperty(name)) { callback(new Errors.ENOATTR()); } else { delete xattrs[name]; context.putObject(node.id, node, update_time); } } if (typeof name != 'string') { callback(new Errors.EINVAL('attribute name must be a string')); } else if (!name) { callback(new Errors.EINVAL('attribute name cannot be an empty string')); } else { ofd.getNode(context, remove_xattr); } } function validate_flags(flags) { if(!_(O_FLAGS).has(flags)) { return null; } return O_FLAGS[flags]; } function validate_file_options(options, enc, fileMode){ if(!options) { options = { encoding: enc, flag: fileMode }; } else if(typeof options === "function") { options = { encoding: enc, flag: fileMode }; } else if(typeof options === "string") { options = { encoding: options, flag: fileMode }; } return options; } function pathCheck(path, callback) { var err; if(!path) { err = new Errors.EINVAL('Path must be a string', path); } else if(isNullPath(path)) { err = new Errors.EINVAL('Path must be a string without null bytes.', path); } else if(!isAbsolutePath(path)) { err = new Errors.EINVAL('Path must be absolute.', path); } if(err) { callback(err); return false; } return true; } function open(fs, context, path, flags, mode, callback) { // NOTE: we support the same signature as node with a `mode` arg, // but ignore it. callback = arguments[arguments.length - 1]; if(!pathCheck(path, callback)) return; function check_result(error, fileNode) { if(error) { callback(error); } else { var position; if(_(flags).contains(O_APPEND)) { position = fileNode.size; } else { position = 0; } var openFileDescription = new OpenFileDescription(path, fileNode.id, flags, position); var fd = fs.allocDescriptor(openFileDescription); callback(null, fd); } } flags = validate_flags(flags); if(!flags) { callback(new Errors.EINVAL('flags is not valid'), path); } open_file(context, path, flags, check_result); } function close(fs, context, fd, callback) { if(!_(fs.openFiles).has(fd)) { callback(new Errors.EBADF()); } else { fs.releaseDescriptor(fd); callback(null); } } function mknod(fs, context, path, mode, callback) { if(!pathCheck(path, callback)) return; make_node(context, path, mode, callback); } function mkdir(fs, context, path, mode, callback) { // NOTE: we support passing a mode arg, but we ignore it internally for now. callback = arguments[arguments.length - 1]; if(!pathCheck(path, callback)) return; make_directory(context, path, callback); } function rmdir(fs, context, path, callback) { if(!pathCheck(path, callback)) return; remove_directory(context, path, callback); } function stat(fs, context, path, callback) { if(!pathCheck(path, callback)) return; function check_result(error, result) { if(error) { callback(error); } else { var stats = new Stats(result, fs.name); callback(null, stats); } } stat_file(context, path, check_result); } function fstat(fs, context, fd, callback) { function check_result(error, result) { if(error) { callback(error); } else { var stats = new Stats(result, fs.name); callback(null, stats); } } var ofd = fs.openFiles[fd]; if(!ofd) { callback(new Errors.EBADF()); } else { fstat_file(context, ofd, check_result); } } function link(fs, context, oldpath, newpath, callback) { if(!pathCheck(oldpath, callback)) return; if(!pathCheck(newpath, callback)) return; link_node(context, oldpath, newpath, callback); } function unlink(fs, context, path, callback) { if(!pathCheck(path, callback)) return; unlink_node(context, path, callback); } function read(fs, context, fd, buffer, offset, length, position, callback) { // Follow how node.js does this function wrapped_cb(err, bytesRead) { // Retain a reference to buffer so that it can't be GC'ed too soon. callback(err, bytesRead || 0, buffer); } offset = (undefined === offset) ? 0 : offset; length = (undefined === length) ? buffer.length - offset : length; callback = arguments[arguments.length - 1]; var ofd = fs.openFiles[fd]; if(!ofd) { callback(new Errors.EBADF()); } else if(!_(ofd.flags).contains(O_READ)) { callback(new Errors.EBADF('descriptor does not permit reading')); } else { read_data(context, ofd, buffer, offset, length, position, wrapped_cb); } } function readFile(fs, context, path, options, callback) { callback = arguments[arguments.length - 1]; options = validate_file_options(options, null, 'r'); if(!pathCheck(path, callback)) return; var flags = validate_flags(options.flag || 'r'); if(!flags) { return callback(new Errors.EINVAL('flags is not valid', path)); } open_file(context, path, flags, function(err, fileNode) { if(err) { return callback(err); } var ofd = new OpenFileDescription(path, fileNode.id, flags, 0); var fd = fs.allocDescriptor(ofd); function cleanup() { fs.releaseDescriptor(fd); } fstat_file(context, ofd, function(err, fstatResult) { if(err) { cleanup(); return callback(err); } var stats = new Stats(fstatResult, fs.name); if(stats.isDirectory()) { cleanup(); return callback(new Errors.EISDIR('illegal operation on directory', path)); } var size = stats.size; var buffer = new Buffer(size); buffer.fill(0); read_data(context, ofd, buffer, 0, size, 0, function(err, nbytes) { cleanup(); if(err) { return callback(err); } var data; if(options.encoding === 'utf8') { data = Encoding.decode(buffer); } else { data = buffer; } callback(null, data); }); }); }); } function write(fs, context, fd, buffer, offset, length, position, callback) { callback = arguments[arguments.length - 1]; offset = (undefined === offset) ? 0 : offset; length = (undefined === length) ? buffer.length - offset : length; var ofd = fs.openFiles[fd]; if(!ofd) { callback(new Errors.EBADF()); } else if(!_(ofd.flags).contains(O_WRITE)) { callback(new Errors.EBADF('descriptor does not permit writing')); } else if(buffer.length - offset < length) { callback(new Errors.EIO('intput buffer is too small')); } else { write_data(context, ofd, buffer, offset, length, position, callback); } } function writeFile(fs, context, path, data, options, callback) { callback = arguments[arguments.length - 1]; options = validate_file_options(options, 'utf8', 'w'); if(!pathCheck(path, callback)) return; var flags = validate_flags(options.flag || 'w'); if(!flags) { return callback(new Errors.EINVAL('flags is not valid', path)); } data = data || ''; if(typeof data === "number") { data = '' + data; } if(typeof data === "string" && options.encoding === 'utf8') { data = Encoding.encode(data); } open_file(context, path, flags, function(err, fileNode) { if(err) { return callback(err); } var ofd = new OpenFileDescription(path, fileNode.id, flags, 0); var fd = fs.allocDescriptor(ofd); replace_data(context, ofd, data, 0, data.length, function(err, nbytes) { fs.releaseDescriptor(fd); if(err) { return callback(err); } callback(null); }); }); } function appendFile(fs, context, path, data, options, callback) { callback = arguments[arguments.length - 1]; options = validate_file_options(options, 'utf8', 'a'); if(!pathCheck(path, callback)) return; var flags = validate_flags(options.flag || 'a'); if(!flags) { return callback(new Errors.EINVAL('flags is not valid', path)); } data = data || ''; if(typeof data === "number") { data = '' + data; } if(typeof data === "string" && options.encoding === 'utf8') { data = Encoding.encode(data); } open_file(context, path, flags, function(err, fileNode) { if(err) { return callback(err); } var ofd = new OpenFileDescription(path, fileNode.id, flags, fileNode.size); var fd = fs.allocDescriptor(ofd); write_data(context, ofd, data, 0, data.length, ofd.position, function(err, nbytes) { fs.releaseDescriptor(fd); if(err) { return callback(err); } callback(null); }); }); } function exists(fs, context, path, callback) { function cb(err, stats) { callback(err ? false : true); } stat(fs, context, path, cb); } function getxattr(fs, context, path, name, callback) { if (!pathCheck(path, callback)) return; getxattr_file(context, path, name, callback); } function fgetxattr(fs, context, fd, name, callback) { var ofd = fs.openFiles[fd]; if (!ofd) { callback(new Errors.EBADF()); } else { fgetxattr_file(context, ofd, name, callback); } } function setxattr(fs, context, path, name, value, flag, callback) { if(typeof flag === 'function') { callback = flag; flag = null; } if (!pathCheck(path, callback)) return; setxattr_file(context, path, name, value, flag, callback); } function fsetxattr(fs, context, fd, name, value, flag, callback) { if(typeof flag === 'function') { callback = flag; flag = null; } var ofd = fs.openFiles[fd]; if (!ofd) { callback(new Errors.EBADF()); } else if (!_(ofd.flags).contains(O_WRITE)) { callback(new Errors.EBADF('descriptor does not permit writing')); } else { fsetxattr_file(context, ofd, name, value, flag, callback); } } function removexattr(fs, context, path, name, callback) { if (!pathCheck(path, callback)) return; removexattr_file(context, path, name, callback); } function fremovexattr(fs, context, fd, name, callback) { var ofd = fs.openFiles[fd]; if (!ofd) { callback(new Errors.EBADF()); } else if (!_(ofd.flags).contains(O_WRITE)) { callback(new Errors.EBADF('descriptor does not permit writing')); } else { fremovexattr_file(context, ofd, name, callback); } } function lseek(fs, context, fd, offset, whence, callback) { function update_descriptor_position(error, stats) { if(error) { callback(error); } else { if(stats.size + offset < 0) { callback(new Errors.EINVAL('resulting file offset would be negative')); } else { ofd.position = stats.size + offset; callback(null, ofd.position); } } } var ofd = fs.openFiles[fd]; if(!ofd) { callback(new Errors.EBADF()); } if('SET' === whence) { if(offset < 0) { callback(new Errors.EINVAL('resulting file offset would be negative')); } else { ofd.position = offset; callback(null, ofd.position); } } else if('CUR' === whence) { if(ofd.position + offset < 0) { callback(new Errors.EINVAL('resulting file offset would be negative')); } else { ofd.position += offset; callback(null, ofd.position); } } else if('END' === whence) { fstat_file(context, ofd, update_descriptor_position); } else { callback(new Errors.EINVAL('whence argument is not a proper value')); } } function readdir(fs, context, path, callback) { if(!pathCheck(path, callback)) return; read_directory(context, path, callback); } function utimes(fs, context, path, atime, mtime, callback) { if(!pathCheck(path, callback)) return; var currentTime = Date.now(); atime = (atime) ? atime : currentTime; mtime = (mtime) ? mtime : currentTime; utimes_file(context, path, atime, mtime, callback); } function futimes(fs, context, fd, atime, mtime, callback) { var currentTime = Date.now(); atime = (atime) ? atime : currentTime; mtime = (mtime) ? mtime : currentTime; var ofd = fs.openFiles[fd]; if(!ofd) { callback(new Errors.EBADF()); } else if(!_(ofd.flags).contains(O_WRITE)) { callback(new Errors.EBADF('descriptor does not permit writing')); } else { futimes_file(context, ofd, atime, mtime, callback); } } function rename(fs, context, oldpath, newpath, callback) { if(!pathCheck(oldpath, callback)) return; if(!pathCheck(newpath, callback)) return; oldpath = normalize(oldpath); newpath = normalize(newpath); var oldParentPath = Path.dirname(oldpath); var newParentPath = Path.dirname(oldpath); var oldName = Path.basename(oldpath); var newName = Path.basename(newpath); var oldParentDirectory, oldParentData; var newParentDirectory, newParentData; function update_times(error, newNode) { if(error) { callback(error); } else { update_node_times(context, newpath, newNode, { ctime: Date.now() }, callback); } } function read_new_directory(error) { if(error) { callback(error); } else { context.getObject(newParentData[newName].id, update_times); } } function update_old_parent_directory_data(error) { if(error) { callback(error); } else { if(oldParentDirectory.id === newParentDirectory.id) { oldParentData = newParentData; } delete oldParentData[oldName]; context.putObject(oldParentDirectory.data, oldParentData, read_new_directory); } } function update_new_parent_directory_data(error) { if(error) { callback(error); } else { newParentData[newName] = oldParentData[oldName]; context.putObject(newParentDirectory.data, newParentData, update_old_parent_directory_data); } } function check_if_new_directory_exists(error, result) { if(error) { callback(error); } else { newParentData = result; if(_(newParentData).has(newName)) { remove_directory(context, newpath, update_new_parent_directory_data); } else { update_new_parent_directory_data(); } } } function read_new_parent_directory_data(error, result) { if(error) { callback(error); } else { newParentDirectory = result; context.getObject(newParentDirectory.data, check_if_new_directory_exists); } } function get_new_parent_directory(error, result) { if(error) { callback(error); } else { oldParentData = result; find_node(context, newParentPath, read_new_parent_directory_data); } } function read_parent_directory_data(error, result) { if(error) { callback(error); } else { oldParentDirectory = result; context.getObject(result.data, get_new_parent_directory); } } function unlink_old_file(error) { if(error) { callback(error); } else { unlink_node(context, oldpath, callback); } } function check_node_type(error, node) { if(error) { callback(error); } else if(node.mode === 'DIRECTORY') { find_node(context, oldParentPath, read_parent_directory_data); } else { link_node(context, oldpath, newpath, unlink_old_file); } } find_node(context, oldpath, check_node_type); } function symlink(fs, context, srcpath, dstpath, type, callback) { // NOTE: we support passing the `type` arg, but ignore it. callback = arguments[arguments.length - 1]; if(!pathCheck(srcpath, callback)) return; if(!pathCheck(dstpath, callback)) return; make_symbolic_link(context, srcpath, dstpath, callback); } function readlink(fs, context, path, callback) { if(!pathCheck(path, callback)) return; read_link(context, path, callback); } function lstat(fs, context, path, callback) { if(!pathCheck(path, callback)) return; function check_result(error, result) { if(error) { callback(error); } else { var stats = new Stats(result, fs.name); callback(null, stats); } } lstat_file(context, path, check_result); } function truncate(fs, context, path, length, callback) { // NOTE: length is optional callback = arguments[arguments.length - 1]; length = length || 0; if(!pathCheck(path, callback)) return; truncate_file(context, path, length, callback); } function ftruncate(fs, context, fd, length, callback) { // NOTE: length is optional callback = arguments[arguments.length - 1]; length = length || 0; var ofd = fs.openFiles[fd]; if(!ofd) { callback(new Errors.EBADF()); } else if(!_(ofd.flags).contains(O_WRITE)) { callback(new Errors.EBADF('descriptor does not permit writing')); } else { ftruncate_file(context, ofd, length, callback); } } module.exports = { ensureRootDirectory: ensure_root_directory, open: open, close: close, mknod: mknod, mkdir: mkdir, rmdir: rmdir, unlink: unlink, stat: stat, fstat: fstat, link: link, read: read, readFile: readFile, write: write, writeFile: writeFile, appendFile: appendFile, exists: exists, getxattr: getxattr, fgetxattr: fgetxattr, setxattr: setxattr, fsetxattr: fsetxattr, removexattr: removexattr, fremovexattr: fremovexattr, lseek: lseek, readdir: readdir, utimes: utimes, futimes: futimes, rename: rename, symlink: symlink, readlink: readlink, lstat: lstat, truncate: truncate, ftruncate: ftruncate }; },{"../../lib/nodash.js":4,"../buffer.js":14,"../constants.js":15,"../directory-entry.js":16,"../encoding.js":17,"../errors.js":18,"../node.js":23,"../open-file-description.js":24,"../path.js":25,"../stats.js":33,"../super-node.js":34}],20:[function(_dereq_,module,exports){ var _ = _dereq_('../../lib/nodash.js'); var isNullPath = _dereq_('../path.js').isNull; var nop = _dereq_('../shared.js').nop; var Constants = _dereq_('../constants.js'); var FILE_SYSTEM_NAME = Constants.FILE_SYSTEM_NAME; var FS_FORMAT = Constants.FS_FORMAT; var FS_READY = Constants.FS_READY; var FS_PENDING = Constants.FS_PENDING; var FS_ERROR = Constants.FS_ERROR; var FS_NODUPEIDCHECK = Constants.FS_NODUPEIDCHECK; var providers = _dereq_('../providers/index.js'); var Shell = _dereq_('../shell/shell.js'); var Intercom = _dereq_('../../lib/intercom.js'); var FSWatcher = _dereq_('../fs-watcher.js'); var Errors = _dereq_('../errors.js'); var defaultGuidFn = _dereq_('../shared.js').guid; var STDIN = Constants.STDIN; var STDOUT = Constants.STDOUT; var STDERR = Constants.STDERR; var FIRST_DESCRIPTOR = Constants.FIRST_DESCRIPTOR; // The core fs operations live on impl var impl = _dereq_('./implementation.js'); // node.js supports a calling pattern that leaves off a callback. function maybeCallback(callback) { if(typeof callback === "function") { return callback; } return function(err) { if(err) { throw err; } }; } // Default callback that logs an error if passed in function defaultCallback(err) { if(err) { console.error('Filer error: ', err); } } /** * FileSystem * * A FileSystem takes an `options` object, which can specify a number of, * options. All options are optional, and include: * * name: the name of the file system, defaults to "local" * * flags: one or more flags to use when creating/opening the file system. * For example: "FORMAT" will cause the file system to be formatted. * No explicit flags are set by default. * * provider: an explicit storage provider to use for the file * system's database context provider. A number of context * providers are included (see /src/providers), and users * can write one of their own and pass it in to be used. * By default an IndexedDB provider is used. * * guid: a function for generating unique IDs for nodes in the filesystem. * Use this to override the built-in UUID generation. (Used mainly for tests). * * callback: a callback function to be executed when the file system becomes * ready for use. Depending on the context provider used, this might * be right away, or could take some time. The callback should expect * an `error` argument, which will be null if everything worked. Also * users should check the file system's `readyState` and `error` * properties to make sure it is usable. */ function FileSystem(options, callback) { options = options || {}; callback = callback || defaultCallback; var flags = options.flags; var guid = options.guid ? options.guid : defaultGuidFn; var provider = options.provider || new providers.Default(options.name || FILE_SYSTEM_NAME); // If we're given a provider, match its name unless we get an explicit name var name = options.name || provider.name; var forceFormatting = _(flags).contains(FS_FORMAT); var fs = this; fs.readyState = FS_PENDING; fs.name = name; fs.error = null; fs.stdin = STDIN; fs.stdout = STDOUT; fs.stderr = STDERR; // Expose Shell constructor this.Shell = Shell.bind(undefined, this); // Safely expose the list of open files and file // descriptor management functions var openFiles = {}; var nextDescriptor = FIRST_DESCRIPTOR; Object.defineProperty(this, "openFiles", { get: function() { return openFiles; } }); this.allocDescriptor = function(openFileDescription) { var fd = nextDescriptor ++; openFiles[fd] = openFileDescription; return fd; }; this.releaseDescriptor = function(fd) { delete openFiles[fd]; }; // Safely expose the operation queue var queue = []; this.queueOrRun = function(operation) { var error; if(FS_READY == fs.readyState) { operation.call(fs); } else if(FS_ERROR == fs.readyState) { error = new Errors.EFILESYSTEMERROR('unknown error'); } else { queue.push(operation); } return error; }; function runQueued() { queue.forEach(function(operation) { operation.call(this); }.bind(fs)); queue = null; } // We support the optional `options` arg from node, but ignore it this.watch = function(filename, options, listener) { if(isNullPath(filename)) { throw new Error('Path must be a string without null bytes.'); } if(typeof options === 'function') { listener = options; options = {}; } options = options || {}; listener = listener || nop; var watcher = new FSWatcher(); watcher.start(filename, false, options.recursive); watcher.on('change', listener); return watcher; }; // Deal with various approaches to node ID creation function wrappedGuidFn(context) { return function(callback) { // Skip the duplicate ID check if asked to if(_(flags).contains(FS_NODUPEIDCHECK)) { callback(null, guid()); return; } // Otherwise (default) make sure this id is unused first function guidWithCheck(callback) { var id = guid(); context.getObject(id, function(err, value) { if(err) { callback(err); return; } // If this id is unused, use it, otherwise find another if(!value) { callback(null, id); } else { guidWithCheck(callback); } }); } guidWithCheck(callback); }; } // Let other instances (in this or other windows) know about // any changes to this fs instance. function broadcastChanges(changes) { if(!changes.length) { return; } var intercom = Intercom.getInstance(); changes.forEach(function(change) { intercom.emit(change.event, change.path); }); } // Open file system storage provider provider.open(function(err) { function complete(error) { function wrappedContext(methodName) { var context = provider[methodName](); context.flags = flags; context.changes = []; context.guid = wrappedGuidFn(context); // When the context is finished, let the fs deal with any change events context.close = function() { var changes = context.changes; broadcastChanges(changes); changes.length = 0; }; return context; } // Wrap the provider so we can extend the context with fs flags and // an array of changes (e.g., watch event 'change' and 'rename' events // for paths updated during the lifetime of the context). From this // point forward we won't call open again, so it's safe to drop it. fs.provider = { openReadWriteContext: function() { return wrappedContext('getReadWriteContext'); }, openReadOnlyContext: function() { return wrappedContext('getReadOnlyContext'); } }; if(error) { fs.readyState = FS_ERROR; } else { fs.readyState = FS_READY; } runQueued(); callback(error, fs); } if(err) { return complete(err); } var context = provider.getReadWriteContext(); context.guid = wrappedGuidFn(context); // Mount the filesystem, formatting if necessary if(forceFormatting) { // Wipe the storage provider, then write root block context.clear(function(err) { if(err) { return complete(err); } impl.ensureRootDirectory(context, complete); }); } else { // Use existing (or create new) root and mount impl.ensureRootDirectory(context, complete); } }); } // Expose storage providers on FileSystem constructor FileSystem.providers = providers; /** * Public API for FileSystem */ [ 'open', 'close', 'mknod', 'mkdir', 'rmdir', 'stat', 'fstat', 'link', 'unlink', 'read', 'readFile', 'write', 'writeFile', 'appendFile', 'exists', 'lseek', 'readdir', 'rename', 'readlink', 'symlink', 'lstat', 'truncate', 'ftruncate', 'utimes', 'futimes', 'setxattr', 'getxattr', 'fsetxattr', 'fgetxattr', 'removexattr', 'fremovexattr' ].forEach(function(methodName) { FileSystem.prototype[methodName] = function() { var fs = this; var args = Array.prototype.slice.call(arguments, 0); var lastArgIndex = args.length - 1; // We may or may not get a callback, and since node.js supports // fire-and-forget style fs operations, we have to dance a bit here. var missingCallback = typeof args[lastArgIndex] !== 'function'; var callback = maybeCallback(args[lastArgIndex]); var error = fs.queueOrRun(function() { var context = fs.provider.openReadWriteContext(); // Fail early if the filesystem is in an error state (e.g., // provider failed to open. if(FS_ERROR === fs.readyState) { var err = new Errors.EFILESYSTEMERROR('filesystem unavailable, operation canceled'); return callback.call(fs, err); } // Wrap the callback so we can explicitly close the context function complete() { context.close(); callback.apply(fs, arguments); } // Either add or replace the callback with our wrapper complete() if(missingCallback) { args.push(complete); } else { args[lastArgIndex] = complete; } // Forward this call to the impl's version, using the following // call signature, with complete() as the callback/last-arg now: // fn(fs, context, arg0, arg1, ... , complete); var fnArgs = [fs, context].concat(args); impl[methodName].apply(null, fnArgs); }); if(error) { callback(error); } }; }); module.exports = FileSystem; },{"../../lib/intercom.js":3,"../../lib/nodash.js":4,"../constants.js":15,"../errors.js":18,"../fs-watcher.js":21,"../path.js":25,"../providers/index.js":26,"../shared.js":30,"../shell/shell.js":32,"./implementation.js":19}],21:[function(_dereq_,module,exports){ var EventEmitter = _dereq_('../lib/eventemitter.js'); var Path = _dereq_('./path.js'); var Intercom = _dereq_('../lib/intercom.js'); /** * FSWatcher based on node.js' FSWatcher * see https://github.com/joyent/node/blob/master/lib/fs.js */ function FSWatcher() { EventEmitter.call(this); var self = this; var recursive = false; var recursivePathPrefix; var filename; function onchange(path) { // Watch for exact filename, or parent path when recursive is true. if(filename === path || (recursive && path.indexOf(recursivePathPrefix) === 0)) { self.trigger('change', 'change', path); } } // We support, but ignore the second arg, which node.js uses. self.start = function(filename_, persistent_, recursive_) { // Bail if we've already started (and therefore have a filename); if(filename) { return; } if(Path.isNull(filename_)) { throw new Error('Path must be a string without null bytes.'); } // TODO: get realpath for symlinks on filename... // Filer's Path.normalize strips trailing slashes, which we use here. // See https://github.com/js-platform/filer/issues/105 filename = Path.normalize(filename_); // Whether to watch beneath this path or not recursive = recursive_ === true; // If recursive, construct a path prefix portion for comparisons later // (i.e., '/path' becomes '/path/' so we can search within a filename for the // prefix). We also take care to allow for '/' on its own. if(recursive) { recursivePathPrefix = filename === '/' ? '/' : filename + '/'; } var intercom = Intercom.getInstance(); intercom.on('change', onchange); }; self.close = function() { var intercom = Intercom.getInstance(); intercom.off('change', onchange); self.removeAllListeners('change'); }; } FSWatcher.prototype = new EventEmitter(); FSWatcher.prototype.constructor = FSWatcher; module.exports = FSWatcher; },{"../lib/eventemitter.js":2,"../lib/intercom.js":3,"./path.js":25}],22:[function(_dereq_,module,exports){ module.exports = { FileSystem: _dereq_('./filesystem/interface.js'), Buffer: _dereq_('./buffer.js'), Path: _dereq_('./path.js'), Errors: _dereq_('./errors.js'), Shell: _dereq_('./shell/shell.js') }; },{"./buffer.js":14,"./errors.js":18,"./filesystem/interface.js":20,"./path.js":25,"./shell/shell.js":32}],23:[function(_dereq_,module,exports){ var MODE_FILE = _dereq_('./constants.js').MODE_FILE; function Node(options) { var now = Date.now(); this.id = options.id; this.mode = options.mode || MODE_FILE; // node type (file, directory, etc) this.size = options.size || 0; // size (bytes for files, entries for directories) this.atime = options.atime || now; // access time (will mirror ctime after creation) this.ctime = options.ctime || now; // creation/change time this.mtime = options.mtime || now; // modified time this.flags = options.flags || []; // file flags this.xattrs = options.xattrs || {}; // extended attributes this.nlinks = options.nlinks || 0; // links count this.version = options.version || 0; // node version this.blksize = undefined; // block size this.nblocks = 1; // blocks count this.data = options.data; // id for data object } // Make sure the options object has an id on property, // either from caller or one we generate using supplied guid fn. function ensureID(options, prop, callback) { if(options[prop]) { callback(null); } else { options.guid(function(err, id) { options[prop] = id; callback(err); }); } } Node.create = function(options, callback) { // We expect both options.id and options.data to be provided/generated. ensureID(options, 'id', function(err) { if(err) { callback(err); return; } ensureID(options, 'data', function(err) { if(err) { callback(err); return; } callback(null, new Node(options)); }); }); }; module.exports = Node; },{"./constants.js":15}],24:[function(_dereq_,module,exports){ var Errors = _dereq_('./errors.js'); function OpenFileDescription(path, id, flags, position) { this.path = path; this.id = id; this.flags = flags; this.position = position; } // Tries to find the node associated with an ofd's `id`. // If not found, an error is returned on the callback. OpenFileDescription.prototype.getNode = function(context, callback) { var id = this.id; var path = this.path; function check_if_node_exists(error, node) { if(error) { return callback(error); } if(!node) { return callback(new Errors.EBADF('file descriptor refers to unknown node', path)); } callback(null, node); } context.getObject(id, check_if_node_exists); }; module.exports = OpenFileDescription; },{"./errors.js":18}],25:[function(_dereq_,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. // Based on https://github.com/joyent/node/blob/41e53e557992a7d552a8e23de035f9463da25c99/lib/path.js // resolves . and .. elements in a path array with directory names there // must be no slashes, empty elements, or device names (c:\) in the array // (so also no leading and trailing slashes - it does not distinguish // relative and absolute paths) function normalizeArray(parts, allowAboveRoot) { // if the path tries to go above the root, `up` ends up > 0 var up = 0; for (var i = parts.length - 1; i >= 0; i--) { var last = parts[i]; if (last === '.') { parts.splice(i, 1); } else if (last === '..') { parts.splice(i, 1); up++; } else if (up) { parts.splice(i, 1); up--; } } // if the path is allowed to go above the root, restore leading ..s if (allowAboveRoot) { for (; up--; up) { parts.unshift('..'); } } return parts; } // Split a filename into [root, dir, basename, ext], unix version // 'root' is just a slash, or nothing. var splitPathRe = /^(\/?)([\s\S]+\/(?!$)|\/)?((?:\.{1,2}$|[\s\S]+?)?(\.[^.\/]*)?)$/; var splitPath = function(filename) { var result = splitPathRe.exec(filename); return [result[1] || '', result[2] || '', result[3] || '', result[4] || '']; }; // path.resolve([from ...], to) function resolve() { var resolvedPath = '', resolvedAbsolute = false; for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { // XXXfiler: we don't have process.cwd() so we use '/' as a fallback var path = (i >= 0) ? arguments[i] : '/'; // Skip empty and invalid entries if (typeof path !== 'string' || !path) { continue; } resolvedPath = path + '/' + resolvedPath; resolvedAbsolute = path.charAt(0) === '/'; } // At this point the path should be resolved to a full absolute path, but // handle relative paths to be safe (might happen when process.cwd() fails) // Normalize the path resolvedPath = normalizeArray(resolvedPath.split('/').filter(function(p) { return !!p; }), !resolvedAbsolute).join('/'); return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; } // path.normalize(path) function normalize(path) { var isAbsolute = path.charAt(0) === '/', trailingSlash = path.substr(-1) === '/'; // Normalize the path path = normalizeArray(path.split('/').filter(function(p) { return !!p; }), !isAbsolute).join('/'); if (!path && !isAbsolute) { path = '.'; } /* if (path && trailingSlash) { path += '/'; } */ return (isAbsolute ? '/' : '') + path; } function join() { var paths = Array.prototype.slice.call(arguments, 0); return normalize(paths.filter(function(p, index) { return p && typeof p === 'string'; }).join('/')); } // path.relative(from, to) function relative(from, to) { from = exports.resolve(from).substr(1); to = exports.resolve(to).substr(1); function trim(arr) { var start = 0; for (; start < arr.length; start++) { if (arr[start] !== '') break; } var end = arr.length - 1; for (; end >= 0; end--) { if (arr[end] !== '') break; } if (start > end) return []; return arr.slice(start, end - start + 1); } var fromParts = trim(from.split('/')); var toParts = trim(to.split('/')); var length = Math.min(fromParts.length, toParts.length); var samePartsLength = length; for (var i = 0; i < length; i++) { if (fromParts[i] !== toParts[i]) { samePartsLength = i; break; } } var outputParts = []; for (var i = samePartsLength; i < fromParts.length; i++) { outputParts.push('..'); } outputParts = outputParts.concat(toParts.slice(samePartsLength)); return outputParts.join('/'); } function dirname(path) { var result = splitPath(path), root = result[0], dir = result[1]; if (!root && !dir) { // No dirname whatsoever return '.'; } if (dir) { // It has a dirname, strip trailing slash dir = dir.substr(0, dir.length - 1); } return root + dir; } function basename(path, ext) { var f = splitPath(path)[2]; // TODO: make this comparison case-insensitive on windows? if (ext && f.substr(-1 * ext.length) === ext) { f = f.substr(0, f.length - ext.length); } // XXXfiler: node.js just does `return f` return f === "" ? "/" : f; } function extname(path) { return splitPath(path)[3]; } function isAbsolute(path) { if(path.charAt(0) === '/') { return true; } return false; } function isNull(path) { if (('' + path).indexOf('\u0000') !== -1) { return true; } return false; } // Make sure we don't double-add a trailing slash (e.g., '/' -> '//') function addTrailing(path) { return path.replace(/\/*$/, '/'); } // Deal with multiple slashes at the end, one, or none // and make sure we don't return the empty string. function removeTrailing(path) { path = path.replace(/\/*$/, ''); return path === '' ? '/' : path; } // XXXfiler: we don't support path.exists() or path.existsSync(), which // are deprecated, and need a FileSystem instance to work. Use fs.stat(). module.exports = { normalize: normalize, resolve: resolve, join: join, relative: relative, sep: '/', delimiter: ':', dirname: dirname, basename: basename, extname: extname, isAbsolute: isAbsolute, isNull: isNull, // Non-node but useful... addTrailing: addTrailing, removeTrailing: removeTrailing }; },{}],26:[function(_dereq_,module,exports){ var IndexedDB = _dereq_('./indexeddb.js'); var WebSQL = _dereq_('./websql.js'); var Memory = _dereq_('./memory.js'); module.exports = { IndexedDB: IndexedDB, WebSQL: WebSQL, Memory: Memory, /** * Convenience Provider references */ // The default provider to use when none is specified Default: IndexedDB, // The Fallback provider does automatic fallback checks Fallback: (function() { if(IndexedDB.isSupported()) { return IndexedDB; } if(WebSQL.isSupported()) { return WebSQL; } function NotSupported() { throw "[Filer Error] Your browser doesn't support IndexedDB or WebSQL."; } NotSupported.isSupported = function() { return false; }; return NotSupported; }()) }; },{"./indexeddb.js":27,"./memory.js":28,"./websql.js":29}],27:[function(_dereq_,module,exports){ (function (global,Buffer){ var FILE_SYSTEM_NAME = _dereq_('../constants.js').FILE_SYSTEM_NAME; var FILE_STORE_NAME = _dereq_('../constants.js').FILE_STORE_NAME; var IDB_RW = _dereq_('../constants.js').IDB_RW; var IDB_RO = _dereq_('../constants.js').IDB_RO; var Errors = _dereq_('../errors.js'); var FilerBuffer = _dereq_('../buffer.js'); var indexedDB = global.indexedDB || global.mozIndexedDB || global.webkitIndexedDB || global.msIndexedDB; function IndexedDBContext(db, mode) { var transaction = db.transaction(FILE_STORE_NAME, mode); this.objectStore = transaction.objectStore(FILE_STORE_NAME); } IndexedDBContext.prototype.clear = function(callback) { try { var request = this.objectStore.clear(); request.onsuccess = function(event) { callback(); }; request.onerror = function(error) { callback(error); }; } catch(e) { callback(e); } }; function _get(objectStore, key, callback) { try { var request = objectStore.get(key); request.onsuccess = function onsuccess(event) { var result = event.target.result; callback(null, result); }; request.onerror = function onerror(error) { callback(error); }; } catch(e) { callback(e); } } IndexedDBContext.prototype.getObject = function(key, callback) { _get(this.objectStore, key, callback); }; IndexedDBContext.prototype.getBuffer = function(key, callback) { _get(this.objectStore, key, function(err, arrayBuffer) { if(err) { return callback(err); } callback(null, new FilerBuffer(arrayBuffer)); }); }; function _put(objectStore, key, value, callback) { try { var request = objectStore.put(value, key); request.onsuccess = function onsuccess(event) { var result = event.target.result; callback(null, result); }; request.onerror = function onerror(error) { callback(error); }; } catch(e) { callback(e); } } IndexedDBContext.prototype.putObject = function(key, value, callback) { _put(this.objectStore, key, value, callback); }; IndexedDBContext.prototype.putBuffer = function(key, uint8BackedBuffer, callback) { var buf; if(!Buffer._useTypedArrays) { // workaround for fxos 1.3 buf = uint8BackedBuffer.toArrayBuffer(); } else { buf = uint8BackedBuffer.buffer; } _put(this.objectStore, key, buf, callback); }; IndexedDBContext.prototype.delete = function(key, callback) { try { var request = this.objectStore.delete(key); request.onsuccess = function onsuccess(event) { var result = event.target.result; callback(null, result); }; request.onerror = function(error) { callback(error); }; } catch(e) { callback(e); } }; function IndexedDB(name) { this.name = name || FILE_SYSTEM_NAME; this.db = null; } IndexedDB.isSupported = function() { return !!indexedDB; }; IndexedDB.prototype.open = function(callback) { var that = this; // Bail if we already have a db open if(that.db) { return callback(); } // NOTE: we're not using versioned databases. var openRequest = indexedDB.open(that.name); // If the db doesn't exist, we'll create it openRequest.onupgradeneeded = function onupgradeneeded(event) { var db = event.target.result; if(db.objectStoreNames.contains(FILE_STORE_NAME)) { db.deleteObjectStore(FILE_STORE_NAME); } db.createObjectStore(FILE_STORE_NAME); }; openRequest.onsuccess = function onsuccess(event) { that.db = event.target.result; callback(); }; openRequest.onerror = function onerror(error) { callback(new Errors.EINVAL('IndexedDB cannot be accessed. If private browsing is enabled, disable it.')); }; }; IndexedDB.prototype.getReadOnlyContext = function() { // Due to timing issues in Chrome with readwrite vs. readonly indexeddb transactions // always use readwrite so we can make sure pending commits finish before callbacks. // See https://github.com/js-platform/filer/issues/128 return new IndexedDBContext(this.db, IDB_RW); }; IndexedDB.prototype.getReadWriteContext = function() { return new IndexedDBContext(this.db, IDB_RW); }; module.exports = IndexedDB; }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},_dereq_("buffer").Buffer) },{"../buffer.js":14,"../constants.js":15,"../errors.js":18,"buffer":6}],28:[function(_dereq_,module,exports){ var FILE_SYSTEM_NAME = _dereq_('../constants.js').FILE_SYSTEM_NAME; // NOTE: prefer setImmediate to nextTick for proper recursion yielding. // see https://github.com/js-platform/filer/pull/24 var asyncCallback = _dereq_('../../lib/async.js').setImmediate; /** * Make shared in-memory DBs possible when using the same name. */ var createDB = (function() { var pool = {}; return function getOrCreate(name) { if(!pool.hasOwnProperty(name)) { pool[name] = {}; } return pool[name]; }; }()); function MemoryContext(db, readOnly) { this.readOnly = readOnly; this.objectStore = db; } MemoryContext.prototype.clear = function(callback) { if(this.readOnly) { asyncCallback(function() { callback("[MemoryContext] Error: write operation on read only context"); }); return; } var objectStore = this.objectStore; Object.keys(objectStore).forEach(function(key){ delete objectStore[key]; }); asyncCallback(callback); }; // Memory context doesn't care about differences between Object and Buffer MemoryContext.prototype.getObject = MemoryContext.prototype.getBuffer = function(key, callback) { var that = this; asyncCallback(function() { callback(null, that.objectStore[key]); }); }; MemoryContext.prototype.putObject = MemoryContext.prototype.putBuffer = function(key, value, callback) { if(this.readOnly) { asyncCallback(function() { callback("[MemoryContext] Error: write operation on read only context"); }); return; } this.objectStore[key] = value; asyncCallback(callback); }; MemoryContext.prototype.delete = function(key, callback) { if(this.readOnly) { asyncCallback(function() { callback("[MemoryContext] Error: write operation on read only context"); }); return; } delete this.objectStore[key]; asyncCallback(callback); }; function Memory(name) { this.name = name || FILE_SYSTEM_NAME; } Memory.isSupported = function() { return true; }; Memory.prototype.open = function(callback) { this.db = createDB(this.name); asyncCallback(callback); }; Memory.prototype.getReadOnlyContext = function() { return new MemoryContext(this.db, true); }; Memory.prototype.getReadWriteContext = function() { return new MemoryContext(this.db, false); }; module.exports = Memory; },{"../../lib/async.js":1,"../constants.js":15}],29:[function(_dereq_,module,exports){ (function (global){ var FILE_SYSTEM_NAME = _dereq_('../constants.js').FILE_SYSTEM_NAME; var FILE_STORE_NAME = _dereq_('../constants.js').FILE_STORE_NAME; var WSQL_VERSION = _dereq_('../constants.js').WSQL_VERSION; var WSQL_SIZE = _dereq_('../constants.js').WSQL_SIZE; var WSQL_DESC = _dereq_('../constants.js').WSQL_DESC; var Errors = _dereq_('../errors.js'); var FilerBuffer = _dereq_('../buffer.js'); var base64ArrayBuffer = _dereq_('base64-arraybuffer'); function WebSQLContext(db, isReadOnly) { var that = this; this.getTransaction = function(callback) { if(that.transaction) { callback(that.transaction); return; } // Either do readTransaction() (read-only) or transaction() (read/write) db[isReadOnly ? 'readTransaction' : 'transaction'](function(transaction) { that.transaction = transaction; callback(transaction); }); }; } WebSQLContext.prototype.clear = function(callback) { function onError(transaction, error) { callback(error); } function onSuccess(transaction, result) { callback(null); } this.getTransaction(function(transaction) { transaction.executeSql("DELETE FROM " + FILE_STORE_NAME + ";", [], onSuccess, onError); }); }; function _get(getTransaction, key, callback) { function onSuccess(transaction, result) { // If the key isn't found, return null var value = result.rows.length === 0 ? null : result.rows.item(0).data; callback(null, value); } function onError(transaction, error) { callback(error); } getTransaction(function(transaction) { transaction.executeSql("SELECT data FROM " + FILE_STORE_NAME + " WHERE id = ? LIMIT 1;", [key], onSuccess, onError); }); } WebSQLContext.prototype.getObject = function(key, callback) { _get(this.getTransaction, key, function(err, result) { if(err) { return callback(err); } try { if(result) { result = JSON.parse(result); } } catch(e) { return callback(e); } callback(null, result); }); }; WebSQLContext.prototype.getBuffer = function(key, callback) { _get(this.getTransaction, key, function(err, result) { if(err) { return callback(err); } // Deal with zero-length ArrayBuffers, which will be encoded as '' if(result || result === '') { var arrayBuffer = base64ArrayBuffer.decode(result); result = new FilerBuffer(arrayBuffer); } callback(null, result); }); }; function _put(getTransaction, key, value, callback) { function onSuccess(transaction, result) { callback(null); } function onError(transaction, error) { callback(error); } getTransaction(function(transaction) { transaction.executeSql("INSERT OR REPLACE INTO " + FILE_STORE_NAME + " (id, data) VALUES (?, ?);", [key, value], onSuccess, onError); }); } WebSQLContext.prototype.putObject = function(key, value, callback) { var json = JSON.stringify(value); _put(this.getTransaction, key, json, callback); }; WebSQLContext.prototype.putBuffer = function(key, uint8BackedBuffer, callback) { var base64 = base64ArrayBuffer.encode(uint8BackedBuffer.buffer); _put(this.getTransaction, key, base64, callback); }; WebSQLContext.prototype.delete = function(key, callback) { function onSuccess(transaction, result) { callback(null); } function onError(transaction, error) { callback(error); } this.getTransaction(function(transaction) { transaction.executeSql("DELETE FROM " + FILE_STORE_NAME + " WHERE id = ?;", [key], onSuccess, onError); }); }; function WebSQL(name) { this.name = name || FILE_SYSTEM_NAME; this.db = null; } WebSQL.isSupported = function() { return !!global.openDatabase; }; WebSQL.prototype.open = function(callback) { var that = this; // Bail if we already have a db open if(that.db) { return callback(); } var db = global.openDatabase(that.name, WSQL_VERSION, WSQL_DESC, WSQL_SIZE); if(!db) { callback("[WebSQL] Unable to open database."); return; } function onError(transaction, error) { if (error.code === 5) { callback(new Errors.EINVAL('WebSQL cannot be accessed. If private browsing is enabled, disable it.')); } callback(error); } function onSuccess(transaction, result) { that.db = db; callback(); } // Create the table and index we'll need to store the fs data. db.transaction(function(transaction) { function createIndex(transaction) { transaction.executeSql("CREATE INDEX IF NOT EXISTS idx_" + FILE_STORE_NAME + "_id" + " on " + FILE_STORE_NAME + " (id);", [], onSuccess, onError); } transaction.executeSql("CREATE TABLE IF NOT EXISTS " + FILE_STORE_NAME + " (id unique, data TEXT);", [], createIndex, onError); }); }; WebSQL.prototype.getReadOnlyContext = function() { return new WebSQLContext(this.db, true); }; WebSQL.prototype.getReadWriteContext = function() { return new WebSQLContext(this.db, false); }; module.exports = WebSQL; }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"../buffer.js":14,"../constants.js":15,"../errors.js":18,"base64-arraybuffer":5}],30:[function(_dereq_,module,exports){ function guid() { 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); }).toUpperCase(); } function nop() {} /** * Convert a Uint8Array to a regular array */ function u8toArray(u8) { var array = []; var len = u8.length; for(var i = 0; i < len; i++) { array[i] = u8[i]; } return array; } module.exports = { guid: guid, u8toArray: u8toArray, nop: nop }; },{}],31:[function(_dereq_,module,exports){ var defaults = _dereq_('../constants.js').ENVIRONMENT; module.exports = function Environment(env) { env = env || {}; env.TMP = env.TMP || defaults.TMP; env.PATH = env.PATH || defaults.PATH; this.get = function(name) { return env[name]; }; this.set = function(name, value) { env[name] = value; }; }; },{"../constants.js":15}],32:[function(_dereq_,module,exports){ var Path = _dereq_('../path.js'); var Errors = _dereq_('../errors.js'); var Environment = _dereq_('./environment.js'); var async = _dereq_('../../lib/async.js'); var Encoding = _dereq_('../encoding.js'); var minimatch = _dereq_('minimatch'); function Shell(fs, options) { options = options || {}; var env = new Environment(options.env); var cwd = '/'; /** * The bound FileSystem (cannot be changed) */ Object.defineProperty(this, 'fs', { get: function() { return fs; }, enumerable: true }); /** * The shell's environment (e.g., for things like * path, tmp, and other env vars). Use env.get() * and env.set() to work with variables. */ Object.defineProperty(this, 'env', { get: function() { return env; }, enumerable: true }); /** * Change the current working directory. We * include `cd` on the `this` vs. proto so that * we can access cwd without exposing it externally. */ this.cd = function(path, callback) { path = Path.resolve(cwd, path); // Make sure the path actually exists, and is a dir fs.stat(path, function(err, stats) { if(err) { callback(new Errors.ENOTDIR(null, path)); return; } if(stats.type === 'DIRECTORY') { cwd = path; callback(); } else { callback(new Errors.ENOTDIR(null, path)); } }); }; /** * Get the current working directory (changed with `cd()`) */ this.pwd = function() { return cwd; }; } /** * Execute the .js command located at `path`. Such commands * should assume the existence of 3 arguments, which will be * defined at runtime: * * * fs - the current shell's bound filesystem object * * args - a list of arguments for the command, or an empty list if none * * callback - a callback function(error, result) to call when done. * * The .js command's contents should be the body of a function * that looks like this: * * function(fs, args, callback) { * // .js code here * } */ Shell.prototype.exec = function(path, args, callback) { /* jshint evil:true */ var sh = this; var fs = sh.fs; if(typeof args === 'function') { callback = args; args = []; } args = args || []; callback = callback || function(){}; path = Path.resolve(sh.pwd(), path); fs.readFile(path, "utf8", function(error, data) { if(error) { callback(error); return; } try { var cmd = new Function('fs', 'args', 'callback', data); cmd(fs, args, callback); } catch(e) { callback(e); } }); }; /** * Create a file if it does not exist, or update access and * modified times if it does. Valid options include: * * * updateOnly - whether to create the file if missing (defaults to false) * * date - use the provided Date value instead of current date/time */ Shell.prototype.touch = function(path, options, callback) { var sh = this; var fs = sh.fs; if(typeof options === 'function') { callback = options; options = {}; } options = options || {}; callback = callback || function(){}; path = Path.resolve(sh.pwd(), path); function createFile(path) { fs.writeFile(path, '', callback); } function updateTimes(path) { var now = Date.now(); var atime = options.date || now; var mtime = options.date || now; fs.utimes(path, atime, mtime, callback); } fs.stat(path, function(error, stats) { if(error) { if(options.updateOnly === true) { callback(); } else { createFile(path); } } else { updateTimes(path); } }); }; /** * Concatenate multiple files into a single String, with each * file separated by a newline. The `files` argument should * be a String (path to single file) or an Array of Strings * (multiple file paths). */ Shell.prototype.cat = function(files, callback) { var sh = this; var fs = sh.fs; var all = ''; callback = callback || function(){}; if(!files) { callback(new Errors.EINVAL('Missing files argument')); return; } files = typeof files === 'string' ? [ files ] : files; function append(item, callback) { var filename = Path.resolve(sh.pwd(), item); fs.readFile(filename, 'utf8', function(error, data) { if(error) { callback(error); return; } all += data + '\n'; callback(); }); } async.eachSeries(files, append, function(error) { if(error) { callback(error); } else { callback(null, all.replace(/\n$/, '')); } }); }; /** * Get the listing of a directory, returning an array of * file entries in the following form: * * { * path: <String> the basename of the directory entry * links: <Number> the number of links to the entry * size: <Number> the size in bytes of the entry * modified: <Number> the last modified date/time * type: <String> the type of the entry * contents: <Array> an optional array of child entries * } * * By default ls() gives a shallow listing. If you want * to follow directories as they are encountered, use * the `recursive=true` option. */ Shell.prototype.ls = function(dir, options, callback) { var sh = this; var fs = sh.fs; if(typeof options === 'function') { callback = options; options = {}; } options = options || {}; callback = callback || function(){}; if(!dir) { callback(new Errors.EINVAL('Missing dir argument')); return; } function list(path, callback) { var pathname = Path.resolve(sh.pwd(), path); var result = []; fs.readdir(pathname, function(error, entries) { if(error) { callback(error); return; } function getDirEntry(name, callback) { name = Path.join(pathname, name); fs.stat(name, function(error, stats) { if(error) { callback(error); return; } var entry = { path: Path.basename(name), links: stats.nlinks, size: stats.size, modified: stats.mtime, type: stats.type }; if(options.recursive && stats.type === 'DIRECTORY') { list(Path.join(pathname, entry.path), function(error, items) { if(error) { callback(error); return; } entry.contents = items; result.push(entry); callback(); }); } else { result.push(entry); callback(); } }); } async.eachSeries(entries, getDirEntry, function(error) { callback(error, result); }); }); } list(dir, callback); }; /** * Removes the file or directory at `path`. If `path` is a file * it will be removed. If `path` is a directory, it will be * removed if it is empty, otherwise the callback will receive * an error. In order to remove non-empty directories, use the * `recursive=true` option. */ Shell.prototype.rm = function(path, options, callback) { var sh = this; var fs = sh.fs; if(typeof options === 'function') { callback = options; options = {}; } options = options || {}; callback = callback || function(){}; if(!path) { callback(new Errors.EINVAL('Missing path argument')); return; } function remove(pathname, callback) { pathname = Path.resolve(sh.pwd(), pathname); fs.stat(pathname, function(error, stats) { if(error) { callback(error); return; } // If this is a file, delete it and we're done if(stats.type === 'FILE') { fs.unlink(pathname, callback); return; } // If it's a dir, check if it's empty fs.readdir(pathname, function(error, entries) { if(error) { callback(error); return; } // If dir is empty, delete it and we're done if(entries.length === 0) { fs.rmdir(pathname, callback); return; } // If not, see if we're allowed to delete recursively if(!options.recursive) { callback(new Errors.ENOTEMPTY(null, pathname)); return; } // Remove each dir entry recursively, then delete the dir. entries = entries.map(function(filename) { // Root dir entries absolutely return Path.join(pathname, filename); }); async.eachSeries(entries, remove, function(error) { if(error) { callback(error); return; } fs.rmdir(pathname, callback); }); }); }); } remove(path, callback); }; /** * Gets the path to the temporary directory, creating it if not * present. The directory used is the one specified in * env.TMP. The callback receives (error, tempDirName). */ Shell.prototype.tempDir = function(callback) { var sh = this; var fs = sh.fs; var tmp = sh.env.get('TMP'); callback = callback || function(){}; // Try and create it, and it will either work or fail // but either way it's now there. fs.mkdir(tmp, function(err) { callback(null, tmp); }); }; /** * Recursively creates the directory at `path`. If the parent * of `path` does not exist, it will be created. * Based off EnsureDir by Sam X. Xu * https://www.npmjs.org/package/ensureDir * MIT License */ Shell.prototype.mkdirp = function(path, callback) { var sh = this; var fs = sh.fs; callback = callback || function(){}; if(!path) { callback(new Errors.EINVAL('Missing path argument')); return; } else if (path === '/') { callback(); return; } function _mkdirp(path, callback) { fs.stat(path, function (err, stat) { if(stat) { if(stat.isDirectory()) { callback(); return; } else if (stat.isFile()) { callback(new Errors.ENOTDIR(null, path)); return; } } else if (err && err.code !== 'ENOENT') { callback(err); return; } else { var parent = Path.dirname(path); if(parent === '/') { fs.mkdir(path, function (err) { if (err && err.code != 'EEXIST') { callback(err); return; } callback(); return; }); } else { _mkdirp(parent, function (err) { if (err) return callback(err); fs.mkdir(path, function (err) { if (err && err.code != 'EEXIST') { callback(err); return; } callback(); return; }); }); } } }); } _mkdirp(path, callback); }; /** * Recursively walk a directory tree, reporting back all paths * that were found along the way. The `path` must be a dir. * Valid options include a `regex` for pattern matching paths * and an `exec` function of the form `function(path, next)` where * `path` is the current path that was found (dir paths have an '/' * appended) and `next` is a callback to call when done processing * the current path, passing any error object back as the first argument. * `find` returns a flat array of absolute paths for all matching/found * paths as the final argument to the callback. */ Shell.prototype.find = function(path, options, callback) { var sh = this; var fs = sh.fs; if(typeof options === 'function') { callback = options; options = {}; } options = options || {}; callback = callback || function(){}; var exec = options.exec || function(path, next) { next(); }; var found = []; if(!path) { callback(new Errors.EINVAL('Missing path argument')); return; } function processPath(path, callback) { exec(path, function(err) { if(err) { callback(err); return; } found.push(path); callback(); }); } function maybeProcessPath(path, callback) { // Test the path against the user's regex, name, path primaries (if any) // and remove any trailing slashes added previously. var rawPath = Path.removeTrailing(path); // Check entire path against provided regex, if any if(options.regex && !options.regex.test(rawPath)) { callback(); return; } // Check basename for matches against name primary, if any if(options.name && !minimatch(Path.basename(rawPath), options.name)) { callback(); return; } // Check dirname for matches against path primary, if any if(options.path && !minimatch(Path.dirname(rawPath), options.path)) { callback(); return; } processPath(path, callback); } function walk(path, callback) { path = Path.resolve(sh.pwd(), path); // The path is either a file or dir, and instead of doing // a stat() to determine it first, we just try to readdir() // and it will either work or not, and we handle the non-dir error. fs.readdir(path, function(err, entries) { if(err) { if(err.code === 'ENOTDIR' /* file case, ignore error */) { maybeProcessPath(path, callback); } else { callback(err); } return; } // Path is really a dir, add a trailing / and report it found maybeProcessPath(Path.addTrailing(path), function(err) { if(err) { callback(err); return; } entries = entries.map(function(entry) { return Path.join(path, entry); }); async.eachSeries(entries, walk, function(err) { callback(err, found); }); }); }); } // Make sure we are starting with a dir path fs.stat(path, function(err, stats) { if(err) { callback(err); return; } if(!stats.isDirectory()) { callback(new Errors.ENOTDIR(null, path)); return; } walk(path, callback); }); }; module.exports = Shell; },{"../../lib/async.js":1,"../encoding.js":17,"../errors.js":18,"../path.js":25,"./environment.js":31,"minimatch":11}],33:[function(_dereq_,module,exports){ var Constants = _dereq_('./constants.js'); function Stats(fileNode, devName) { this.node = fileNode.id; this.dev = devName; this.size = fileNode.size; this.nlinks = fileNode.nlinks; this.atime = fileNode.atime; this.mtime = fileNode.mtime; this.ctime = fileNode.ctime; this.type = fileNode.mode; } Stats.prototype.isFile = function() { return this.type === Constants.MODE_FILE; }; Stats.prototype.isDirectory = function() { return this.type === Constants.MODE_DIRECTORY; }; Stats.prototype.isSymbolicLink = function() { return this.type === Constants.MODE_SYMBOLIC_LINK; }; // These will always be false in Filer. Stats.prototype.isSocket = Stats.prototype.isFIFO = Stats.prototype.isCharacterDevice = Stats.prototype.isBlockDevice = function() { return false; }; module.exports = Stats; },{"./constants.js":15}],34:[function(_dereq_,module,exports){ var Constants = _dereq_('./constants.js'); function SuperNode(options) { var now = Date.now(); this.id = Constants.SUPER_NODE_ID; this.mode = Constants.MODE_META; this.atime = options.atime || now; this.ctime = options.ctime || now; this.mtime = options.mtime || now; // root node id (randomly generated) this.rnode = options.rnode; } SuperNode.create = function(options, callback) { options.guid(function(err, rnode) { if(err) { callback(err); return; } options.rnode = options.rnode || rnode; callback(null, new SuperNode(options)); }); }; module.exports = SuperNode; },{"./constants.js":15}]},{},[22]) (22) });