(function () {

/* Imports */
var Meteor = Package.meteor.Meteor;
var check = Package.check.check;
var Match = Package.check.Match;
var CollectionHooks = Package['matb33:collection-hooks'].CollectionHooks;
var MongoInternals = Package.mongo.MongoInternals;
var Mongo = Package.mongo.Mongo;
var _ = Package.underscore._;
var WebApp = Package.webapp.WebApp;
var main = Package.webapp.main;
var WebAppInternals = Package.webapp.WebAppInternals;

/* Package-scope variables */
var UploadFS, domain, fs, Future, http, https, mkdirp, stream, zlib;

(function(){

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                     //
// packages/jalik_ufs/ufs.js                                                                                           //
//                                                                                                                     //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                                       //
var stores = {};                                                                                                       // 1
                                                                                                                       // 2
UploadFS = {                                                                                                           // 3
    /**                                                                                                                // 4
     * Contains all stores                                                                                             // 5
     */                                                                                                                // 6
    store: {},                                                                                                         // 7
    /**                                                                                                                // 8
     * Returns the temporary file path                                                                                 // 9
     * @param fileId                                                                                                   // 10
     * @return {string}                                                                                                // 11
     */                                                                                                                // 12
    getTempFilePath: function (fileId) {                                                                               // 13
        return UploadFS.config.tmpDir + '/' + fileId;                                                                  // 14
    },                                                                                                                 // 15
    /**                                                                                                                // 16
     * Returns the store by its name                                                                                   // 17
     * @param name                                                                                                     // 18
     * @return {UploadFS.Store}                                                                                        // 19
     */                                                                                                                // 20
    getStore: function (name) {                                                                                        // 21
        return stores[name];                                                                                           // 22
    },                                                                                                                 // 23
    /**                                                                                                                // 24
     * Returns all stores                                                                                              // 25
     * @return {object}                                                                                                // 26
     */                                                                                                                // 27
    getStores: function () {                                                                                           // 28
        return stores;                                                                                                 // 29
    },                                                                                                                 // 30
    /**                                                                                                                // 31
     * Imports a file from a URL                                                                                       // 32
     * @param url                                                                                                      // 33
     * @param file                                                                                                     // 34
     * @param store                                                                                                    // 35
     * @param callback                                                                                                 // 36
     */                                                                                                                // 37
    importFromURL: function (url, file, store, callback) {                                                             // 38
        Meteor.call('ufsImportURL', url, file, store && store.getName(), callback);                                    // 39
    }                                                                                                                  // 40
};                                                                                                                     // 41
                                                                                                                       // 42
if (Meteor.isServer) {                                                                                                 // 43
    /**                                                                                                                // 44
     * Generates a random token using a pattern (xy)                                                                   // 45
     * @param pattern                                                                                                  // 46
     * @return {string}                                                                                                // 47
     */                                                                                                                // 48
    UploadFS.generateToken = function (pattern) {                                                                      // 49
        return (pattern || 'xyxyxyxyxy').replace(/[xy]/g, function (c) {                                               // 50
            var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);                                        // 51
            var s = v.toString(16);                                                                                    // 52
            return Math.round(Math.random()) ? s.toUpperCase() : s;                                                    // 53
        });                                                                                                            // 54
    };                                                                                                                 // 55
}                                                                                                                      // 56
                                                                                                                       // 57
if (Meteor.isClient) {                                                                                                 // 58
    /**                                                                                                                // 59
     * Returns file and data as ArrayBuffer for each files in the event                                                // 60
     * @param event                                                                                                    // 61
     * @param callback                                                                                                 // 62
     */                                                                                                                // 63
    UploadFS.readAsArrayBuffer = function (event, callback) {                                                          // 64
        if (typeof callback !== 'function') {                                                                          // 65
            throw new TypeError('callback is not a function');                                                         // 66
        }                                                                                                              // 67
                                                                                                                       // 68
        var files = event.target.files;                                                                                // 69
                                                                                                                       // 70
        for (var i = 0; i < files.length; i += 1) {                                                                    // 71
            var file = files[i];                                                                                       // 72
                                                                                                                       // 73
            (function (file) {                                                                                         // 74
                var reader = new FileReader();                                                                         // 75
                reader.onload = function (ev) {                                                                        // 76
                    callback.call(UploadFS, ev.target.result, file);                                                   // 77
                };                                                                                                     // 78
                reader.readAsArrayBuffer(file);                                                                        // 79
            })(file);                                                                                                  // 80
        }                                                                                                              // 81
    };                                                                                                                 // 82
                                                                                                                       // 83
    /**                                                                                                                // 84
     * Opens the browser's file selection dialog                                                                       // 85
     * @param callback                                                                                                 // 86
     */                                                                                                                // 87
    UploadFS.selectFiles = function (callback) {                                                                       // 88
        var img = document.createElement('input');                                                                     // 89
        img.type = 'file';                                                                                             // 90
        img.onchange = callback;                                                                                       // 91
        img.click();                                                                                                   // 92
    }                                                                                                                  // 93
}                                                                                                                      // 94
                                                                                                                       // 95
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}).call(this);






(function(){

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                     //
// packages/jalik_ufs/ufs-config.js                                                                                    //
//                                                                                                                     //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                                       //
/**                                                                                                                    // 1
 * UploadFS configuration                                                                                              // 2
 * @param options                                                                                                      // 3
 * @constructor                                                                                                        // 4
 */                                                                                                                    // 5
UploadFS.Config = function (options) {                                                                                 // 6
    // Set default options                                                                                             // 7
    options = _.extend({                                                                                               // 8
        https: false,                                                                                                  // 9
        simulateReadDelay: 0,                                                                                          // 10
        simulateUploadSpeed: 0,                                                                                        // 11
        simulateWriteDelay: 0,                                                                                         // 12
        storesPath: 'ufs',                                                                                             // 13
        tmpDir: '/tmp/ufs'                                                                                             // 14
    }, options);                                                                                                       // 15
                                                                                                                       // 16
    // Check options                                                                                                   // 17
    if (typeof options.https !== 'boolean') {                                                                          // 18
        throw new TypeError('https is not a function');                                                                // 19
    }                                                                                                                  // 20
    if (typeof options.simulateReadDelay !== 'number') {                                                               // 21
        throw new Meteor.Error('simulateReadDelay is not a number');                                                   // 22
    }                                                                                                                  // 23
    if (typeof options.simulateUploadSpeed !== 'number') {                                                             // 24
        throw new Meteor.Error('simulateUploadSpeed is not a number');                                                 // 25
    }                                                                                                                  // 26
    if (typeof options.simulateWriteDelay !== 'number') {                                                              // 27
        throw new Meteor.Error('simulateWriteDelay is not a number');                                                  // 28
    }                                                                                                                  // 29
    if (typeof options.storesPath !== 'string') {                                                                      // 30
        throw new Meteor.Error('storesPath is not a string');                                                          // 31
    }                                                                                                                  // 32
    if (typeof options.tmpDir !== 'string') {                                                                          // 33
        throw new Meteor.Error('tmpDir is not a string');                                                              // 34
    }                                                                                                                  // 35
                                                                                                                       // 36
    // Public attributes                                                                                               // 37
    this.https = options.https;                                                                                        // 38
    this.simulateReadDelay = parseInt(options.simulateReadDelay);                                                      // 39
    this.simulateUploadSpeed = parseInt(options.simulateUploadSpeed);                                                  // 40
    this.simulateWriteDelay = parseInt(options.simulateWriteDelay);                                                    // 41
    this.storesPath = options.storesPath;                                                                              // 42
    this.tmpDir = options.tmpDir;                                                                                      // 43
};                                                                                                                     // 44
                                                                                                                       // 45
/**                                                                                                                    // 46
 * Simulation read delay in milliseconds                                                                               // 47
 * @type {number}                                                                                                      // 48
 */                                                                                                                    // 49
UploadFS.Config.prototype.simulateReadDelay = 0;                                                                       // 50
                                                                                                                       // 51
/**                                                                                                                    // 52
 * Simulation upload speed in milliseconds                                                                             // 53
 * @type {number}                                                                                                      // 54
 */                                                                                                                    // 55
UploadFS.Config.prototype.simulateUploadSpeed = 0;                                                                     // 56
                                                                                                                       // 57
/**                                                                                                                    // 58
 * Simulation write delay in milliseconds                                                                              // 59
 * @type {number}                                                                                                      // 60
 */                                                                                                                    // 61
UploadFS.Config.prototype.simulateWriteDelay = 0;                                                                      // 62
                                                                                                                       // 63
/**                                                                                                                    // 64
 * URL path to stores                                                                                                  // 65
 * @type {string}                                                                                                      // 66
 */                                                                                                                    // 67
UploadFS.Config.prototype.storesPath = null;                                                                           // 68
                                                                                                                       // 69
/**                                                                                                                    // 70
 * Local temporary directory for uploading files                                                                       // 71
 * @type {string}                                                                                                      // 72
 */                                                                                                                    // 73
UploadFS.Config.prototype.tmpDir = null;                                                                               // 74
                                                                                                                       // 75
/**                                                                                                                    // 76
 * Global configuration                                                                                                // 77
 * @type {UploadFS.Config}                                                                                             // 78
 */                                                                                                                    // 79
UploadFS.config = new UploadFS.Config();                                                                               // 80
                                                                                                                       // 81
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}).call(this);






(function(){

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                     //
// packages/jalik_ufs/ufs-filter.js                                                                                    //
//                                                                                                                     //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                                       //
/**                                                                                                                    // 1
 * File filter                                                                                                         // 2
 * @param options                                                                                                      // 3
 * @constructor                                                                                                        // 4
 */                                                                                                                    // 5
UploadFS.Filter = function (options) {                                                                                 // 6
    var self = this;                                                                                                   // 7
                                                                                                                       // 8
    // Set default options                                                                                             // 9
    options = _.extend({                                                                                               // 10
        contentTypes: null,                                                                                            // 11
        extensions: null,                                                                                              // 12
        minSize: 1,                                                                                                    // 13
        maxSize: 0,                                                                                                    // 14
        onCheck: null                                                                                                  // 15
    }, options);                                                                                                       // 16
                                                                                                                       // 17
    // Check options                                                                                                   // 18
    if (options.contentTypes && !(options.contentTypes instanceof Array)) {                                            // 19
        throw new TypeError('contentTypes is not an Array');                                                           // 20
    }                                                                                                                  // 21
    if (options.extensions && !(options.extensions instanceof Array)) {                                                // 22
        throw new TypeError('extensions is not an Array');                                                             // 23
    }                                                                                                                  // 24
    if (typeof options.minSize !== 'number') {                                                                         // 25
        throw new TypeError('minSize is not a number');                                                                // 26
    }                                                                                                                  // 27
    if (typeof options.maxSize !== 'number') {                                                                         // 28
        throw new TypeError('maxSize is not a number');                                                                // 29
    }                                                                                                                  // 30
    if (options.onCheck && typeof options.onCheck !== 'function') {                                                    // 31
        throw new TypeError('onCheck is not a function');                                                              // 32
    }                                                                                                                  // 33
                                                                                                                       // 34
    // Private attributes                                                                                              // 35
    var contentTypes = options.contentTypes;                                                                           // 36
    var extensions = options.extensions;                                                                               // 37
    var onCheck = options.onCheck;                                                                                     // 38
    var maxSize = parseInt(options.maxSize);                                                                           // 39
    var minSize = parseInt(options.minSize);                                                                           // 40
                                                                                                                       // 41
    /**                                                                                                                // 42
     * Checks the file                                                                                                 // 43
     * @param file                                                                                                     // 44
     */                                                                                                                // 45
    self.check = function (file) {                                                                                     // 46
        // Check size                                                                                                  // 47
        if (file.size <= 0 || file.size < self.getMinSize()) {                                                         // 48
            throw new Meteor.Error('file-too-small', 'File is too small (min =' + self.getMinSize() + ')');            // 49
        }                                                                                                              // 50
        if (self.getMaxSize() > 0 && file.size > self.getMaxSize()) {                                                  // 51
            throw new Meteor.Error('file-too-large', 'File is too large (max = ' + self.getMaxSize() + ')');           // 52
        }                                                                                                              // 53
        // Check extension                                                                                             // 54
        if (self.getExtensions() && !_.contains(self.getExtensions(), file.extension)) {                               // 55
            throw new Meteor.Error('invalid-file-extension', 'File extension is not accepted');                        // 56
        }                                                                                                              // 57
        // Check content type                                                                                          // 58
        if (self.getContentTypes() && !checkContentType(file.type, self.getContentTypes())) {                          // 59
            throw new Meteor.Error('invalid-file-type', 'File type is not accepted');                                  // 60
        }                                                                                                              // 61
        // Apply custom check                                                                                          // 62
        if (typeof onCheck === 'function' && !onCheck.call(self, file)) {                                              // 63
            throw new Meteor.Error('invalid-file', 'File does not match filter');                                      // 64
        }                                                                                                              // 65
    };                                                                                                                 // 66
                                                                                                                       // 67
    /**                                                                                                                // 68
     * Returns the allowed content types                                                                               // 69
     * @return {Array}                                                                                                 // 70
     */                                                                                                                // 71
    self.getContentTypes = function () {                                                                               // 72
        return contentTypes;                                                                                           // 73
    };                                                                                                                 // 74
                                                                                                                       // 75
    /**                                                                                                                // 76
     * Returns the allowed extensions                                                                                  // 77
     * @return {Array}                                                                                                 // 78
     */                                                                                                                // 79
    self.getExtensions = function () {                                                                                 // 80
        return extensions;                                                                                             // 81
    };                                                                                                                 // 82
                                                                                                                       // 83
    /**                                                                                                                // 84
     * Returns the maximum file size                                                                                   // 85
     * @return {Number}                                                                                                // 86
     */                                                                                                                // 87
    self.getMaxSize = function () {                                                                                    // 88
        return maxSize;                                                                                                // 89
    };                                                                                                                 // 90
                                                                                                                       // 91
    /**                                                                                                                // 92
     * Returns the minimum file size                                                                                   // 93
     * @return {Number}                                                                                                // 94
     */                                                                                                                // 95
    self.getMinSize = function () {                                                                                    // 96
        return minSize;                                                                                                // 97
    };                                                                                                                 // 98
                                                                                                                       // 99
    /**                                                                                                                // 100
     * Checks if the file matches filter                                                                               // 101
     * @param file                                                                                                     // 102
     * @return {boolean}                                                                                               // 103
     */                                                                                                                // 104
    self.isValid = function (file) {                                                                                   // 105
        return !(                                                                                                      // 106
            file.size <= 0 || file.size < self.getMinSize()                                                            // 107
            || self.getMaxSize() > 0 && file.size > self.getMaxSize()                                                  // 108
            || self.getExtensions() && !_.contains(self.getExtensions(), file.extension)                               // 109
            || self.getContentTypes() && !checkContentType(file.type, self.getContentTypes())                          // 110
            || (typeof onCheck === 'function' && !onCheck.call(self, file))                                            // 111
        );                                                                                                             // 112
    };                                                                                                                 // 113
};                                                                                                                     // 114
                                                                                                                       // 115
function checkContentType(type, list) {                                                                                // 116
    if (_.contains(list, type)) {                                                                                      // 117
        return true;                                                                                                   // 118
    } else {                                                                                                           // 119
        var wildCardGlob = '/*';                                                                                       // 120
        var wildcards = _.filter(list, function (item) {                                                               // 121
            return item.indexOf(wildCardGlob) > 0;                                                                     // 122
        });                                                                                                            // 123
                                                                                                                       // 124
        if (_.contains(wildcards, type.replace(/(\/.*)$/, wildCardGlob))) {                                            // 125
            return true;                                                                                               // 126
        }                                                                                                              // 127
    }                                                                                                                  // 128
    return false;                                                                                                      // 129
}                                                                                                                      // 130
                                                                                                                       // 131
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}).call(this);






(function(){

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                     //
// packages/jalik_ufs/ufs-store.js                                                                                     //
//                                                                                                                     //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                                       //
/**                                                                                                                    // 1
 * File store                                                                                                          // 2
 * @param options                                                                                                      // 3
 * @constructor                                                                                                        // 4
 */                                                                                                                    // 5
UploadFS.Store = function (options) {                                                                                  // 6
    var self = this;                                                                                                   // 7
                                                                                                                       // 8
    // Set default options                                                                                             // 9
    options = _.extend({                                                                                               // 10
        collection: null,                                                                                              // 11
        filter: null,                                                                                                  // 12
        name: null,                                                                                                    // 13
        onCopyError: null,                                                                                             // 14
        onFinishUpload: null,                                                                                          // 15
        onRead: null,                                                                                                  // 16
        onReadError: null,                                                                                             // 17
        onWriteError: null,                                                                                            // 18
        transformRead: null,                                                                                           // 19
        transformWrite: null                                                                                           // 20
    }, options);                                                                                                       // 21
                                                                                                                       // 22
    // Check instance                                                                                                  // 23
    if (!(self instanceof UploadFS.Store)) {                                                                           // 24
        throw new Error('UploadFS.Store is not an instance');                                                          // 25
    }                                                                                                                  // 26
                                                                                                                       // 27
    // Check options                                                                                                   // 28
    if (!(options.collection instanceof Mongo.Collection)) {                                                           // 29
        throw new TypeError('collection is not a Mongo.Collection');                                                   // 30
    }                                                                                                                  // 31
    if (options.filter && !(options.filter instanceof UploadFS.Filter)) {                                              // 32
        throw new TypeError('filter is not an UploadFS.Filter');                                                       // 33
    }                                                                                                                  // 34
    if (typeof options.name !== 'string') {                                                                            // 35
        throw new TypeError('name is not a string');                                                                   // 36
    }                                                                                                                  // 37
    if (UploadFS.getStore(options.name)) {                                                                             // 38
        throw new TypeError('name already exists');                                                                    // 39
    }                                                                                                                  // 40
    if (options.onCopyError && typeof options.onCopyError !== 'function') {                                            // 41
        throw new TypeError('onCopyError is not a function');                                                          // 42
    }                                                                                                                  // 43
    if (options.onFinishUpload && typeof options.onFinishUpload !== 'function') {                                      // 44
        throw new TypeError('onFinishUpload is not a function');                                                       // 45
    }                                                                                                                  // 46
    if (options.onRead && typeof options.onRead !== 'function') {                                                      // 47
        throw new TypeError('onRead is not a function');                                                               // 48
    }                                                                                                                  // 49
    if (options.onReadError && typeof options.onReadError !== 'function') {                                            // 50
        throw new TypeError('onReadError is not a function');                                                          // 51
    }                                                                                                                  // 52
    if (options.onWriteError && typeof options.onWriteError !== 'function') {                                          // 53
        throw new TypeError('onWriteError is not a function');                                                         // 54
    }                                                                                                                  // 55
    if (options.transformRead && typeof options.transformRead !== 'function') {                                        // 56
        throw new TypeError('transformRead is not a function');                                                        // 57
    }                                                                                                                  // 58
    if (options.transformWrite && typeof options.transformWrite !== 'function') {                                      // 59
        throw new TypeError('transformWrite is not a function');                                                       // 60
    }                                                                                                                  // 61
                                                                                                                       // 62
    // Public attributes                                                                                               // 63
    self.onCopyError = options.onCopyError || self.onCopyError;                                                        // 64
    self.onFinishUpload = options.onFinishUpload || self.onFinishUpload;                                               // 65
    self.onRead = options.onRead || self.onRead;                                                                       // 66
    self.onReadError = options.onReadError || self.onReadError;                                                        // 67
    self.onWriteError = options.onWriteError || self.onWriteError;                                                     // 68
                                                                                                                       // 69
    // Private attributes                                                                                              // 70
    var collection = options.collection;                                                                               // 71
    var copyTo = options.copyTo;                                                                                       // 72
    var filter = options.filter;                                                                                       // 73
    var name = options.name;                                                                                           // 74
    var transformRead = options.transformRead;                                                                         // 75
    var transformWrite = options.transformWrite;                                                                       // 76
                                                                                                                       // 77
    // Add the store to the list                                                                                       // 78
    UploadFS.getStores()[name] = self;                                                                                 // 79
                                                                                                                       // 80
    /**                                                                                                                // 81
     * Creates the file in the collection                                                                              // 82
     * @param file                                                                                                     // 83
     * @return {string}                                                                                                // 84
     */                                                                                                                // 85
    self.create = function (file) {                                                                                    // 86
        check(file, Object);                                                                                           // 87
        file.store = name;                                                                                             // 88
        return self.getCollection().insert(file);                                                                      // 89
    };                                                                                                                 // 90
                                                                                                                       // 91
    /**                                                                                                                // 92
     * Returns the collection                                                                                          // 93
     * @return {Mongo.Collection}                                                                                      // 94
     */                                                                                                                // 95
    self.getCollection = function () {                                                                                 // 96
        return collection;                                                                                             // 97
    };                                                                                                                 // 98
                                                                                                                       // 99
    /**                                                                                                                // 100
     * Returns the file filter                                                                                         // 101
     * @return {UploadFS.Filter}                                                                                       // 102
     */                                                                                                                // 103
    self.getFilter = function () {                                                                                     // 104
        return filter;                                                                                                 // 105
    };                                                                                                                 // 106
                                                                                                                       // 107
    /**                                                                                                                // 108
     * Returns the store name                                                                                          // 109
     * @return {string}                                                                                                // 110
     */                                                                                                                // 111
    self.getName = function () {                                                                                       // 112
        return name;                                                                                                   // 113
    };                                                                                                                 // 114
                                                                                                                       // 115
                                                                                                                       // 116
    if (Meteor.isServer) {                                                                                             // 117
                                                                                                                       // 118
        /**                                                                                                            // 119
         * Copies the file to a store                                                                                  // 120
         * @param fileId                                                                                               // 121
         * @param store                                                                                                // 122
         * @param callback                                                                                             // 123
         */                                                                                                            // 124
        self.copy = function (fileId, store, callback) {                                                               // 125
            check(fileId, String);                                                                                     // 126
                                                                                                                       // 127
            if (!(store instanceof UploadFS.Store)) {                                                                  // 128
                throw new TypeError('store is not an UploadFS.store.Store');                                           // 129
            }                                                                                                          // 130
                                                                                                                       // 131
            // Get original file                                                                                       // 132
            var file = self.getCollection().findOne(fileId);                                                           // 133
            if (!file) {                                                                                               // 134
                throw new Meteor.Error(404, 'File not found');                                                         // 135
            }                                                                                                          // 136
                                                                                                                       // 137
            // Prepare copy                                                                                            // 138
            var copy = _.omit(file, '_id', 'url');                                                                     // 139
            copy.originalStore = self.getName();                                                                       // 140
            copy.originalId = fileId;                                                                                  // 141
                                                                                                                       // 142
            // Create the copy                                                                                         // 143
            var copyId = store.create(copy);                                                                           // 144
                                                                                                                       // 145
            // Get original stream                                                                                     // 146
            var rs = self.getReadStream(fileId, file);                                                                 // 147
                                                                                                                       // 148
            // Copy file data                                                                                          // 149
            store.write(rs, copyId, Meteor.bindEnvironment(function (err) {                                            // 150
                if (err) {                                                                                             // 151
                    store.getCollection().remove(copyId);                                                              // 152
                    self.onCopyError.call(self, err, fileId, file);                                                    // 153
                }                                                                                                      // 154
                if (typeof callback === 'function') {                                                                  // 155
                    callback.call(self, err, copyId, copy, store);                                                     // 156
                }                                                                                                      // 157
            }));                                                                                                       // 158
        };                                                                                                             // 159
                                                                                                                       // 160
        /**                                                                                                            // 161
         * Transforms the file on reading                                                                              // 162
         * @param from                                                                                                 // 163
         * @param to                                                                                                   // 164
         * @param fileId                                                                                               // 165
         * @param file                                                                                                 // 166
         * @param request                                                                                              // 167
         * @param headers                                                                                              // 168
         */                                                                                                            // 169
        self.transformRead = function (from, to, fileId, file, request, headers) {                                     // 170
            if (typeof transformRead === 'function') {                                                                 // 171
                transformRead.call(self, from, to, fileId, file, request, headers);                                    // 172
            } else {                                                                                                   // 173
                from.pipe(to);                                                                                         // 174
            }                                                                                                          // 175
        };                                                                                                             // 176
                                                                                                                       // 177
        /**                                                                                                            // 178
         * Transforms the file on writing                                                                              // 179
         * @param from                                                                                                 // 180
         * @param to                                                                                                   // 181
         * @param fileId                                                                                               // 182
         * @param file                                                                                                 // 183
         */                                                                                                            // 184
        self.transformWrite = function (from, to, fileId, file) {                                                      // 185
            if (typeof transformWrite === 'function') {                                                                // 186
                transformWrite.call(self, from, to, fileId, file);                                                     // 187
            } else {                                                                                                   // 188
                from.pipe(to);                                                                                         // 189
            }                                                                                                          // 190
        };                                                                                                             // 191
                                                                                                                       // 192
        /**                                                                                                            // 193
         * Writes the file to the store                                                                                // 194
         * @param rs                                                                                                   // 195
         * @param fileId                                                                                               // 196
         * @param callback                                                                                             // 197
         */                                                                                                            // 198
        self.write = function (rs, fileId, callback) {                                                                 // 199
            var file = self.getCollection().findOne(fileId);                                                           // 200
            var ws = self.getWriteStream(fileId, file);                                                                // 201
                                                                                                                       // 202
            var errorHandler = Meteor.bindEnvironment(function (err) {                                                 // 203
                self.getCollection().remove(fileId);                                                                   // 204
                self.onWriteError.call(self, err, fileId, file);                                                       // 205
                callback.call(self, err);                                                                              // 206
            });                                                                                                        // 207
                                                                                                                       // 208
            ws.on('error', errorHandler);                                                                              // 209
            ws.on('finish', Meteor.bindEnvironment(function () {                                                       // 210
                var size = 0;                                                                                          // 211
                var from = self.getReadStream(fileId, file);                                                           // 212
                                                                                                                       // 213
                from.on('data', function (data) {                                                                      // 214
                    size += data.length;                                                                               // 215
                });                                                                                                    // 216
                from.on('end', Meteor.bindEnvironment(function () {                                                    // 217
                    // Set file attribute                                                                              // 218
                    file.complete = true;                                                                              // 219
                    file.progress = 1;                                                                                 // 220
                    file.size = size;                                                                                  // 221
                    file.token = UploadFS.generateToken();                                                             // 222
                    file.uploading = false;                                                                            // 223
                    file.uploadedAt = new Date();                                                                      // 224
                    file.url = self.getFileURL(fileId);                                                                // 225
                                                                                                                       // 226
                    // Sets the file URL when file transfer is complete,                                               // 227
                    // this way, the image will loads entirely.                                                        // 228
                    self.getCollection().update(fileId, {                                                              // 229
                        $set: {                                                                                        // 230
                            complete: file.complete,                                                                   // 231
                            progress: file.progress,                                                                   // 232
                            size: file.size,                                                                           // 233
                            token: file.token,                                                                         // 234
                            uploading: file.uploading,                                                                 // 235
                            uploadedAt: file.uploadedAt,                                                               // 236
                            url: file.url                                                                              // 237
                        }                                                                                              // 238
                    });                                                                                                // 239
                                                                                                                       // 240
                    // Return file info                                                                                // 241
                    callback.call(self, null, file);                                                                   // 242
                                                                                                                       // 243
                    // Execute callback                                                                                // 244
                    if (typeof self.onFinishUpload == 'function') {                                                    // 245
                        self.onFinishUpload.call(self, file);                                                          // 246
                    }                                                                                                  // 247
                                                                                                                       // 248
                    // Simulate write speed                                                                            // 249
                    if (UploadFS.config.simulateWriteDelay) {                                                          // 250
                        Meteor._sleepForMs(UploadFS.config.simulateWriteDelay);                                        // 251
                    }                                                                                                  // 252
                                                                                                                       // 253
                    // Copy file to other stores                                                                       // 254
                    if (copyTo instanceof Array) {                                                                     // 255
                        for (var i = 0; i < copyTo.length; i += 1) {                                                   // 256
                            var store = copyTo[i];                                                                     // 257
                                                                                                                       // 258
                            if (!store.getFilter() || store.getFilter().isValid(file)) {                               // 259
                                self.copy(fileId, store);                                                              // 260
                            }                                                                                          // 261
                        }                                                                                              // 262
                    }                                                                                                  // 263
                }));                                                                                                   // 264
            }));                                                                                                       // 265
                                                                                                                       // 266
            // Execute transformation                                                                                  // 267
            self.transformWrite(rs, ws, fileId, file);                                                                 // 268
        };                                                                                                             // 269
    }                                                                                                                  // 270
                                                                                                                       // 271
    // Code executed before inserting file                                                                             // 272
    collection.before.insert(function (userId, file) {                                                                 // 273
        if (typeof file.name !== 'string' || !file.name.length) {                                                      // 274
            throw new Meteor.Error(400, "file name not defined");                                                      // 275
        }                                                                                                              // 276
        if (typeof file.store !== 'string' || !file.store.length) {                                                    // 277
            throw new Meteor.Error(400, "file store not defined");                                                     // 278
        }                                                                                                              // 279
        if (typeof file.complete !== 'boolean') {                                                                      // 280
            file.complete = false;                                                                                     // 281
        }                                                                                                              // 282
        if (typeof file.uploading !== 'boolean') {                                                                     // 283
            file.uploading = true;                                                                                     // 284
        }                                                                                                              // 285
        file.extension = file.name && file.name.substr((~-file.name.lastIndexOf('.') >>> 0) + 2).toLowerCase();        // 286
        file.progress = parseFloat(file.progress) || 0;                                                                // 287
        file.size = parseInt(file.size) || 0;                                                                          // 288
        file.userId = file.userId || userId;                                                                           // 289
    });                                                                                                                // 290
                                                                                                                       // 291
    // Code executed after removing file                                                                               // 292
    collection.after.remove(function (userId, file) {                                                                  // 293
        if (Meteor.isServer) {                                                                                         // 294
            if (copyTo instanceof Array) {                                                                             // 295
                for (var i = 0; i < copyTo.length; i += 1) {                                                           // 296
                    // Remove copies in stores                                                                         // 297
                    copyTo[i].getCollection().remove({originalId: file._id});                                          // 298
                }                                                                                                      // 299
            }                                                                                                          // 300
        }                                                                                                              // 301
    });                                                                                                                // 302
                                                                                                                       // 303
    // Code executed before removing file                                                                              // 304
    collection.before.remove(function (userId, file) {                                                                 // 305
        if (Meteor.isServer) {                                                                                         // 306
            // Delete the physical file in the store                                                                   // 307
            self.delete(file._id);                                                                                     // 308
                                                                                                                       // 309
            var tmpFile = UploadFS.getTempFilePath(file._id);                                                          // 310
                                                                                                                       // 311
            // Delete the temp file                                                                                    // 312
            fs.stat(tmpFile, function (err) {                                                                          // 313
                !err && fs.unlink(tmpFile, function (err) {                                                            // 314
                    err && console.error('ufs: cannot delete temp file at ' + tmpFile + ' (' + err.message + ')');     // 315
                });                                                                                                    // 316
            });                                                                                                        // 317
        }                                                                                                              // 318
    });                                                                                                                // 319
                                                                                                                       // 320
    collection.deny({                                                                                                  // 321
        // Test filter on file insertion                                                                               // 322
        insert: function (userId, file) {                                                                              // 323
            if (filter instanceof UploadFS.Filter) {                                                                   // 324
                filter.check(file);                                                                                    // 325
            }                                                                                                          // 326
            return typeof options.insert === 'function'                                                                // 327
                && !options.insert.apply(this, arguments);                                                             // 328
        }                                                                                                              // 329
    });                                                                                                                // 330
};                                                                                                                     // 331
                                                                                                                       // 332
/**                                                                                                                    // 333
 * Returns the file URL                                                                                                // 334
 * @param fileId                                                                                                       // 335
 */                                                                                                                    // 336
UploadFS.Store.prototype.getFileURL = function (fileId) {                                                              // 337
    var file = this.getCollection().findOne(fileId, {                                                                  // 338
        fields: {name: 1}                                                                                              // 339
    });                                                                                                                // 340
    return file && this.getURL() + '/' + fileId + '/' + encodeURIComponent(file.name);                                 // 341
};                                                                                                                     // 342
                                                                                                                       // 343
/**                                                                                                                    // 344
 * Returns the store URL                                                                                               // 345
 */                                                                                                                    // 346
UploadFS.Store.prototype.getURL = function () {                                                                        // 347
    return Meteor.absoluteUrl(UploadFS.config.storesPath + '/' + this.getName(), {                                     // 348
        secure: UploadFS.config.https                                                                                  // 349
    });                                                                                                                // 350
};                                                                                                                     // 351
                                                                                                                       // 352
if (Meteor.isServer) {                                                                                                 // 353
    /**                                                                                                                // 354
     * Deletes a file async                                                                                            // 355
     * @param fileId                                                                                                   // 356
     * @param callback                                                                                                 // 357
     */                                                                                                                // 358
    UploadFS.Store.prototype.delete = function (fileId, callback) {                                                    // 359
        throw new Error('delete is not implemented');                                                                  // 360
    };                                                                                                                 // 361
                                                                                                                       // 362
    /**                                                                                                                // 363
     * Returns the file read stream                                                                                    // 364
     * @param fileId                                                                                                   // 365
     * @param file                                                                                                     // 366
     */                                                                                                                // 367
    UploadFS.Store.prototype.getReadStream = function (fileId, file) {                                                 // 368
        throw new Error('getReadStream is not implemented');                                                           // 369
    };                                                                                                                 // 370
                                                                                                                       // 371
    /**                                                                                                                // 372
     * Returns the file write stream                                                                                   // 373
     * @param fileId                                                                                                   // 374
     * @param file                                                                                                     // 375
     */                                                                                                                // 376
    UploadFS.Store.prototype.getWriteStream = function (fileId, file) {                                                // 377
        throw new Error('getWriteStream is not implemented');                                                          // 378
    };                                                                                                                 // 379
                                                                                                                       // 380
    /**                                                                                                                // 381
     * Callback for copy errors                                                                                        // 382
     * @param err                                                                                                      // 383
     * @param fileId                                                                                                   // 384
     * @param file                                                                                                     // 385
     * @return boolean                                                                                                 // 386
     */                                                                                                                // 387
    UploadFS.Store.prototype.onCopyError = function (err, fileId, file) {                                              // 388
        console.error('ufs: cannot copy file "' + fileId + '" (' + err.message + ')');                                 // 389
    };                                                                                                                 // 390
                                                                                                                       // 391
    /**                                                                                                                // 392
     * Called when a file has been uploaded                                                                            // 393
     * @param file                                                                                                     // 394
     */                                                                                                                // 395
    UploadFS.Store.prototype.onFinishUpload = function (file) {                                                        // 396
    };                                                                                                                 // 397
                                                                                                                       // 398
    /**                                                                                                                // 399
     * Called when a file is read from the store                                                                       // 400
     * @param fileId                                                                                                   // 401
     * @param file                                                                                                     // 402
     * @param request                                                                                                  // 403
     * @param response                                                                                                 // 404
     * @return boolean                                                                                                 // 405
     */                                                                                                                // 406
    UploadFS.Store.prototype.onRead = function (fileId, file, request, response) {                                     // 407
        return true;                                                                                                   // 408
    };                                                                                                                 // 409
                                                                                                                       // 410
    /**                                                                                                                // 411
     * Callback for read errors                                                                                        // 412
     * @param err                                                                                                      // 413
     * @param fileId                                                                                                   // 414
     * @param file                                                                                                     // 415
     * @return boolean                                                                                                 // 416
     */                                                                                                                // 417
    UploadFS.Store.prototype.onReadError = function (err, fileId, file) {                                              // 418
        console.error('ufs: cannot read file "' + fileId + '" (' + err.message + ')');                                 // 419
    };                                                                                                                 // 420
                                                                                                                       // 421
    /**                                                                                                                // 422
     * Callback for write errors                                                                                       // 423
     * @param err                                                                                                      // 424
     * @param fileId                                                                                                   // 425
     * @param file                                                                                                     // 426
     * @return boolean                                                                                                 // 427
     */                                                                                                                // 428
    UploadFS.Store.prototype.onWriteError = function (err, fileId, file) {                                             // 429
        console.error('ufs: cannot write file "' + fileId + '" (' + err.message + ')');                                // 430
    };                                                                                                                 // 431
}                                                                                                                      // 432
                                                                                                                       // 433
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}).call(this);






(function(){

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                     //
// packages/jalik_ufs/ufs-methods.js                                                                                   //
//                                                                                                                     //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                                       //
Meteor.methods({                                                                                                       // 1
                                                                                                                       // 2
    /**                                                                                                                // 3
     * Completes the file transfer                                                                                     // 4
     * @param fileId                                                                                                   // 5
     * @param storeName                                                                                                // 6
     */                                                                                                                // 7
    ufsComplete: function (fileId, storeName) {                                                                        // 8
        check(fileId, String);                                                                                         // 9
        check(storeName, String);                                                                                      // 10
                                                                                                                       // 11
        // Allow other uploads to run concurrently                                                                     // 12
        this.unblock();                                                                                                // 13
                                                                                                                       // 14
        var store = UploadFS.getStore(storeName);                                                                      // 15
        if (!store) {                                                                                                  // 16
            throw new Meteor.Error(404, 'store "' + storeName + '" does not exist');                                   // 17
        }                                                                                                              // 18
        // Check that file exists and is owned by current user                                                         // 19
        if (store.getCollection().find({_id: fileId, userId: this.userId}).count() < 1) {                              // 20
            throw new Meteor.Error(404, 'file "' + fileId + '" does not exist');                                       // 21
        }                                                                                                              // 22
                                                                                                                       // 23
        var fut = new Future();                                                                                        // 24
        var tmpFile = UploadFS.getTempFilePath(fileId);                                                                // 25
                                                                                                                       // 26
        // Get the temp file                                                                                           // 27
        var rs = fs.createReadStream(tmpFile, {                                                                        // 28
            flags: 'r',                                                                                                // 29
            encoding: null,                                                                                            // 30
            autoClose: true                                                                                            // 31
        });                                                                                                            // 32
                                                                                                                       // 33
        rs.on('error', Meteor.bindEnvironment(function () {                                                            // 34
            store.getCollection().remove(fileId);                                                                      // 35
        }));                                                                                                           // 36
                                                                                                                       // 37
        // Save file in the store                                                                                      // 38
        store.write(rs, fileId, Meteor.bindEnvironment(function (err, file) {                                          // 39
            fs.unlink(tmpFile, function (err) {                                                                        // 40
                err && console.error('ufs: cannot delete temp file ' + tmpFile + ' (' + err.message + ')');            // 41
            });                                                                                                        // 42
                                                                                                                       // 43
            if (err) {                                                                                                 // 44
                fut.throw(err);                                                                                        // 45
            } else {                                                                                                   // 46
                fut.return(file);                                                                                      // 47
            }                                                                                                          // 48
        }));                                                                                                           // 49
        return fut.wait();                                                                                             // 50
    },                                                                                                                 // 51
                                                                                                                       // 52
    /**                                                                                                                // 53
     * Imports a file from the URL                                                                                     // 54
     * @param url                                                                                                      // 55
     * @param file                                                                                                     // 56
     * @param storeName                                                                                                // 57
     * @return {*}                                                                                                     // 58
     */                                                                                                                // 59
    ufsImportURL: function (url, file, storeName) {                                                                    // 60
        check(url, String);                                                                                            // 61
        check(file, Object);                                                                                           // 62
        check(storeName, String);                                                                                      // 63
                                                                                                                       // 64
        this.unblock();                                                                                                // 65
                                                                                                                       // 66
        var store = UploadFS.getStore(storeName);                                                                      // 67
        if (!store) {                                                                                                  // 68
            throw new Meteor.Error(404, 'Store "' + storeName + '" does not exist');                                   // 69
        }                                                                                                              // 70
                                                                                                                       // 71
        try {                                                                                                          // 72
            // Extract file info                                                                                       // 73
            if (!file.name) {                                                                                          // 74
                file.name = url.replace(/\?.*$/, '').split('/').pop();                                                 // 75
                file.extension = file.name.split('.').pop();                                                           // 76
                file.type = 'image/' + file.extension;                                                                 // 77
            }                                                                                                          // 78
            // Check if file is valid                                                                                  // 79
            if (store.getFilter() instanceof UploadFS.Filter) {                                                        // 80
                store.getFilter().check(file);                                                                         // 81
            }                                                                                                          // 82
            // Create the file                                                                                         // 83
            var fileId = store.create(file);                                                                           // 84
                                                                                                                       // 85
        } catch (err) {                                                                                                // 86
            throw new Meteor.Error(500, err.message);                                                                  // 87
        }                                                                                                              // 88
                                                                                                                       // 89
        var fut = new Future();                                                                                        // 90
        var proto;                                                                                                     // 91
                                                                                                                       // 92
        // Detect protocol to use                                                                                      // 93
        if (/http:\/\//i.test(url)) {                                                                                  // 94
            proto = http;                                                                                              // 95
        } else if (/https:\/\//i.test(url)) {                                                                          // 96
            proto = https;                                                                                             // 97
        }                                                                                                              // 98
                                                                                                                       // 99
        // Download file                                                                                               // 100
        proto.get(url, Meteor.bindEnvironment(function (res) {                                                         // 101
            // Save the file in the store                                                                              // 102
            store.write(res, fileId, function (err, file) {                                                            // 103
                if (err) {                                                                                             // 104
                    fut.throw(err);                                                                                    // 105
                } else {                                                                                               // 106
                    fut.return(fileId);                                                                                // 107
                }                                                                                                      // 108
            });                                                                                                        // 109
        })).on('error', function (err) {                                                                               // 110
            fut.throw(err);                                                                                            // 111
        });                                                                                                            // 112
        return fut.wait();                                                                                             // 113
    },                                                                                                                 // 114
                                                                                                                       // 115
    /**                                                                                                                // 116
     * Saves a chunk of file                                                                                           // 117
     * @param chunk                                                                                                    // 118
     * @param fileId                                                                                                   // 119
     * @param storeName                                                                                                // 120
     * @param progress                                                                                                 // 121
     * @return {*}                                                                                                     // 122
     */                                                                                                                // 123
    ufsWrite: function (chunk, fileId, storeName, progress) {                                                          // 124
        check(fileId, String);                                                                                         // 125
        check(storeName, String);                                                                                      // 126
        check(progress, Number);                                                                                       // 127
                                                                                                                       // 128
        this.unblock();                                                                                                // 129
                                                                                                                       // 130
        // Check arguments                                                                                             // 131
        if (!(chunk instanceof Uint8Array)) {                                                                          // 132
            throw new Meteor.Error(400, 'chunk is not an Uint8Array');                                                 // 133
        }                                                                                                              // 134
        if (chunk.length <= 0) {                                                                                       // 135
            throw new Meteor.Error(400, 'chunk is empty');                                                             // 136
        }                                                                                                              // 137
                                                                                                                       // 138
        var store = UploadFS.getStore(storeName);                                                                      // 139
        if (!store) {                                                                                                  // 140
            throw new Meteor.Error(404, 'store ' + storeName + ' does not exist');                                     // 141
        }                                                                                                              // 142
                                                                                                                       // 143
        // Check that file exists, is not complete and is owned by current user                                        // 144
        if (store.getCollection().find({_id: fileId, complete: false, userId: this.userId}).count() < 1) {             // 145
            throw new Meteor.Error(404, 'file ' + fileId + ' does not exist');                                         // 146
        }                                                                                                              // 147
                                                                                                                       // 148
        var fut = new Future();                                                                                        // 149
        var tmpFile = UploadFS.getTempFilePath(fileId);                                                                // 150
                                                                                                                       // 151
        // Save the chunk                                                                                              // 152
        fs.appendFile(tmpFile, new Buffer(chunk), Meteor.bindEnvironment(function (err) {                              // 153
            if (err) {                                                                                                 // 154
                console.error('ufs: cannot write chunk of file "' + fileId + '" (' + err.message + ')');               // 155
                fs.unlink(tmpFile, function (err) {                                                                    // 156
                    err && console.error('ufs: cannot delete temp file ' + tmpFile + ' (' + err.message + ')');        // 157
                });                                                                                                    // 158
                fut.throw(err);                                                                                        // 159
            } else {                                                                                                   // 160
                // Update completed state                                                                              // 161
                store.getCollection().update(fileId, {                                                                 // 162
                    $set: {progress: progress}                                                                         // 163
                });                                                                                                    // 164
                fut.return(chunk.length);                                                                              // 165
            }                                                                                                          // 166
        }));                                                                                                           // 167
        return fut.wait();                                                                                             // 168
    }                                                                                                                  // 169
});                                                                                                                    // 170
                                                                                                                       // 171
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}).call(this);






(function(){

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                     //
// packages/jalik_ufs/ufs-server.js                                                                                    //
//                                                                                                                     //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                                                                                                                       //
domain = Npm.require('domain');                                                                                        // 1
fs = Npm.require('fs');                                                                                                // 2
Future = Npm.require('fibers/future');                                                                                 // 3
http = Npm.require('http');                                                                                            // 4
https = Npm.require('https');                                                                                          // 5
mkdirp = Npm.require('mkdirp');                                                                                        // 6
stream = Npm.require('stream');                                                                                        // 7
zlib = Npm.require('zlib');                                                                                            // 8
                                                                                                                       // 9
Meteor.startup(function () {                                                                                           // 10
    var path = UploadFS.config.tmpDir;                                                                                 // 11
    var mode = '0744';                                                                                                 // 12
                                                                                                                       // 13
    fs.stat(path, function (err) {                                                                                     // 14
        if (err) {                                                                                                     // 15
            // Create the temp directory                                                                               // 16
            mkdirp(path, {mode: mode}, function (err) {                                                                // 17
                if (err) {                                                                                             // 18
                    console.error('ufs: cannot create temp directory at ' + path + ' (' + err.message + ')');          // 19
                } else {                                                                                               // 20
                    console.log('ufs: temp directory created at ' + path);                                             // 21
                }                                                                                                      // 22
            });                                                                                                        // 23
        } else {                                                                                                       // 24
            // Set directory permissions                                                                               // 25
            fs.chmod(path, mode, function (err) {                                                                      // 26
                err && console.error('ufs: cannot set temp directory permissions ' + mode + ' (' + err.message + ')');
            });                                                                                                        // 28
        }                                                                                                              // 29
    });                                                                                                                // 30
});                                                                                                                    // 31
                                                                                                                       // 32
// Create domain to handle errors                                                                                      // 33
// and possibly avoid server crashes.                                                                                  // 34
var d = domain.create();                                                                                               // 35
                                                                                                                       // 36
d.on('error', function (err) {                                                                                         // 37
    console.error('ufs: ' + err.message);                                                                              // 38
});                                                                                                                    // 39
                                                                                                                       // 40
// Listen HTTP requests to serve files                                                                                 // 41
WebApp.connectHandlers.use(function (req, res, next) {                                                                 // 42
    // Quick check to see if request should be catch                                                                   // 43
    if (req.url.indexOf(UploadFS.config.storesPath) === -1) {                                                          // 44
        next();                                                                                                        // 45
        return;                                                                                                        // 46
    }                                                                                                                  // 47
                                                                                                                       // 48
    // Remove store path                                                                                               // 49
    var path = req.url.substr(UploadFS.config.storesPath.length + 1);                                                  // 50
                                                                                                                       // 51
    // Get store, file Id and file name                                                                                // 52
    var regExp = new RegExp('^\/([^\/]+)\/([^\/]+)(?:\/([^\/]+))?$');                                                  // 53
    var match = regExp.exec(path);                                                                                     // 54
                                                                                                                       // 55
    if (match !== null) {                                                                                              // 56
        // Get store                                                                                                   // 57
        var storeName = match[1];                                                                                      // 58
        var store = UploadFS.getStore(storeName);                                                                      // 59
                                                                                                                       // 60
        if (!store) {                                                                                                  // 61
            res.writeHead(404);                                                                                        // 62
            res.end();                                                                                                 // 63
            return;                                                                                                    // 64
        }                                                                                                              // 65
                                                                                                                       // 66
        if (typeof store.onRead !== 'function') {                                                                      // 67
            console.error('ufs: store "' + storeName + '" onRead is not a function');                                  // 68
            res.writeHead(500);                                                                                        // 69
            res.end();                                                                                                 // 70
            return;                                                                                                    // 71
        }                                                                                                              // 72
                                                                                                                       // 73
        // Remove file extension from file Id                                                                          // 74
        var index = match[2].indexOf('.');                                                                             // 75
        var fileId = index !== -1 ? match[2].substr(0, index) : match[2];                                              // 76
                                                                                                                       // 77
        // Get file from database                                                                                      // 78
        var file = store.getCollection().findOne(fileId);                                                              // 79
        if (!file) {                                                                                                   // 80
            res.writeHead(404);                                                                                        // 81
            res.end();                                                                                                 // 82
            return;                                                                                                    // 83
        }                                                                                                              // 84
                                                                                                                       // 85
        // Simulate read speed                                                                                         // 86
        if (UploadFS.config.simulateReadDelay) {                                                                       // 87
            Meteor._sleepForMs(UploadFS.config.simulateReadDelay);                                                     // 88
        }                                                                                                              // 89
                                                                                                                       // 90
        d.run(function () {                                                                                            // 91
            // Check if the file can be accessed                                                                       // 92
            if (store.onRead.call(store, fileId, file, req, res)) {                                                    // 93
                // Open the file stream                                                                                // 94
                var rs = store.getReadStream(fileId, file);                                                            // 95
                var ws = new stream.PassThrough();                                                                     // 96
                                                                                                                       // 97
                rs.on('error', function (err) {                                                                        // 98
                    store.onReadError.call(store, err, fileId, file);                                                  // 99
                    res.end();                                                                                         // 100
                });                                                                                                    // 101
                ws.on('error', function (err) {                                                                        // 102
                    store.onReadError.call(store, err, fileId, file);                                                  // 103
                    res.end();                                                                                         // 104
                });                                                                                                    // 105
                ws.on('close', function () {                                                                           // 106
                    // Close output stream at the end                                                                  // 107
                    ws.emit('end');                                                                                    // 108
                });                                                                                                    // 109
                                                                                                                       // 110
                var accept = req.headers['accept-encoding'] || '';                                                     // 111
                var headers = {                                                                                        // 112
                    'Content-Type': file.type,                                                                         // 113
                    'Content-Length': file.size                                                                        // 114
                };                                                                                                     // 115
                                                                                                                       // 116
                // Transform stream                                                                                    // 117
                store.transformRead(rs, ws, fileId, file, req, headers);                                               // 118
                                                                                                                       // 119
                // Compress data using gzip                                                                            // 120
                if (accept.match(/\bgzip\b/)) {                                                                        // 121
                    headers['Content-Encoding'] = 'gzip';                                                              // 122
                    delete headers['Content-Length'];                                                                  // 123
                    res.writeHead(200, headers);                                                                       // 124
                    ws.pipe(zlib.createGzip()).pipe(res);                                                              // 125
                }                                                                                                      // 126
                // Compress data using deflate                                                                         // 127
                else if (accept.match(/\bdeflate\b/)) {                                                                // 128
                    headers['Content-Encoding'] = 'deflate';                                                           // 129
                    delete headers['Content-Length'];                                                                  // 130
                    res.writeHead(200, headers);                                                                       // 131
                    ws.pipe(zlib.createDeflate()).pipe(res);                                                           // 132
                }                                                                                                      // 133
                // Send raw data                                                                                       // 134
                else {                                                                                                 // 135
                    res.writeHead(200, headers);                                                                       // 136
                    ws.pipe(res);                                                                                      // 137
                }                                                                                                      // 138
            } else {                                                                                                   // 139
                res.end();                                                                                             // 140
            }                                                                                                          // 141
        });                                                                                                            // 142
                                                                                                                       // 143
    } else {                                                                                                           // 144
        next();                                                                                                        // 145
    }                                                                                                                  // 146
});                                                                                                                    // 147
                                                                                                                       // 148
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}).call(this);


/* Exports */
if (typeof Package === 'undefined') Package = {};
Package['jalik:ufs'] = {
  UploadFS: UploadFS
};

})();

//# sourceMappingURL=jalik_ufs.js.map