define(function(require, module, exports) {
"use strict";
    
var SUPPORT_FOLDER_UPLOAD = (function() {
    var input = document.createElement("input");
    return "webkitdirectory" in input || "directory" in input;
})();

function Batch(files, entries) {
    this.files = files;
    this.entries = entries;
}

Batch.prototype.hasDirectories = function() {
    return this.files.some(function(file) {
        return !!file.isDirectory; 
    });
};

/**
 * remove all files within the given root folder of with the given root file name
 */
Batch.prototype.removeRoot = function(root) {
    this.files = this.files.filter(function(file) {
        return file.fullPath.split("/")[1] !== root;
    });
};

Batch.prototype.subTree = function(root) {
    return this.files.filter(function(file) {
        return file.fullPath.split("/")[1] === root;
    });
};

Batch.prototype.ignoreFiles = function(ignoredFilesMap) {
    this.files = this.files.filter(function(file) {
        return !ignoredFilesMap[file.name];
    });
};

Batch.prototype.getSizes = function() {
    var max = 0;
    var sum = this.files.reduce(function(sum, file) {
        if (file.size > max)
            max = file.size;
        return sum + file.size;
    }, 0);
    
    return {
        max: max,
        sum: sum,
        count: this.files.length
    };
};

Batch.prototype.getRoots = function() {
    return Object.keys(this.files.reduce(function(roots, file) {
        var root = file.fullPath.split("/")[1];
        if (root)
            roots[root] = 1;
        return roots;
    }, {}));
};

Batch.prototype._detectDirectories = function(callback) {
    forEach(this.files, function(file, next) {
        if (typeof file.size !== "number") {
            file.isDirectory = true;
            return next();
        }
        if (file.size > 17000) {
            file.isFile = true;
            return next();
        }
        try {
            var reader = new FileReader();
            reader.readAsBinaryString(file);
            reader.onloadend = function(e) {
                var error = reader.error;
                var hadError = error && (
                    error.name == "SecurityError" || // Firefox
                    error.name == "NotReadableError" || // Firefox
                    error.code == 4 || // Safari 
                    error.code == 1); // Chrome 
                    
                console.log(e, hadError, reader.error, file.size);
                
                if (hadError)
                    file.isDirectory = true;
                else
                    file.isFile = true;
                
                next();
            };
        } catch (e) {
            file.isDirectory = true;
            return next();
        }
    }, callback);
};

Batch.fromInput = function(inputEl, callback) {
    if (!inputEl.files)
        return new Batch([]);
        
    var files = [].slice.call(inputEl.files, 0);
    files.forEach(function(file) {
        var relativePath = file.relativePath || file.webkitRelativePath;
        file.fullPath = "/" + (relativePath ? relativePath : file.name);
    });
    
    var fromFolderUpload = 
        SUPPORT_FOLDER_UPLOAD && 
        inputEl.getAttribute && 
        (typeof inputEl.getAttribute("directory") === "string" || typeof inputEl.getAttribute("webkitdirectory") === "string");
    
    // folder uploads handle directories differently
    if (fromFolderUpload) {
        files = files.filter(function(file) {
            file.isFile = true;
            return file.name !== ".";
        });                
        return callback(null, new Batch(files));
    }
        
    var batch = new Batch(files);
    batch._detectDirectories(function(err) {
        callback(err, batch);
    });        
};

Batch.fromFileApi = function(entries, callback) {
    var files = [];
    var skipped = {};
    
    forEach(entries, function(entry, next) {
        walkFiles(entry, function(entry, next) {
            // ignore directories
            if (entry.isDirectory)
                return next();

            entry.file(function(file) {
                file.fullPath = entry.fullPath;
                file.isFile = true;
                files.push(file);
                next();
            }, function(err) {
                skipped[entry.fullPath] = err;
                next();
            });
        }, function(err) {
            next();
        });
    }, function(err) {
        if (err) return callback(err);
        callback(null, new Batch(files, entries), skipped);
    });
};

Batch.fromDrop = function(dropEvent, callback) {
    var dataTransfer = dropEvent.dataTransfer;
    if (!dataTransfer)
        return callback(null, new Batch([]));
    
    if (!dataTransfer.items)
        return Batch.fromInput(dataTransfer, callback);
        
    if (!dataTransfer.items || dataTransfer.items.length === 0)
        return callback(null, new Batch([]));
    
    var first = dataTransfer.items[0];
    var getAsEntry = first.getAsEntry || first.webkitGetAsEntry;
        
    var entries = [].map.call(dataTransfer.items, function(item) {
        return getAsEntry.call(item);
    });
    
    Batch.fromFileApi(entries, callback);
};

function walkFiles(entry, onEntry, callback) {
    if (!entry) {
        return callback();
    }
    if (entry.isFile) {
        onEntry(entry, callback);
    } 
    else if (entry.isDirectory) {
        onEntry(entry, function(err) {
            if (err) return callback(err);
            
            entry.createReader().readEntries(function(entries) {
                forEach(entries, function(entry, next) {
                    walkFiles(entry, onEntry, next);
                }, callback);
            }, callback);
        });
    }
}

function forEach(list, onEntry, callback) {
    (function loop(i) {
        if (i >= list.length)
            return callback();
            
        onEntry(list[i], function(err) {
            if (err) return callback(err);
            
            loop(i+1);
        });
    })(0);
}

return {
    SUPPORT_FOLDER_UPLOAD: SUPPORT_FOLDER_UPLOAD,
    fromFileApi: Batch.fromFileApi,
    fromDrop: Batch.fromDrop,
    fromInput: Batch.fromInput
};

});
@@ -5507,24 +5507,37 @@
 %0A           
+ var reader =
  entry.creat
@@ -5549,40 +5549,131 @@
 er()
-.readEntries(function(entries) %7B
+;%0A            function handleEntries(entries) %7B%0A                if (!entries.length)%0A                    return callback();
 %0A   
@@ -5802,42 +5802,245 @@
  %7D, 
-callback);%0A            %7D, callback
+readMore);%0A            %7D%0A            function readMore() %7B%0A                // Keep calling readEntries() until no more results are returned.%0A                reader.readEntries(handleEntries, callback);%0A            %7D%0A            readMore(
 );%0A 

fix zendesk issue: uploader misses files on large directories