(function() {
  var Loader, ffmpeg, fs, getWin, gui, log4js, path, vm, win;

  fs = require('fs');

  path = require('path');

  vm = require('vm');

  log4js = require('log4js');

  ffmpeg = require('fluent-ffmpeg');

  gui = require('nw.gui');

  win = null;

  getWin = function() {
    return win != null ? win : win = gui.Window.get();
  };

  getWin().on('new-win-policy', function(frame, url, policy) {
    return policy.ignore();
  });

  Loader = (function() {
    function Loader(modules) {
      var appData, client, config, devMode, keyHandle, location, pendingKey;
      this.modules = modules != null ? modules : {};
      this.modules.loader = this;
      log4js.configure({
        appenders: []
      });
      log4js.loadAppender('file');
      appData = process.env.LOCALAPPDATA || process.env.APPDATA;
      config = JSON.parse(fs.readFileSync('package.json', 'utf8'));
      this.env = {
        appData: appData,
        config: config
      };
      ffmpeg.setFfmpegPath('../plugins/ffmpeg.exe');
      ffmpeg.setFfprobePath('../plugins/ffprobe.exe');
      this.client = client = document.createElement('iframe');
      if (config.growth['is-client-local']) {
        location = 'file:///' + path.resolve(config.growth['client-server']);
      } else {
        location = 'http://' + config.growth['client-server'];
      }
      client.src = "" + location + "/" + config.growth.client + "/index-iframe-node-webkit.html";
      client.frameBorder = '0';
      client.setAttribute('style', 'width:100%;height:100%;border:0;');
      devMode = false;
      pendingKey = false;
      keyHandle = (function(_this) {
        return function(event) {
          if (event.ctrlKey && event.shiftKey && event.keyCode === 68) {
            if (!devMode) {
              _this.modules.logger.info('Development mode on');
            }
            devMode = true;
          }
          if (devMode) {
            if (event.keyCode === 123) {
              _this.showDevTools();
            }
            if (event.keyCode === 116) {
              _this.reload();
            }
            if (event.ctrlKey && event.keyCode === 75) {
              pendingKey = true;
            }
            if (pendingKey) {
              pendingKey = true;
              if (event.ctrlKey && event.keyCode === 67) {
                _this.modules.setting.set({
                  clear: false
                });
              }
              if (event.ctrlKey && event.keyCode === 70) {
                return _this.showItemInFolder(_this.modules.setting.localRoot);
              }
            }
          }
        };
      })(this);
      client.onload = function() {
        var doc, style, tag;
        style = document.createElement('style');
        style.innerHTML = "@font-face {font-family: 'simheiRegular';src: url(" + (path.resolve('../assets/font/simhei.ttf').split(path.sep).join('/')) + ");}";
        doc = client.contentWindow.document;
        doc.head.appendChild(style);
        doc.addEventListener('keyup', keyHandle);
        doc.onkeydown = function (event) {
	var event = event || window.event;
	var target = event.target || event.srcElement;
	var type = target.type || target.getAttribute('type');
	var readonly = null == target.getAttribute('readonly') ? false : target.getAttribute('readonly');
	var enabled = null == target.getAttribute('enabled') ? true : target.getAttribute('enabled');
	return !(event.keyCode == 8
		&& ((type != "password" && type != "text" && type != "textarea"))
		|| ((type == "password" || type == "text" || type == "textarea") && (readonly || !enabled)));
	};
        tag = document.getElementsByClassName('version')[0];
        return tag.textContent = "v3.5." + (config.growth.version.split('.').shift());
      };
      if (!config.growth['no-client']) {
        document.body.appendChild(client);
      }
      document.addEventListener('keyup', keyHandle);
      this.namespaces = {};
    }

    Loader.prototype.run = function(code) {
      var script;
      script = vm.createScript(code);
      return script.runInThisContext();
    };

    Loader.prototype.execute = function(message) {
      var module, name, text;
      name = message.name, text = message.text;
      module = this.run(text);
      return this.modules[name] = module;
    };

    Loader.prototype.register = function(name, module) {
      return this.modules[name] = module;
    };

    Loader.prototype.require = function(name, module) {
      return this.modules[name] = require(module);
    };

    Loader.prototype.reload = function() {
      return getWin().reload();
    };

    Loader.prototype.showDevTools = function() {
      return getWin().showDevTools();
    };

    Loader.prototype.showItemInFolder = function(path) {
      return gui.Shell.showItemInFolder(path);
    };

    Loader.prototype.openExternal = function(path) {
      return gui.Shell.openExternal(path);
    };

    return Loader;

  })();

  window.loader = new Loader;

}).call(this);

(function() {
  var CArray, EventEmitter, FileUtility, Limiter, Promise, Q, Utility, child, crypto, fs, path, _,
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
    __slice = [].slice;

  fs = require('fs');

  path = require('path');

  Q = require('q');

  Promise = Q.Promise;

  crypto = require('crypto');

  _ = require('underscore');

  child = require('child_process');

  EventEmitter = require('events').EventEmitter;

  loader.namespaces.statusModule = {
    initStatus: function() {
      var statusHandles;
      if (this.hasOwnProperty('__status__')) {
        return;
      }
      this.__status__ = void 0;
      Object.defineProperty(this, 'status', {
        get: (function(_this) {
          return function() {
            return _this.__status__;
          };
        })(this),
        set: (function(_this) {
          return function(newValue) {
            return _this.__status__ = newValue;
          };
        })(this)
      });
      statusHandles = [];
      this.__statusHandles__ = statusHandles;
      return Object.observe(this, (function(_this) {
        return function(properties) {
          var newStatus, property;
          property = _(properties).findWhere({
            name: '__status__',
            type: 'update'
          });
          if (!property || _(statusHandles).isEmpty()) {
            return;
          }
          newStatus = property.object.__status__;
          return _.chain(statusHandles).where({
            status: newStatus
          }).each(function(handle) {
            if (handle) {
              return handle.callback.call(_this, newStatus, _this);
            }
          }).value();
        };
      })(this));
    },
    onStatus: function(status, callback) {
      if (!this.hasOwnProperty('__status__')) {
        this.initStatus();
      }
      return this.__statusHandles__.push({
        status: status,
        callback: callback
      });
    }
  };

  CArray = (function(_super) {
    __extends(CArray, _super);

    function CArray() {
      CArray.__super__.constructor.apply(this, arguments);
    }

    CArray.prototype.push = function() {
      var arg;
      arg = Array.prototype.slice.call(arguments);
      CArray.__super__.push.apply(this, arguments);
      return this.emit('splice', [
        {
          type: 'splice',
          addedCount: arg.length,
          index: this.length - arg.length,
          object: this,
          removed: []
        }
      ]);
    };

    CArray.prototype.splice = function() {
      var count, index, items, removed;
      index = arguments[0], count = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
      removed = CArray.__super__.splice.apply(this, arguments);
      if (removed.length === 0 && items.length === 0) {
        return;
      }
      return this.emit('splice', [
        {
          type: 'splice',
          addedCount: items.length,
          index: index,
          object: this,
          removed: removed
        }
      ]);
    };

    return CArray;

  })(Array);

  _.extend(CArray.prototype, EventEmitter.prototype);

  Limiter = (function() {
    function Limiter(parallel, options) {
      this.parallel = parallel;
      if (options == null) {
        options = {};
      }
      this.stdout = options.stdout, this.name = options.name, this.timeout = options.timeout;
      this.working = new CArray;
      this.pending = new CArray;
      this.pending.on('splice', (function(_this) {
        return function(changes) {
          return _(changes).each(function(change) {
            var addedCount, index, object, type;
            type = change.type, object = change.object, index = change.index, addedCount = change.addedCount;
            if (type !== 'splice' || addedCount < 1) {
              return;
            }
            _this.report("pending insert " + addedCount + ", current: [" + (_this.mapNames(object)) + "]");
            return _this.popPending();
          });
        };
      })(this));
      this.working.on('splice', (function(_this) {
        return function(changes) {
          return _(changes).each(function(change) {
            var addedCount, i, index, object, removed, type, _i, _ref;
            type = change.type, removed = change.removed, object = change.object, index = change.index, addedCount = change.addedCount;
            if (type !== 'splice') {
              return;
            }
            if (addedCount > 0) {
              _this.report("working insert " + addedCount + ", current: [" + (_this.mapNames(object)) + "]");
              for (i = _i = index, _ref = index + addedCount - 1; index <= _ref ? _i <= _ref : _i >= _ref; i = index <= _ref ? ++_i : --_i) {
                _this.insert(object[i]);
              }
            }
            if (removed.length > 0 && _this.pending.length > 0) {
              _this.report("working remove " + removed.length + ": [" + (_this.mapNames(removed)) + "]");
              return _this.popPending();
            }
          });
        };
      })(this));
    }

    Limiter.prototype.start = function(worker) {
      if (worker) {
        this.report("try start worker " + worker.name);
      }
      if (!(worker && this.working.length < this.parallel && !this.paused)) {
        return;
      }
      this.report("start worker " + worker.name);
      Utility.remove(this.pending, worker);
      return this.working.push(worker);
    };

    Limiter.prototype.insert = function(worker) {
      var progress;
      if (this.terminal) {
        this.report("cancel worker " + worker.name);
        worker.access.reject();
        Utility.remove(this.working, worker);
        return;
      }
      worker.access.resolve();
      this.report("process worker " + worker.name);
      progress = this.timeout ? worker.progress.timeout(this.timeout, {
        message: 'Progress timeout'
      })["catch"](function() {
        return console.warn('[Timeout] Worker in limiter');
      }) : worker.progress;
      return progress.fin((function(_this) {
        return function() {
          var finished;
          finished = _(_this.working).filter(function(exist) {
            return !exist.progress.isPending();
          });
          _this.report("" + finished.length + " worker is finished: [" + (_this.mapNames(finished)) + "]");
          Utility.removes(_this.working, finished);
          return Utility.remove(_this.working, worker);
        };
      })(this));
    };

    Limiter.prototype.report = function(message) {
      if (this.stdout) {
        return this.stdout.log("Limiter report from [" + this.name + "]: " + message);
      }
    };

    Limiter.prototype.popPending = function() {
      var i, _i, _ref, _results;
      if (!(this.parallel > this.working.length)) {
        return;
      }
      this.report("working has " + (this.parallel - this.working.length) + " empty");
      _results = [];
      for (i = _i = 1, _ref = this.parallel - this.working.length; 1 <= _ref ? _i <= _ref : _i >= _ref; i = 1 <= _ref ? ++_i : --_i) {
        _results.push(this.start(this.pending[0]));
      }
      return _results;
    };

    Limiter.prototype.getAccess = function(progress, name) {
      var worker;
      this.report("fire " + name);
      worker = {
        access: Q.defer(),
        progress: progress
      };
      if (name) {
        worker.name = name;
      }
      this.pending.push(worker);
      return worker.access.promise;
    };

    Limiter.prototype.access = function(task) {
      var defer;
      defer = Q.defer();
      return this.getAccess(defer.promise).then((function(_this) {
        return function() {
          return task.call(null, defer);
        };
      })(this)).fin((function(_this) {
        return function() {
          return defer.resolve();
        };
      })(this));
    };

    Limiter.prototype.pause = function() {
      return this.paused = true;
    };

    Limiter.prototype.resume = function() {
      this.paused = false;
      return this.popPending();
    };

    Limiter.prototype.shutdown = function() {
      this.terminal = true;
      this.report("cancel workers " + this.working.length + ": [" + (this.mapNames(this.working)) + "]");
      return this.working.splice(0, this.working.length);
    };

    Limiter.prototype.mapNames = function(workers) {
      return workers.map(function(item) {
        return item.name;
      });
    };

    return Limiter;

  })();

  loader.namespaces.Utility = Utility = (function() {
    function Utility() {}

    Utility.pJson = function(obj) {
      return JSON.stringify(obj, null, 2);
    };

    Utility.mixin = function(origin, module) {
      return _(origin.prototype).extend(module);
    };

    Utility.remove = function(list, item) {
      var idx;
      idx = list.indexOf(item);
      if (idx < 0) {
        return;
      }
      return (list.splice(idx, 1))[0];
    };

    Utility.removes = function(list, items) {
      return _(items).map((function(_this) {
        return function(item) {
          return _this.remove(list, item);
        };
      })(this));
    };

    Utility.getLimiter = function(parallel, options) {
      return new Limiter(parallel, options);
    };

    Utility.getMd5 = function(str) {
      var md5sum;
      md5sum = crypto.createHash('md5');
      md5sum.update(str);
      return md5sum.digest('hex');
    };

    Utility.delay = function(wait) {
      return new Promise(function(resolve) {
        return _.delay(function() {
          return resolve();
        }, wait);
      });
    };

    Utility.strSize = function(obj) {
      var props;
      props = {
        '1': ['h', 'height'],
        '2': ['w', 'width'],
        '3': ['q', 'quality']
      };
      return _.chain(props).map(function(v) {
        if (obj[v[1]]) {
          return "" + obj[v[1]] + v[0];
        }
      }).compact().value().join('_');
    };

    return Utility;

  })();

  var winCopyDir = function (from,to, callback){
    from=from.replace(/\//gim,"\\");
    to=to.replace(/\//gim,"\\");
    child.exec("xcopy /y /e \""+from+"\\*\" \""+to+"\\\"", callback);
};

  var mkdirpSync = function (dirpath) {
  var parts = dirpath.split('/');
  for( var i = 1; i <= parts.length; i++ ) {
    var p = path.join.apply(null, parts.slice(0, i));
    if (!fs.existsSync(p)) fs.mkdirSync(p);
  }
};

  loader.namespaces.FileUtility = FileUtility = (function() {
    function FileUtility() {}

    FileUtility.copyFolder = function(from, to) {
      mkdirpSync(to);
      return new Promise(function(resolve, reject) {
        return winCopyDir(from, to, function(err) {
          if (err) {
            return reject(err);
          }
          return resolve();
        });
      });
    };

    FileUtility.createFolder = function(pathStr) {
      return mkdirpSync(pathStr);
    };

    FileUtility.prepareFolder = function(pathStr) {
      var dir;
      dir = path.dirname(pathStr);
      return this.createFolder(dir);
    };

    FileUtility.readFile = function(path, start, end) {
      var sf;
      sf = Date.now();
      return new Promise((function(_this) {
        return function(resolve, reject) {
          var buf, rd;
          rd = fs.createReadStream(path, {
            start: start,
            end: end
          });
          buf = null;
          rd.on('data', function(chunk) {
            if (buf != null) {
              return buf = Buffer.concat([buf, chunk]);
            } else {
              return buf = chunk;
            }
          });
          rd.on('end', function() {
            console.log("Inside read file takes " + (Date.now() - sf));
            return resolve(buf);
          });
          return rd.on('error', function() {
            return reject.apply(null, arguments);
          });
        };
      })(this));
    };

    FileUtility.cutTo = function(from, to) {
      return this.copyFile(from, to).then((function(_this) {
        return function() {
          return _this.destroy(from);
        };
      })(this));
    };

    FileUtility.copyFile = function(from, to, processing) {
      var bc, length, report, size;
      if (processing == null) {
        processing = null;
      }
      this.prepareFolder(to);
      bc = Date.now();
      length = 0;
      if (processing) {
        size = (fs.statSync(from)).size;
        report = _.throttle(function(length) {
          return processing.call(null, length / size);
        }, 500);
      }
      return new Promise(function(resolve, reject) {
        var rd, wr;
        rd = fs.createReadStream(from).on('data', function(chunk) {
          length = length + chunk.length;
          if (report) {
            return report();
          }
        });
        rd.on('error', function(err) {
          return reject(err);
        });
        wr = fs.createWriteStream(to);
        wr.on('error', function(err) {
          return reject(err);
        });
        wr.on('close', function(result) {
          console.log("copy takes " + (Date.now() - bc) + "ms");
          return resolve(result);
        });
        return rd.pipe(wr);
      });
    };

    FileUtility.destroy = function(path) {
      return new Promise(function(resolve, reject) {
        if (!fs.existsSync(path)) {
          return resolve();
        }
        return fs.unlink(path, function(err) {
          if (err) {
            return reject(err);
          }
          return resolve();
        });
      });
    };

    FileUtility.getMd5 = function(path) {
      var bc, md5sum;
      bc = Date.now();
      md5sum = crypto.createHash('md5');
      return new Promise(function(resolve, reject) {
        var s;
        s = fs.ReadStream(path);
        s.on('data', function(buf) {
          return md5sum.update(buf);
        });
        s.on('end', function() {
          console.log("MD5 count takes " + (Date.now() - bc) + "ms");
          return resolve(md5sum.digest('hex'));
        });
        return s.on('error', function() {
          return reject.apply(null, arguments);
        });
      });
    };

    FileUtility.getBase64 = function(path) {
      return new Promise(function(resolve, reject) {
        return fs.readFile(path, function(err, data) {
          if (err) {
            return reject(err);
          }
          return resolve(data.toString('base64'));
        });
      });
    };

    return FileUtility;

  })();

}).call(this);

(function() {
  var Setting, appData, fs, loader, path, settingPath, _;

  fs = require('fs');

  path = require('path');

  _ = require('underscore');

  loader = window.loader;

  settingPath = 'setting.json';

  appData = loader.env.appData;

  Setting = (function() {
    function Setting() {
      var content;
      if (fs.existsSync(settingPath)) {
        content = JSON.parse(fs.readFileSync(settingPath, 'utf8'));
      }
      if (content == null) {
        content = {};
      }
      this.content = content;
      if (content.localFolder == null) {
        content.localFolder = appData;
      }
      this.setLocalFolder(content.localFolder);
    }

    Setting.prototype.openLocalFolder = function() {
      return loader.showItemInFolder(this.localRoot);
    };

    Setting.prototype.setLocalFolder = function(localFolder) {
      var config, localRoot;
      config = loader.env.config;
      this.localRoot = localRoot = path.join(localFolder, "" + config.name + "Files");
      if (!fs.existsSync(localRoot)) {
        return fs.mkdirSync(localRoot);
      }
    };

    Setting.prototype.get = function() {
      return this.content;
    };

    Setting.prototype.set = function(content) {
      var fileManager, logger, _ref;
      _ref = loader.modules, logger = _ref.logger, fileManager = _ref.fileManager;
      if (this.content == null) {
        this.content = {};
      }
      _(this.content).extend(content);
      if (this.content.localFolder) {
        this.setLocalFolder(this.content.localFolder);
        fileManager.initFolder();
        logger.init();
      }
      return this.save();
    };

    Setting.prototype.save = function() {
      var dump;
      dump = _.clone(this.content);
      if (dump.localFolder === appData) {
        delete dump.localFolder;
      }
      return fs.writeFileSync(settingPath, JSON.stringify(dump, null, 2), 'utf8');
    };

    return Setting;

  })();

  loader.register('setting', new Setting);

}).call(this);

(function() {
  var Logger, exceptionHandle, fs, loader, log4js, logger, path, setting;

  fs = require('fs');

  path = require('path');

  log4js = require('log4js');

  loader = window.loader;

  setting = loader.modules.setting;

  Logger = (function() {
    function Logger() {}

    Logger.prototype.init = function() {
      var logFolder, logTime;
      logFolder = path.join(setting.localRoot, 'log');
      if (!fs.existsSync(logFolder)) {
        fs.mkdirSync(logFolder);
      }
      logTime = Date.now();
      log4js.addAppender(log4js.appenders.file(path.join(logFolder, 'dump.log'), void 0, 2048000, 10), "dump" + logTime);
      this.cheese = log4js.getLogger("dump" + logTime);
      return this.cheese.setLevel('INFO');
    };

    Logger.prototype.info = function() {
      return this.cheese.info.apply(this.cheese, arguments);
    };

    Logger.prototype.warn = function() {
      return this.cheese.warn.apply(this.cheese, arguments);
    };

    Logger.prototype.error = function() {
      return this.cheese.error.apply(this.cheese, arguments);
    };

    Logger.prototype.fatal = function() {
      return this.cheese.fatal.apply(this.cheese, arguments);
    };

    return Logger;

  })();

  logger = new Logger;

  logger.init();

  loader.register('logger', logger);

  logger.info('Application launch...');

  exceptionHandle = function(err) {
    console.error(err);
    if (logger != null ? logger.inited : void 0) {
      return logger.fatal(err);
    }
  };

  process.removeAllListeners('uncaughtException');

  process.on('uncaughtException', exceptionHandle);

}).call(this);

(function() {
  var FFmpeg, Promise, Q, Utility, convertLimiter, ffmpeg, loader, logger, path, _;

  ffmpeg = require('fluent-ffmpeg');

  path = require('path');

  Q = require('q');

  Promise = Q.Promise;

  _ = require('underscore');

  loader = window.loader;

  logger = loader.modules.logger;

  Utility = loader.namespaces.Utility;

  convertLimiter = Utility.getLimiter(1);

  loader.namespaces.FFmpeg = FFmpeg = (function() {
    function FFmpeg() {}

    FFmpeg.readMeta = function(path) {
      return new Promise(function(resolve, reject) {
        return ffmpeg(path).ffprobe(function(err, data) {
          if (err) {
            return reject(err);
          }
          return resolve(data);
        });
      });
    };

    FFmpeg.convertAccess = convertLimiter.getAccess.bind(convertLimiter);

    FFmpeg.cacheThumb = function(options) {
      var from, height, maxHeight, maxWidth, to, width;
      from = options.from, to = options.to, maxWidth = options.width, maxHeight = options.height;
      height = width = null;
      return this.readMeta(from).then((function(_this) {
        return function(info) {
          var byteSize, size, videoInfo;
          byteSize = info.format.size;
          videoInfo = _(info.streams).findWhere({
            codec_type: 'video'
          });
          height = videoInfo != null ? videoInfo.height : void 0;
          width = videoInfo != null ? videoInfo.width : void 0;
          if (!height || !width) {
            throw {
              message: 'Can not read image'
            };
          }
          if (!maxHeight && !maxWidth) {
            return _this.generateThumb(from, to);
          }
          if (maxHeight) {
            if (maxWidth) {
              if ((maxHeight * width) > (maxWidth * height)) {
                size = width > maxWidth ? "" + maxWidth + "x?" : null;
              } else {
                size = height > maxHeight ? "?x" + maxHeight : null;
              }
            } else {
              size = height > maxHeight ? "?x" + maxHeight : null;
            }
          }
          return _this.generateThumb(from, to, size);
        };
      })(this));
    };

    FFmpeg.generateThumb = function(from, to, size) {
      var info;
      if (size == null) {
        size = null;
      }
      info = null;
      return new Promise(function(resolve, reject) {
        var command;
        command = ffmpeg().input(from).output(to).on('error', function() {
          logger.error("Transcoding failed. Image infomation: ", Utility.pJson(info));
          return reject.apply(null, arguments);
        }).on('codecData', function(data) {
          return info = data;
        }).on('end', function() {
          resolve.apply(null, arguments);
          return console.log('Transcoding succeeded !');
        });
        if (size) {
          command.size(size);
        }
        return command.run();
      });
    };

    FFmpeg.convert = function(from, to, size, processing) {
      var defer;
      if (size == null) {
        size = null;
      }
      if (processing == null) {
        processing = null;
      }
      defer = Q.defer();
      return Q().then((function(_this) {
        return function() {
          return _this.convertAccess(defer.promise);
        };
      })(this)).then((function(_this) {
        return function() {
          return new Promise(function(resolve, reject) {
            var command, lastPercent;
            lastPercent = null;
            command = ffmpeg().input(from).output(to).videoCodec('libx264').on('error', function() {
              return reject.apply(null, arguments);
            }).on('end', function() {
              resolve.apply(null, arguments);
              return console.log('Transcoding succeeded !');
            }).on('codecData', function() {
              return console.log(arguments);
            }).on('progress', function(info) {
              var currentPercent;
              currentPercent = parseInt(info.percent);
              if (currentPercent !== lastPercent) {
                lastPercent = currentPercent;
                if (processing) {
                  return processing(info);
                }
              }
            });
            if (size) {
              command.size(size);
            }
            return command.run();
          });
        };
      })(this)).fin((function(_this) {
        return function() {
          return defer.resolve();
        };
      })(this));
    };

    FFmpeg.cacheCapture = function(options) {
      var from, to;
      from = options.from, to = options.to;
      return this.readMeta(from).then((function(_this) {
        return function(info) {
          var duration, time;
          duration = info.format.duration;
          time = duration > 1 ? 1 : duration;
          return _this.capture(from, time, path.basename(to), path.dirname(to));
        };
      })(this));
    };

    FFmpeg.capture = function(path, time, filename, folder) {
      return new Promise(function(resolve, reject) {
        return ffmpeg(path).on('error', function() {
          return reject.apply(null, arguments);
        }).on('end', function() {
          resolve.apply(null, arguments);
          return console.log('Screenshots taken !');
        }).screenshots({
          timestamps: [time],
          filename: filename,
          folder: folder
        });
      });
    };

    return FFmpeg;

  })();

}).call(this);

(function() {
  var FFmpeg, File, FileUtility, Promise, Q, URL, Utility, env, fs, http, loader, logger, mh, modules, namespaces, nodeReq, path, statusModule, _;

  fs = require('fs');

  path = require('path');

  nodeReq = require('request');

  _ = require('underscore');

  URL = require('url');

  Q = require('q');

  Promise = Q.Promise;

  loader = window.loader;

  env = loader.env, modules = loader.modules, namespaces = loader.namespaces;

  mh = http = logger = null;

  statusModule = namespaces.statusModule, Utility = namespaces.Utility, FileUtility = namespaces.FileUtility, FFmpeg = namespaces.FFmpeg;

  process.nextTick(function() {
    mh = modules.messageHost;
    return http = modules.http, logger = modules.logger, modules;
  });

  loader.namespaces.File = File = (function() {
    var _ref;

    function File(data, manager) {
      var entry;
      this.manager = manager;
      this.name = data.name;
      this.store = this.manager.fileStore;
      entry = this.store.querySingle({
        index: 'name',
        value: data.name
      }).then((function(_this) {
        return function(list) {
          var entity;
          entity = list[0];
          return entity != null ? entity : entity = _this.store.put(_(data).extend({
            tasks: []
          }));
        };
      })(this))["catch"](console.error.bind(console));
      this.limiters = [];
      this.ready = this.chain = entry.then((function(_this) {
        return function(data) {
          return _this.data = data;
        };
      })(this));
    }

    File.prototype.chunkSize = (_ref = env.config.growth['chunk-size']) != null ? _ref : 100;

    File.prototype.pushTaskOp = function(name, options) {
      var task;
      task = {
        name: name,
        options: options,
        time: Date.now(),
        hrt: process.hrtime()[1]
      };
      this.ready.then((function(_this) {
        return function() {
          _this.data.tasks.push(task);
          return _this.persist();
        };
      })(this));
      return this.chain = this.chain.then((function(_this) {
        return function() {
          return _this.doTask(task);
        };
      })(this));
    };

    File.prototype.persist = function() {
      return this.store.put(this.data);
    };

    File.prototype.pauseTask = function() {
      return this.limiters.forEach(function(limiter) {
        return limiter.pause();
      });
    };

    File.prototype.resumeTask = function() {
      return this.limiters.forEach(function(limiter) {
        return limiter.resume();
      });
    };

    File.prototype.pushTask = function(name, options) {
      return this.chain = this.chain.then((function(_this) {
        return function() {
          var task;
          task = {
            name: name,
            options: options,
            time: Date.now(),
            hrt: process.hrtime()[1]
          };
          _this.data.tasks.push(task);
          _this.persist();
          return _this.doTask(task);
        };
      })(this));
    };

    File.prototype.popTask = function() {
      return this.chain = this.chain.then((function(_this) {
        return function() {
          if (_this.data.tasks.length === 0) {
            return;
          }
          return _this.doTask(_this.data.tasks[0]);
        };
      })(this));
    };

    File.prototype.doTask = function(task) {
      var name, options;
      name = task.name, options = task.options;
      return this[name].call(this, options)["catch"](function(err) {
        var _ref1;
        console.error((_ref1 = err.stack) != null ? _ref1 : err);
        throw err;
      }).fin((function(_this) {
        return function() {
          Utility.remove(_this.data.tasks, task);
          return _this.persist();
        };
      })(this));
    };

    File.prototype.getTmp = function() {
      return this.ready.then((function(_this) {
        return function() {
          return _this.data.tmp;
        };
      })(this));
    };

    File.prototype.getBase64 = function() {
      var src, tmp, _ref1;
      _ref1 = this.data, tmp = _ref1.tmp, src = _ref1.src;
      return FileUtility.getBase64(tmp != null ? tmp : src);
    };

    File.prototype.backup = function(options) {
      return Q().then((function(_this) {
        return function() {
          return _this.configureBackup(options);
        };
      })(this)).then((function(_this) {
        return function() {
          return _this._backup();
        };
      })(this));
    };

    File.prototype.undoBackup = function() {
      return FileUtility.destroy(this.data.tmp).then((function(_this) {
        return function() {
          delete _this.data.copied;
          delete _this.data.tmp;
          return delete _this.data.size;
        };
      })(this));
    };

    File.prototype.generateThumb = function(options) {
      return Q().then((function(_this) {
        return function() {
          return _this.configureBackup(options);
        };
      })(this)).then((function(_this) {
        return function() {
          if (!_this.data.copied) {
            return _this._backup();
          }
        };
      })(this)).then((function(_this) {
        return function() {
          var _ref1;
          if ((_ref1 = _this.data.image) != null ? _ref1.config : void 0) {
            return;
          }
          return FFmpeg.readMeta(_this.data.tmp).then(function(info) {
            var videoInfo, _base;
            if ((_base = _this.data).image == null) {
              _base.image = {};
            }
            _this.data.size = info.format.size;
            videoInfo = _(info.streams).findWhere({
              codec_type: 'video'
            });
            _this.data.image.height = videoInfo != null ? videoInfo.height : void 0;
            _this.data.image.width = videoInfo != null ? videoInfo.width : void 0;
            _this.data.image.config = true;
            return _this.persist();
          });
        };
      })(this)).then((function(_this) {
        return function() {
          var height, size, thumb, width, _ref1;
          if (_this.data.thumb != null) {
            return;
          }
          _ref1 = _this.data.image, width = _ref1.width, height = _ref1.height;
          size = null;
          thumb = path.join(_this.manager.thumbRoot, "" + _this.name + (path.extname(_this.data.tmp)));
          if ((width * 9) > (height * 16)) {
            size = width > 400 ? '400x?' : null;
          } else {
            size = height > 225 ? '?x225' : null;
          }
          return FFmpeg.generateThumb(_this.data.tmp, thumb, size).then(function() {
            var _base;
            if ((_base = _this.data).thumb == null) {
              _base.thumb = {};
            }
            _this.data.thumb.src = thumb;
            return _this.persist();
          });
        };
      })(this));
    };

    File.prototype.cacheThumb = function(options) {
      return Q().then((function(_this) {
        return function() {
          return _this.backupOp(options);
        };
      })(this)).then((function(_this) {
        return function() {
          var height, tmp, to, width;
          to = options.to, width = options.width, height = options.height;
          tmp = _this.data.tmp;
          return _this._cacheThumb({
            from: tmp,
            to: to,
            width: width,
            height: height
          });
        };
      })(this)).fin((function(_this) {
        return function() {
          delete _this.data.beBackup;
          delete _this.data.thumbCached;
          return _this.undoBackup();
        };
      })(this));
    };

    File.prototype.cacheScreenshot = function(options) {
      return Q().then((function(_this) {
        return function() {
          var from, to;
          from = options.src, to = options.to;
          FileUtility.prepareFolder(to);
          return FFmpeg.cacheCapture({
            from: from,
            to: to
          });
        };
      })(this));
    };

    File.prototype.backupOp = function(options) {
      var name, src, tmp;
      if (this.data.beBackup) {
        return;
      }
      name = this.name;
      if (options.src) {
        this.data.src = options.src;
      }
      src = this.data.src;
      tmp = path.join(this.manager.tempRoot, name + path.extname(src));
      return Q().then((function(_this) {
        return function() {
          return _this._backupOp({
            src: src,
            name: name,
            tmp: tmp
          });
        };
      })(this)).then((function(_this) {
        return function() {
          _this.data.tmp = tmp;
          _this.data.beBackup = true;
          return _this.persist();
        };
      })(this));
    };

    File.prototype._cacheThumb = function(options) {
      if (this.data.thumbCached) {
        return;
      }
      return Q().then((function(_this) {
        return function() {
          FileUtility.prepareFolder(options.to);
          return FFmpeg.cacheThumb(options);
        };
      })(this)).then((function(_this) {
        return function() {
          _this.data.thumbCached = true;
          return _this.persist();
        };
      })(this));
    };

    File.prototype.setAttrs = function(options) {
      if (this.data.attrs != null) {
        _(this.data.attrs).extend(options.attrs);
      } else {
        this.data.attrs = options.attrs;
      }
      return this.persist();
    };

    File.prototype._backup = function() {
      return this._backupOp(this.data);
    };

    File.prototype._backupOp = function(options) {
      var category, name, postPercent, reporter, src, tmp;
      src = options.src, tmp = options.tmp, name = options.name, category = options.category;
      reporter = mh.reportPercentHandler({
        name: name,
        title: "" + src + " 文件备份",
        category: category,
        event: 'copy'
      });
      postPercent = function(percent) {
        percent = parseInt(percent);
        return reporter(percent);
      };
      return FileUtility.copyFile(src, tmp, postPercent).then((function(_this) {
        return function() {
          mh.reportTerminal({
            name: name,
            event: 'copy'
          });
          _this.data.copied = true;
          return _this.persist();
        };
      })(this));
    };

    File.prototype.download = function(options) {
      return Q().then((function(_this) {
        return function() {
          _this.data.url = options.url;
          return _this.persist();
        };
      })(this)).then((function(_this) {
        return function() {
          return _this._download(options);
        };
      })(this)).then((function(_this) {
        return function() {
          delete _this.data.downloaded;
          return _this.persist();
        };
      })(this))["catch"](function(err) {
        var _ref1;
        console.error((_ref1 = err.stack) != null ? _ref1 : err);
        throw err;
      });
    };

    File.prototype._download = function(options) {
      var cache, downloaded, extname, limiter, name, promise, to, url, _ref1, _ref2;
      _ref1 = this.data, url = _ref1.url, name = _ref1.name, downloaded = _ref1.downloaded;
      if (downloaded) {
        return;
      }
      extname = path.extname(URL.parse(url).pathname);
      options = _.extend({
        node: this.data,
        name: name,
        cachePath: path.join(this.manager.cacheRoot, name + extname),
        persistHandle: (function(_this) {
          return function() {
            return _this.persist();
          };
        })(this)
      }, options);
      to = options.to, cache = options.cache;
      if (!to || cache) {
        options.to = path.join(this.manager.tempRoot, name + extname);
      }
      _ref2 = http.download(options), promise = _ref2.promise, limiter = _ref2.limiter;
      this.limiters.push(limiter);
      return promise.then((function(_this) {
        return function(p) {
          if (!cache && to) {
            return;
          }
          _this.data['tmp'] = p;
          if (cache && to) {
            return FileUtility.copyFile(p, to);
          }
        };
      })(this)).then((function(_this) {
        return function() {
          _this.data.downloaded = true;
          return _this.persist();
        };
      })(this)).fin((function(_this) {
        return function() {
          return Utility.remove(_this.limiters, limiter);
        };
      })(this));
    };

    File.prototype.upload = function(options) {
      return this.configureBackup(options).then((function(_this) {
        return function() {
          if (!_this.data.copied) {
            return _this._backup();
          }
        };
      })(this)).then((function(_this) {
        return function() {
          var _ref1;
          if (!((_ref1 = _this.data.upload) != null ? _ref1.config : void 0)) {
            return _this.configureUpload(options);
          }
        };
      })(this)).then((function(_this) {
        return function() {
          _this.data.upload.title = _this.data.src;
          return _this._upload({
            property: 'tmp'
          });
        };
      })(this))["catch"](function(err) {
        return console.error(err.stack);
      }).then((function(_this) {
        return function() {
          return _this.undoBackup();
        };
      })(this)).then((function(_this) {
        return function() {
          return _this.cleanUpload();
        };
      })(this));
    };

    File.prototype._upload = function(options) {
      var limiter, promise, _ref1;
      options = _.extend({
        node: this.data,
        name: this.name,
        property: 'src',
        persistHandle: (function(_this) {
          return function() {
            return _this.persist();
          };
        })(this)
      }, options);
      _ref1 = http.upload(options), promise = _ref1.promise, limiter = _ref1.limiter;
      this.limiters.push(limiter);
      return promise.fin((function(_this) {
        return function() {
          return Utility.remove(_this.limiters, limiter);
        };
      })(this));
    };

    File.prototype.videoScan = function(options) {
      return FFmpeg.readMeta(options.src).then((function(_this) {
        return function(info) {
          return console.log(info);
        };
      })(this));
    };

    File.prototype.videoUpload = function(options) {
      this.data.category = 'video';
      return this.configureBackup(options).then((function(_this) {
        return function() {
          if (!_this.data.copied) {
            return _this._backup();
          }
        };
      })(this)).then((function(_this) {
        return function() {
          return FFmpeg.readMeta(_this.data.tmp).then(function(info) {
            var videoInfo, _base;
            logger.info("Converte video: " + _this.data.src, Utility.pJson(info));
            if ((_base = _this.data).video == null) {
              _base.video = {};
            }
            _this.data.video.duration = info.format.duration;
            _this.data.size = info.format.size;
            videoInfo = _(info.streams).findWhere({
              codec_type: 'video'
            });
            _this.data.video.height = videoInfo != null ? videoInfo.height : void 0;
            _this.data.video.width = videoInfo != null ? videoInfo.width : void 0;
            return _this.persist();
          });
        };
      })(this)).then((function(_this) {
        return function() {
          var height, msg, produce, videoSize, width, _ref1, _ref2;
          if ((_ref1 = _this.data.video) != null ? _ref1.converted : void 0) {
            return;
          }
          msg = {
            name: _this.name,
            title: "" + _this.data.src + " 视频转化",
            category: 'video',
            event: 'convert',
            status: 'process',
            percent: 0
          };
          mh.post(msg);
          _ref2 = _this.data.video, height = _ref2.height, width = _ref2.width;
          produce = path.join(_this.manager.produceRoot, "" + _this.name + ".mp4");
          if ((width * 3) > (height * 4)) {
            videoSize = width > 800 ? '800x?' : null;
          } else {
            videoSize = height > 600 ? '?x600' : null;
          }
          return FFmpeg.convert(_this.data.tmp, produce, videoSize, function(info) {
            return mh.post(_.extend({}, msg, {
              percent: parseInt(info.percent)
            }));
          }).then(function(info) {
            var _base;
            if ((_base = _this.data).produce == null) {
              _base.produce = {};
            }
            _this.data.produce.src = produce;
            _this.data.video.converted = true;
            return _this.persist();
          }).then(function() {
            return mh.post({
              name: _this.name,
              title: "" + _this.data.src + " 视频转化",
              event: 'convert',
              status: 'terminal'
            });
          });
        };
      })(this)).then((function(_this) {
        return function() {
          var time, _ref1;
          if ((_ref1 = _this.data.video) != null ? _ref1.capture : void 0) {
            return;
          }
          time = _this.data.video.duration > 1 ? 1 : _this.data.video.duration;
          return FFmpeg.capture(_this.data.produce.src, time, "" + _this.data.name + ".png", _this.manager.screenshotRoot).then(function() {
            var _base;
            if ((_base = _this.data).screenshot == null) {
              _base.screenshot = {};
            }
            _this.data.screenshot.src = path.join(_this.manager.screenshotRoot, "" + _this.data.name + ".png");
            _this.data.video.capture = true;
            return _this.persist();
          });
        };
      })(this)).then((function(_this) {
        return function() {
          var data, remotePath, stat, type, _ref1;
          data = _this.data.screenshot;
          remotePath = options.remotePath, type = options.type;
          if (!((_ref1 = data.upload) != null ? _ref1.config : void 0)) {
            stat = fs.statSync(data.src);
            data.size = stat.size;
            if (data.upload == null) {
              data.upload = {};
            }
            data.upload.title = "" + _this.data.src + " 封面";
            return _this.configureUpload({
              remotePath: "" + (path.dirname(remotePath)) + "/" + (path.basename(remotePath, path.extname(remotePath))) + "_preview.png",
              type: type
            }, data);
          }
        };
      })(this)).then((function(_this) {
        return function() {
          return _this._upload({
            node: _this.data.screenshot
          });
        };
      })(this)).then((function(_this) {
        return function() {
          var data, stat, _ref1;
          data = _this.data.produce;
          if (!((_ref1 = data.upload) != null ? _ref1.config : void 0)) {
            stat = fs.statSync(data.src);
            data.size = stat.size;
            if (data.upload == null) {
              data.upload = {};
            }
            data.upload.title = _this.data.src;
            return _this.configureUpload(options, data);
          }
        };
      })(this)).then((function(_this) {
        return function() {
          return _this._upload({
            node: _this.data.produce
          });
        };
      })(this))["catch"](function(err) {
        return console.error(err.stack);
      }).then((function(_this) {
        return function() {
          return _this.undoBackup();
        };
      })(this)).then((function(_this) {
        return function() {
          return _this.cleanVideoUpload();
        };
      })(this));
    };

    File.prototype.cleanUpload = function() {
      delete this.data.upload;
      return this.persist();
    };

    File.prototype.undoThumb = function() {
      return Q().then((function(_this) {
        return function() {
          var _ref1;
          if (((_ref1 = _this.data.thumb) != null ? _ref1.src : void 0)) {
            return FileUtility.destroy(_this.data.thumb.src);
          }
        };
      })(this)).then((function(_this) {
        return function() {
          delete _this.data.thumb;
          delete _this.data.image;
          return _this.persist();
        };
      })(this));
    };

    File.prototype.cleanVideoUpload = function() {
      return Q().then((function(_this) {
        return function() {
          return FileUtility.destroy(_this.data.produce.src);
        };
      })(this)).then((function(_this) {
        return function() {
          return FileUtility.destroy(_this.data.screenshot.src);
        };
      })(this)).then((function(_this) {
        return function() {
          _this.data.produce = _this.data.produce.location;
          _this.data.screenshot = _this.data.screenshot.location;
          delete _this.data.video;
          return _this.persist();
        };
      })(this));
    };

    File.prototype.clean = function() {
      return Q().then((function(_this) {
        return function() {
          return _this.undoBackup();
        };
      })(this)).then((function(_this) {
        return function() {
          return _this.undoThumb();
        };
      })(this)).then((function(_this) {
        return function() {
          delete _this.data.attrs;
          return _this.persist();
        };
      })(this));
    };

    File.prototype.configureBackup = function(options) {
      var src, stat;
      src = options.src;
      stat = fs.statSync(src);
      this.data.src = src;
      this.data.size = stat.size;
      this.data.tmp = path.join(this.manager.tempRoot, this.data.name + path.extname(src));
      return this.persist();
    };

    File.prototype.configureUpload = function(options, data) {
      var remotePath, type;
      if (data == null) {
        data = this.data;
      }
      remotePath = options.remotePath, type = options.type;
      if (data.upload == null) {
        data.upload = {};
      }
      data.upload.remotePath = remotePath != null ? remotePath : this.name;
      data.upload.index = 0;
      data.upload.type = type != null ? type : 'AlbumPhoto';
      data.upload.chunk = Math.ceil(data.size / this.chunkSize / 1024);
      data.upload.chunkSize = this.chunkSize * 1024;
      data.upload.config = true;
      return this.persist();
    };

    return File;

  })();

  Utility.mixin(File, statusModule);

}).call(this);

(function() {
  var File, FileManager, FileUtility, Promise, Q, Store, Utility, crypto, cwdPath, fs, http, loader, logger, mh, path, readonly, setting, _;

  fs = require('fs');

  path = require('path');

  _ = require('underscore');

  Q = require('q');

  Promise = Q.Promise;

  crypto = require('crypto');

  loader = window.loader;

  readonly = loader.env.config.growth.readonly;

  Utility = loader.namespaces.Utility;

  mh = setting = Store = File = FileUtility = logger = http = null;

  cwdPath = process.cwd();

  process.nextTick(function() {
    var _ref, _ref1;
    mh = loader.modules.messageHost;
    _ref = loader.modules, setting = _ref.setting, logger = _ref.logger, http = _ref.http;
    _ref1 = loader.namespaces, Store = _ref1.Store, File = _ref1.File, FileUtility = _ref1.FileUtility;
    return loader.register('fileManager', new FileManager);
  });

  FileManager = (function() {
    FileManager.prototype.processFiles = [];

    function FileManager() {
      this.initFolder();
      this.fileStore = new Store({
        storeName: 'growth-file',
        indexes: [
          {
            name: 'name',
            keyPath: 'name',
            unique: true
          }
        ]
      });
    }

    FileManager.prototype.resetStore = function() {
      return Q().then((function(_this) {
        return function() {
          if (!setting.content.clear) {
            logger.info('Clean indexeddb');
            return _this.fileStore.clear().then(function() {
              setting.content.clear = true;
              return setting.save();
            });
          }
        };
      })(this));
    };

    FileManager.prototype.initFolder = function() {
      this.prepareFolder('tempRoot', 'temp');
      this.prepareFolder('cacheRoot', 'cache');
      this.prepareFolder('produceRoot', 'produces');
      this.prepareFolder('screenshotRoot', 'screenshots');
      this.prepareFolder('thumbRoot', 'thumbs');
      if (readonly) {
        return this.prepareFolder('readonlyRoot', 'readonly');
      }
    };

    FileManager.prototype.prepareFolder = function(prop, folder) {
      this[prop] = path.join(setting.localRoot, folder);
      if (!fs.existsSync(this[prop])) {
        return fs.mkdirSync(this[prop]);
      }
    };

    FileManager.prototype.recover = function() {
      if (this.recovered) {
        return;
      }
      this.recovered = true;
      return this.fileStore.filter(function(obj) {
        return obj.tasks.length !== 0 && !obj.lazy;
      }).then((function(_this) {
        return function(list) {
          return list.forEach(function(item) {
            return _this.wrapTask(item, function(file) {
              return file.popTask();
            });
          });
        };
      })(this));
    };

    FileManager.prototype.execute = function() {
      return console.log(arguments);
    };

    FileManager.prototype.getFile = function(options) {
      return Q().then((function(_this) {
        return function() {
          var name, src, url;
          name = options.name, url = options.url, src = options.src;
          if (name) {
            return name;
          }
          if (src) {
            return FileUtility.getMd5(src);
          }
          if (url) {
            return Utility.getMd5(url);
          }
        };
      })(this)).then((function(_this) {
        return function(name) {
          var file;
          file = _(_this.processFiles).findWhere({
            name: name
          });
          if (!file) {
            file = new File({
              name: name
            }, _this);
            _this.processFiles.push(file);
          }
          return file;
        };
      })(this))["catch"](function(err) {
        return console.error(err.stack);
      });
    };

    FileManager.prototype.popFile = function(file) {
      if (file.chain.isPending()) {
        return;
      }
      return Utility.remove(this.processFiles, file);
    };

    FileManager.prototype.wrapTask = function(data, task) {
      var filePath, name, url;
      filePath = data.filePath, name = data.name, url = data.url;
      if (!((name != null) || (filePath != null) || (url != null))) {
        return console.error('无法找到文件');
      }
      return this.getFile({
        name: name,
        src: filePath,
        url: url
      }).then((function(_this) {
        return function(file) {
          return Q().then(function() {
            return task.call(null, file, data);
          }).then(function(result) {
            _this.popFile(file);
            return result;
          });
        };
      })(this));
    };

    FileManager.prototype.upload = function(data) {
      var filePath, name, remotePath, type;
      filePath = data.filePath, name = data.name, type = data.type, remotePath = data.remotePath;
      return this.wrapTask(data, function(file) {
        if (remotePath == null) {
          console.warn('远程路径不存在, 将使用文件名');
        }
        return file.pushTask('upload', {
          remotePath: remotePath != null ? remotePath : name,
          src: filePath,
          type: type
        });
      });
    };

    FileManager.prototype.getBase64 = function(data) {
      return this.wrapTask(data, function(file) {
        return file.pushTask('getBase64');
      });
    };

    FileManager.prototype.backup = function(data) {
      var filePath, name;
      filePath = data.filePath, name = data.name;
      return this.wrapTask(data, function(file) {
        return file.pushTask('backup', {
          src: filePath
        }).then(function(result) {
          if (data.attrs == null) {
            return result;
          }
          return file.pushTask('setAttrs', data).then(function() {
            return file.data;
          });
        });
      });
    };

    FileManager.prototype.download = function(data) {
      var name, targetFile, terminal, to, url;
      name = data.name, url = data.url, to = data.to, terminal = data.terminal;
      targetFile = null;
      return Q().then((function(_this) {
        return function() {
          return _this.getFile({
            name: name,
            url: url
          });
        };
      })(this)).then(function(file) {
        targetFile = file;
        return file.getTmp();
      }).then((function(_this) {
        return function(tmp) {
          if (tmp && to) {
            return FileUtility.copyFile(tmp, to).then(function() {
              return http.emit('download', _.extend({
                name: targetFile.name,
                status: 'terminal'
              }, targetFile.data, terminal));
            });
          } else {
            return _this.wrapTask(data, function(file) {
              return file.pushTask('download', data);
            });
          }
        };
      })(this));
    };

    FileManager.prototype.undoBackup = function(data) {
      return this.wrapTask(data, function(file) {
        return file.pushTask('undoBackup');
      });
    };

    FileManager.prototype.thumb = function(data) {
      var filePath;
      filePath = data.filePath;
      return this.wrapTask(data, function(file) {
        return file.pushTask('generateThumb', {
          src: filePath
        }).then(function(result) {
          if (data.attrs == null) {
            return result;
          }
          return file.pushTask('setAttrs', data).then(function() {
            return file.data;
          });
        });
      });
    };

    FileManager.prototype.achieveThumb = function(data) {
      var cachePath, filePath, filename, height, pathSubDir, width;
      filePath = data.filePath, width = data.width, height = data.height;
      filename = "" + (path.basename(filePath)) + "@" + (Utility.strSize({
        width: width,
        height: height
      })) + (path.extname(filePath));
      cachePath = "" + (path.dirname(filePath)) + "/.thumbs/" + filename;
      if (fs.existsSync(cachePath)) {
        return cachePath;
      }
      if (readonly) {
        pathSubDir = (path.dirname(filePath)).split('/').pop();
        cachePath = "" + this.readonlyRoot + "/.thumbs/" + pathSubDir + "/" + filename;
        if (fs.existsSync(cachePath)) {
          return cachePath;
        }
      }
      return this.wrapTask(data, function(file) {
        if (!fs.existsSync(filePath)) {
          throw {
            message: 'Source image does not exist'
          };
        }
        return file.pushTask('cacheThumb', {
          src: filePath,
          to: cachePath,
          width: width,
          height: height
        }).then(function() {
          return cachePath;
        });
      });
    };

    FileManager.prototype.achieveScreenshot = function(data) {
      var cachePath, filePath, filename, pathSubDir;
      filePath = data.filePath;
      filename = "" + (path.basename(filePath, path.extname(filePath))) + "_preview.png";
      cachePath = "" + (path.dirname(filePath)) + "/.screenshots/" + filename;
      if (fs.existsSync(cachePath)) {
        return cachePath;
      }
      if (readonly) {
        pathSubDir = (path.dirname(filePath)).split('/').pop();
        cachePath = "" + this.readonlyRoot + "/.thumbs/" + pathSubDir + "/" + filename;
        if (fs.existsSync(cachePath)) {
          return cachePath;
        }
      }
      return this.wrapTask(data, function(file) {
        if (!fs.existsSync(filePath)) {
          throw {
            message: 'Source video does not exist'
          };
        }
        return file.pushTask('cacheScreenshot', {
          src: filePath,
          to: cachePath
        }).then(function() {
          return cachePath;
        });
      });
    };

    FileManager.prototype.videoUpload = function(data) {
      var filePath, name, remotePath, type;
      filePath = data.filePath, name = data.name, type = data.type, remotePath = data.remotePath;
      return this.wrapTask(data, function(file) {
        if (remotePath == null) {
          console.warn('远程路径不存在, 将使用文件名');
        }
        return file.pushTask('videoUpload', {
          remotePath: remotePath != null ? remotePath : name,
          src: filePath,
          type: type
        });
      });
    };

    FileManager.prototype.videoScan = function(data) {
      var filePath, name;
      filePath = data.filePath, name = data.name;
      return this.wrapTask(data, function(file) {
        return file.pushTask('videoScan', {
          src: filePath
        });
      });
    };

    FileManager.prototype.setAttrs = function(data) {
      return this.wrapTask(data, function(file) {
        return file.pushTask('setAttrs', {
          attrs: data.attrs
        });
      });
    };

    FileManager.prototype.queryAttrs = function(attrs) {
      var match;
      match = _.matches(attrs);
      return this.fileStore.filter(function(obj) {
        return match(obj.attrs);
      });
    };

    FileManager.prototype.clean = function(data) {
      return this.wrapTask(data, function(file) {
        return file.pushTask('clean');
      });
    };

    FileManager.prototype.pause = function(data) {
      return this.wrapTask(data, function(file) {
        return file.pauseTask();
      });
    };

    FileManager.prototype.resume = function(data) {
      return this.wrapTask(data, function(file) {
        return file.resumeTask();
      });
    };

    FileManager.prototype.isExist = function(data) {
      var filePath;
      filePath = data.filePath;
      return fs.existsSync(filePath);
    };

    FileManager.prototype.uploadStatus = function(data) {
      var name;
      name = data.name;
      return this.fileStore.querySingle({
        index: 'name',
        value: name
      }).then((function(_this) {
        return function(list) {
          var entity, location, src, status, tmp, upload;
          entity = list[0];
          if (!entity || (!entity.location && entity.tasks.length === 0) || (entity.tasks.length !== 0 && entity.tasks[0].name !== 'upload')) {
            return;
          }
          name = entity.name, location = entity.location, upload = entity.upload, tmp = entity.tmp, src = entity.src;
          if (entity.location) {
            status = 'uploaded';
          } else if (entity.upload) {
            status = 'uploading';
          } else {
            status = 'pending';
          }
          return {
            name: name,
            location: location,
            tmp: tmp,
            src: src,
            status: status
          };
        };
      })(this));
    };

    return FileManager;

  })();

}).call(this);

(function() {
  var EventEmitter, FileUtility, Http, Promise, Q, Utility, alive, alivePath, crypto, downloadChunk, downloadChunkTimeout, downloadRetryGap, downloadRetryLimit, downloadThread, env, fileServer, fs, host, loader, logger, modules, namespaces, nodeReq, path, uploadRetryGap, _, _ref,
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

  fs = require('fs');

  path = require('path');

  nodeReq = require('request');

  Q = require('q');

  Promise = Q.Promise;

  crypto = require('crypto');

  _ = require('underscore');

  EventEmitter = require('events').EventEmitter;

  loader = window.loader;

  env = loader.env, namespaces = loader.namespaces, modules = loader.modules;

  Utility = namespaces.Utility, FileUtility = namespaces.FileUtility;

  logger = modules.logger;

  _ref = loader.env.config.growth, host = _ref.host, alive = _ref['alive-server'], fileServer = _ref['file-server'], alivePath = _ref['alive-path'], downloadRetryGap = _ref['download-retry-gap'], downloadChunkTimeout = _ref['download-chunk-timeout'], downloadThread = _ref['download-thread'];

  if (downloadThread == null) {
    downloadThread = 3;
  }

  downloadChunk = 100;

  if (downloadChunkTimeout == null) {
    downloadChunkTimeout = 20000;
  }

  downloadRetryLimit = 5;

  if (downloadRetryGap == null) {
    downloadRetryGap = 5000;
  }

  uploadRetryGap = 5000;

  Http = (function(_super) {
    __extends(Http, _super);

    function Http() {
      this.uploadLimiter = Utility.getLimiter(3);
      this.uploadAccess = this.uploadLimiter.getAccess.bind(this.uploadLimiter);
      this.downloadLimiter = Utility.getLimiter(downloadThread);
      this.downloadAccess = this.downloadLimiter.getAccess.bind(this.downloadLimiter);
    }

    Http.prototype.apiRequest = function(data) {
      return {
        url: "http://" + host + "/api.aspx",
        json: _.extend({
          AppKey: 'SGA_APPKEY',
          AppSecret: '',
          AppCode: 'SGA',
          Format: 'Json',
          Timestamp: '',
          Version: '1.0',
          Signature: '12B66E52E52216D7124E77C4EC1EA42C'
        }, data)
      };
    };

    Http.prototype.fileRequest = function(data, options) {
      var method, parms, qs;
      method = options.method, qs = options.qs;
      parms = {
        url: "http://" + fileServer + "/File/" + method,
        qs: qs
      };
      if (data) {
        parms.body = data;
      }
      return parms;
    };

    Http.prototype.post = function(data, options) {
      var action, brq, defer, parms, reject, resolve, retry;
      if (options == null) {
        options = {};
      }
      retry = options.retry, defer = options.defer, action = options.action;
      if (!defer) {
        options.defer = defer = Q.defer();
      }
      resolve = defer.resolve, reject = defer.reject;
      brq = Date.now();
      parms = this[action].call(this, data, options);
      nodeReq.post(parms, (function(_this) {
        return function(err, httpResponse, body) {
          var takes;
          takes = Date.now() - brq;
          if (!err && httpResponse && httpResponse.statusCode === 200 && (action === 'fileRequest' || body.Success)) {
            console.log("Request takes " + takes + "ms");
            return resolve(action === 'fileRequest' ? JSON.parse(body) : body);
          } else {
            _this.error("Request is failed with code: " + (httpResponse != null ? httpResponse.statusCode : void 0) + " | takes: " + takes + "ms | error: ", err, "| body: ", body);
            if (retry) {
              return Utility.delay(uploadRetryGap).then(function() {
                return _this.post.apply(_this, [data, options]);
              });
            }
            return reject({
              err: err,
              httpResponse: httpResponse,
              body: body
            });
          }
        };
      })(this));
      return defer.promise;
    };

    Http.prototype.ping = function(user) {
      return new Promise(function(resolve, reject) {
        return nodeReq.get({
          url: "http://" + alive + "/" + alivePath + "/czda/online/" + user.PersonID,
          headers: {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36'
          }
        }, function(err, response, body) {
          if (!err && response.statusCode === 200) {
            return resolve(response);
          } else {
            return reject.apply(null, arguments);
          }
        });
      });
    };

    Http.prototype.upload = function(options) {
      var defer, promise;
      defer = Q.defer();
      options = _.extend({
        limiter: Utility.getLimiter(1)
      }, options);
      promise = Q().then((function(_this) {
        return function() {
          return _this.reportUpload(options, 'process', 0);
        };
      })(this)).then((function(_this) {
        return function() {
          return _this.uploadAccess(defer.promise);
        };
      })(this)).then((function(_this) {
        return function() {
          return _this.uploadInit(options);
        };
      })(this)).then((function(_this) {
        return function() {
          return _this.uploadProcess(options);
        };
      })(this)).then((function(_this) {
        return function() {
          return _this.uploadComplete(options);
        };
      })(this))["catch"]((function(_this) {
        return function(err) {
          _this.emit('upload', _.extend({
            name: options.name,
            status: 'abort'
          }));
          return _this.error(err.message);
        };
      })(this)).fin((function(_this) {
        return function() {
          return defer.resolve();
        };
      })(this));
      return {
        promise: promise,
        limiter: options.limiter
      };
    };

    Http.prototype.download = function(options) {
      var defer, limiter, promise;
      defer = Q.defer();
      limiter = Utility.getLimiter(1, {
        timeout: downloadChunkTimeout
      });
      options = _.extend({
        limiter: limiter
      }, options);
      promise = Q().then((function(_this) {
        return function() {
          return _this.downloadConfig(options);
        };
      })(this)).then((function(_this) {
        return function() {
          return _this.reportDownload(options, 'process', 0);
        };
      })(this)).then((function(_this) {
        return function() {
          return _this.downloadAccess(defer.promise);
        };
      })(this)).then((function(_this) {
        return function() {
          return _this.downloadProcess(options);
        };
      })(this)).then((function(_this) {
        return function() {
          return _this.downloadComplete(options);
        };
      })(this))["catch"]((function(_this) {
        return function(err) {
          _this.emit('download', _.extend({
            name: options.name,
            status: 'abort'
          }, options.abort));
          _this.error(err.message);
          throw err;
        };
      })(this)).fin((function(_this) {
        return function() {
          _this.downloadClear(options);
          return defer.resolve();
        };
      })(this));
      return {
        promise: promise,
        limiter: options.limiter
      };
    };

    Http.prototype.downloadConfig = function(options) {
      var cachePath, node, persistHandle;
      node = options.node, cachePath = options.cachePath, persistHandle = options.persistHandle;
      if (!node.download) {
        node.download = {
          index: 0,
          chunkSize: downloadChunk * 1024,
          cache: cachePath
        };
        return persistHandle.call(null);
      }
    };

    Http.prototype.downloadClear = function(options) {
      var node, persistHandle;
      node = options.node, persistHandle = options.persistHandle;
      delete node.download;
      return persistHandle.call(null);
    };

    Http.prototype.downloadProcess = function(options) {
      var cache, chunk, chunkSize, defer, index, limiter, node, persistHandle, retry, url, _ref1;
      node = options.node, persistHandle = options.persistHandle, limiter = options.limiter;
      (_ref1 = node.download, chunk = _ref1.chunk, index = _ref1.index, cache = _ref1.cache, chunkSize = _ref1.chunkSize, retry = _ref1.retry), url = node.url;
      console.time('access download');
      if (!chunk || index < chunk) {
        defer = Q.defer();
        return limiter.getAccess(defer.promise).then((function(_this) {
          return function() {
            console.timeEnd('access download');
            console.time('download takes');
            return _this.partialDownload(url, cache, index, chunkSize, node.download.size, downloadChunkTimeout - 1000);
          };
        })(this)).fin(function() {
          return console.timeEnd('download takes');
        }).then((function(_this) {
          return function(size) {
            if (!chunk) {
              node.download.chunk = size === 0 ? 1 : Math.ceil(size / chunkSize);
              node.download.size = size;
            }
            if (index < node.download.chunk) {
              node.download.index += 1;
            }
            return persistHandle.call(null);
          };
        })(this)).then((function(_this) {
          return function() {
            var _ref2;
            _ref2 = node.download, index = _ref2.index, chunk = _ref2.chunk;
            _this.reportDownload(options, 'process', Math.floor(index / chunk * 100));
            defer.resolve();
            return _this.downloadProcess(options);
          };
        })(this))["catch"]((function(_this) {
          return function(err) {
            var _base;
            if (err == null) {
              err = {};
            }
            defer.resolve();
            if (err.extra === 'cancel') {
              throw err;
            }
            if (node.download.retry && node.download.retry > downloadRetryLimit) {
              console.error(err);
              err.extra = 'cancel';
              throw err;
            } else {
              if ((_base = node.download).retry == null) {
                _base.retry = 0;
              }
              node.download.retry += 1;
              return persistHandle.call(null).then(function() {
                return Utility.delay(downloadRetryGap);
              }).then(function() {
                return _this.downloadProcess(options);
              });
            }
          };
        })(this));
      }
    };

    Http.prototype.downloadComplete = function(options) {
      var cache, name, node, persistHandle, terminal, to;
      node = options.node, persistHandle = options.persistHandle, to = options.to, terminal = options.terminal, name = options.name;
      cache = node.download.cache;
      return FileUtility.cutTo(cache, to).then((function(_this) {
        return function() {
          return _this.emit('download', _.extend({
            name: name,
            status: 'terminal'
          }, node, terminal));
        };
      })(this)).then(function() {
        return to;
      });
    };

    Http.prototype.uploadInit = function(options) {
      var bw, inited, node, persistHandle, remotePath, type, _ref1;
      node = options.node, persistHandle = options.persistHandle;
      _ref1 = node.upload, remotePath = _ref1.remotePath, type = _ref1.type, inited = _ref1.inited;
      if (inited) {
        return;
      }
      bw = Date.now();
      return this.post(null, {
        qs: {
          filekey: remotePath,
          filetype: type
        },
        retry: true,
        action: 'fileRequest',
        method: 'InitiateMultipartUpload'
      }).then((function(_this) {
        return function(resp) {
          console.log("WrappedPost takes " + (Date.now() - bw));
          node.upload.inited = true;
          node.upload.uploadId = resp.UploadId;
          return persistHandle.call(null);
        };
      })(this));
    };

    Http.prototype.uploadProcess = function(options) {
      var node, persistHandle, uploaded;
      node = options.node, persistHandle = options.persistHandle;
      uploaded = node.upload.uploaded;
      if (uploaded) {
        return;
      }
      return this.recurUpload(options).then((function(_this) {
        return function() {
          console.log('Upload Success');
          node.upload.uploaded = true;
          return persistHandle.call(null);
        };
      })(this));
    };

    Http.prototype.recurUpload = function(options) {
      var au, bu, chunk, chunkSize, defer, index, limiter, node, persistHandle, property, remotePath, size, src, type, uploadId, _ref1;
      node = options.node, persistHandle = options.persistHandle, property = options.property, limiter = options.limiter;
      (_ref1 = node.upload, index = _ref1.index, chunk = _ref1.chunk, chunkSize = _ref1.chunkSize, uploadId = _ref1.uploadId, type = _ref1.type, remotePath = _ref1.remotePath), size = node.size;
      src = node[property];
      if (index === chunk) {
        return;
      }
      bu = Date.now();
      au = null;
      defer = Q.defer();
      return limiter.getAccess(defer.promise).then((function(_this) {
        return function() {
          return _this.partialUpload(src, index, chunkSize, size, uploadId, type, remotePath);
        };
      })(this)).then((function(_this) {
        return function(tag) {
          var _base;
          au = Date.now();
          console.log("Upload takes " + (au - bu));
          if (index < chunk) {
            node.upload.index += 1;
          }
          if ((_base = node.upload).eTags == null) {
            _base.eTags = [];
          }
          node.upload.eTags.push(tag);
          return persistHandle.call(null);
        };
      })(this)).then((function(_this) {
        return function() {
          var _ref2;
          _ref2 = node.upload, index = _ref2.index, chunk = _ref2.chunk;
          console.log("Save takes " + (Date.now() - au));
          _this.reportUpload(options, 'process', Math.floor(index / chunk * 100));
          defer.resolve();
          return _this.recurUpload(options);
        };
      })(this))["catch"]((function(_this) {
        return function(err) {
          if (err.extra === 'cancel') {
            throw err;
          }
          if (err.code === 'ENOENT') {
            err.extra = 'cancel';
            throw err;
          }
          defer.resolve();
          return Utility.delay(uploadRetryGap).then(function() {
            return _this.recurUpload(options);
          });
        };
      })(this));
    };

    Http.prototype.partialUpload = function(src, index, chunkSize, totalSize, uploadId, type, fileName) {
      var end, md5sum, size, start;
      md5sum = crypto.createHash('md5');
      start = index * chunkSize;
      end = ((index + 1) * chunkSize > totalSize ? totalSize : (index + 1) * chunkSize) - 1;
      size = end - start + 1;
      return FileUtility.readFile(src, start, end).then((function(_this) {
        return function(buf) {
          var bw, md5d;
          bw = Date.now();
          md5d = md5sum.update(buf).digest('hex');
          return _this.post(buf, {
            qs: {
              uploadid: uploadId,
              filetype: type,
              filekey: fileName,
              partnumber: index + 1,
              partsize: chunkSize
            },
            action: 'fileRequest',
            method: 'UploadPart'
          }).then(function(resp) {
            console.log("WrappedPost takes " + (Date.now() - bw));
            if (md5d !== resp.ETag.toLowerCase()) {
              throw 'md5 invaild.';
            }
            return resp.ETag;
          });
        };
      })(this));
    };

    Http.prototype.uploadComplete = function(options) {
      var completed, name, node, persistHandle, property, remotePath, src, title, type, uploadId, _ref1;
      node = options.node, persistHandle = options.persistHandle, property = options.property, name = options.name;
      _ref1 = node.upload, remotePath = _ref1.remotePath, type = _ref1.type, uploadId = _ref1.uploadId, title = _ref1.title, completed = _ref1.completed;
      if (completed) {
        return;
      }
      src = node[property];
      return this.post(null, {
        qs: {
          filekey: remotePath,
          filetype: type,
          uploadid: uploadId
        },
        action: 'fileRequest',
        method: 'CompleteMultipartUpload',
        retry: true
      }).then((function(_this) {
        return function(resp) {
          node.location = resp.Location;
          node.upload.completed = true;
          return persistHandle.call(null);
        };
      })(this)).then((function(_this) {
        return function() {
          return _this.emit('upload', _.extend({
            name: name,
            title: title != null ? title : src,
            status: 'terminal'
          }, node, node.upload));
        };
      })(this));
    };

    Http.prototype.partialDownload = function(url, tmp, index, chunkSize, totalSize, timeout) {
      return new Promise((function(_this) {
        return function(resolve, reject) {
          var end, parms;
          end = totalSize && (index + 1) * chunkSize > totalSize ? totalSize : (index + 1) * chunkSize;
          parms = {
            url: url,
            headers: {
              "Range": "bytes=" + (index * chunkSize) + "-" + (end - 1)
            },
            encoding: null
          };
          if (timeout) {
            parms.timeout = timeout;
          }
          return nodeReq(parms, function(err, httpResponse, body) {
            var totalLength;
            if (!err && httpResponse && (httpResponse.statusCode === 200 || httpResponse.statusCode === 206)) {
              if (httpResponse.statusCode === 206) {
                totalLength = parseInt(httpResponse.headers['content-range'].split('/')[1]);
                if (isNaN(totalLength)) {
                  return reject({
                    extra: 'invaildlength'
                  });
                }
              }
              if (httpResponse.statusCode === 200) {
                totalLength = body.length;
              }
              if (index === 0 && fs.existsSync(tmp)) {
                fs.unlinkSync(tmp);
              }
              return fs.appendFile(tmp, body, function(err) {
                if (err) {
                  return reject(err);
                }
                return resolve(totalLength);
              });
            } else {
              _this.error("Download failed with code: " + (httpResponse != null ? httpResponse.statusCode : void 0) + " | error: ", err, "| body: ", body);
              return reject(err != null ? err : {
                message: 'unreachable'
              });
            }
          });
        };
      })(this));
    };

    Http.prototype.error = function(msg) {
      return logger.error("Report from [http] module: " + msg);
    };

    Http.prototype.reportUpload = function(options, status, percent) {
      var category, name, node, property, src, title, _ref1;
      if (percent == null) {
        percent = 0;
      }
      node = options.node, property = options.property, name = options.name;
      (_ref1 = node.upload, title = _ref1.title), category = node.category;
      src = node[property];
      return this.emit('upload', {
        name: name,
        title: title != null ? title : src,
        src: src,
        category: category,
        percent: percent,
        status: status
      });
    };

    Http.prototype.reportDownload = function(options, status, percent) {
      var name, url;
      if (percent == null) {
        percent = 0;
      }
      url = options.url, name = options.name;
      return this.emit('download', {
        name: name,
        url: url,
        percent: percent,
        status: status
      });
    };

    return Http;

  })(EventEmitter);

  loader.register('http', new Http);

}).call(this);

(function() {
  var EventEmitter, Instruction, Promise, Q, http, loader, logger, mh, offline, path, version,
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

  Q = require('q');

  Promise = Q.Promise;

  path = require('path');

  EventEmitter = require('events').EventEmitter;

  loader = window.loader;

  offline = loader.env.config.growth.offline;

  mh = version = http = logger = null;

  process.nextTick(function() {
    var _ref;
    mh = loader.modules.messageHost;
    _ref = loader.modules, version = _ref.version, http = _ref.http, logger = _ref.logger;
    return loader.register('instruction', new Instruction);
  });

  Instruction = (function(_super) {
    __extends(Instruction, _super);

    function Instruction() {
      this.executed = false;
      if (!offline) {
        version.on('upgraded', (function(_this) {
          return function() {
            if (_this.executed) {
              return mh.post({
                event: 'upgraded'
              });
            }
          };
        })(this));
      }
    }

    Instruction.prototype.execute = function(options) {
      var _ref, _ref1;
      if (this.executed) {
        return;
      }
      logger.info("Instruction Process...");
      this.executed = true;
      version.setWebVersion(options != null ? (_ref = options.version) != null ? (_ref1 = _ref.server) != null ? _ref1.current : void 0 : void 0 : void 0);
      if (offline) {
        return;
      }
      if (version.upgraded) {
        mh.post({
          event: 'upgraded'
        });
      }
      return this.keepAlive();
    };

    Instruction.prototype.keepAlive = function() {
      if (this.trying) {
        return;
      }
      this.trying = true;
      return setInterval((function(_this) {
        return function() {
          var bp;
          if (!_this.user) {
            return;
          }
          bp = Date.now();
          return http.ping(_this.user).fin(function() {
            return mh.post({
              event: 'ping',
              status: 'alive',
              takes: Date.now() - bp
            });
          }, function(err, resp, body) {
            return mh.post({
              event: 'ping',
              status: 'lost',
              takes: Date.now() - bp,
              error: err,
              code: resp.statusCode,
              body: body
            });
          });
        };
      })(this), 30000);
    };

    Instruction.prototype.setUser = function(user) {
      this.user = user;
      logger.info("User " + this.user.ChineseName + "[" + this.user.PersonID + "] login");
      return this.emit('userchanged', this.user);
    };

    Instruction.prototype.initUser = function() {
      if (this._initUser) {
        return this._initUser;
      }
      return this._initUser = new Promise((function(_this) {
        return function(resolve) {
          return _this.once('userchanged', function(user) {
            return resolve(user);
          });
        };
      })(this));
    };

    Instruction.prototype.fileRoot = function() {
      return "../repository/" + loader.env.config.name;
    };

    Instruction.prototype.resolveUser = function() {
      return Q().then((function(_this) {
        return function() {
          if (_this.user) {
            return _this.user;
          }
          return _this.initUser();
        };
      })(this));
    };

    Instruction.prototype.resolveUserFolder = function() {
      return Q().then((function(_this) {
        return function() {
          var folder;
          folder = function(user) {
            var p;
            p = "../repository/" + loader.env.config.name + "/" + user.PersonID;
            return {
              relativePath: p,
              absolutePath: path.resolve(p).split(path.sep).join('/')
            };
          };
          if (_this.user) {
            return folder(_this.user);
          }
          if (_this.initUserFolder) {
            return _this.initUserFolder;
          }
          return _this.initUserFolder = _this.initUser().then(folder);
        };
      })(this));
    };

    return Instruction;

  })(EventEmitter);

}).call(this);

(function() {
  var MessageHost, Promise, Q, client, loader, noClient, _;

  Q = require('q');

  Promise = Q.Promise;

  _ = require('underscore');

  loader = window.loader;

  client = loader.client;

  noClient = loader.env.config.growth['no-client'];

  MessageHost = (function() {
    function MessageHost() {
      if (!noClient) {
        client.contentWindow.addEventListener("message", this.receive.bind(this), false);
      }
      this.activeSendEvents = ['upgrading', 'upgraded', 'ping'];
    }

    MessageHost.prototype.origin = "*";

    MessageHost.prototype.defaultMessage = {
      dest: 'client',
      src: 'host',
      payload: {}
    };

    MessageHost.prototype.sendEvent = function(activeEvents) {
      var events;
      if (!(activeEvents instanceof Array)) {
        activeEvents = [activeEvents];
      }
      events = this.activeSendEvents;
      return events.push.apply(events, _(activeEvents).difference(events));
    };

    MessageHost.prototype.send = function(message) {
      if (!noClient) {
        return client.contentWindow.postMessage(message, this.origin);
      }
    };

    MessageHost.prototype.receive = function(event) {
      var id, message, payload, reply;
      message = event.data;
      switch (message.dest) {
        case 'client':
          break;
        case 'host':
          id = message.id, reply = message.reply, payload = message.payload;
          return Q().then((function(_this) {
            return function() {
              if (payload instanceof Array) {
                return Q.all(payload.map(function(p) {
                  return _this.executor(p);
                }));
              } else {
                return _this.executor(payload);
              }
            };
          })(this)).then((function(_this) {
            return function(result) {
              if (reply) {
                return _this.post(result, {
                  response: true,
                  id: id,
                  reqMessage: message
                });
              }
            };
          })(this))["catch"]((function(_this) {
            return function(err) {
              var msg, stack;
              msg = err != null ? err.message : void 0;
              stack = err != null ? err.stack : void 0;
              console.log(stack != null ? stack : err);
              if (reply) {
                return _this.post(msg, {
                  response: true,
                  id: id,
                  reqMessage: message,
                  reject: true
                });
              }
            };
          })(this));
      }
    };

    MessageHost.prototype.executor = function(options) {
      var action, data, interceptor, module, promise, reject, resolve;
      action = options.action, module = options.module, data = options.data, interceptor = options.interceptor;
      promise = Q.fcall(function() {
        var moduleInstance;
        moduleInstance = loader.modules[module];
        if (moduleInstance != null) {
          return moduleInstance[action != null ? action : 'execute'].apply(moduleInstance, data);
        } else {
          return console.log(data);
        }
      });
      if (interceptor) {
        resolve = interceptor.resolve, reject = interceptor.reject;
        if (resolve) {
          promise = promise.then((function(_this) {
            return function() {
              return _this.executor(resolve);
            };
          })(this));
        }
        if (reject) {
          promise = promise["catch"]((function(_this) {
            return function() {
              return _this.executor(reject);
            };
          })(this));
        }
      }
      return promise;
    };

    MessageHost.prototype.post = function(data, message) {
      if (message == null) {
        message = {};
      }
      message = _.extend(message, this.defaultMessage);
      this.intercept(data);
      if (!message.response && !_(this.activeSendEvents).contains(data.event)) {
        return;
      }
      message.payload = data;
      return this.send(message);
    };

    MessageHost.prototype.intercept = function(data) {
      var interceptor;
      if (data == null) {
        data = {};
      }
      interceptor = data.interceptor;
      if (interceptor) {
        return this.executor(interceptor);
      }
    };

    MessageHost.prototype.reportPercentHandler = function(options) {
      var lastPercent;
      lastPercent = -1;
      return _.throttle((function(_this) {
        return function(percent) {
          if (lastPercent !== percent) {
            lastPercent = percent;
            return _this.post(_.extend(options, {
              status: 'process',
              percent: percent
            }));
          }
        };
      })(this), 500, {
        trailing: false
      });
    };

    MessageHost.prototype.reportTerminal = function(options) {
      return this.post(_.extend(options, {
        status: 'terminal'
      }));
    };

    return MessageHost;

  })();

  loader.register('messageHost', new MessageHost);

}).call(this);

(function() {
  var Promise, RepoManager, Repository, fs, instruction, loader, path, repoPath, _;

  Promise = (require('q')).Promise;

  _ = require('underscore');

  fs = require('fs');

  path = require('path');

  loader = window.loader;

  instruction = Repository = null;

  repoPath = "../repository/" + loader.env.config.name;

  process.nextTick(function() {
    var FileUtility, readonly, repoManager, _ref, _ref1;
    _ref = loader.namespaces, Repository = _ref.Repository, FileUtility = _ref.FileUtility;
    FileUtility.createFolder(repoPath);
    _ref1 = loader.modules, instruction = _ref1.instruction, repoManager = _ref1.repoManager;
    repoManager.initUsers();
    readonly = loader.env.config.growth.readonly;
    if (!readonly) {
      return instruction.on('userchanged', function(user) {
        return repoManager.changeUser(user);
      });
    }
  });

  RepoManager = (function() {
    function RepoManager(repoCache) {
      this.repoCache = repoCache != null ? repoCache : {};
    }

    RepoManager.prototype.initUsers = function() {
      return this.users = this.accessRepo("" + repoPath + "/users");
    };

    RepoManager.prototype.setProfile = function(data) {
      return this.resolveRepo('_profile').then(function(repo) {
        return repo.put(data);
      });
    };

    RepoManager.prototype.getProfiles = function(options) {
      var paths, profileRoot, promises, root;
      if (options == null) {
        options = {};
      }
      root = options.root;
      profileRoot = root ? "" + repoPath + "/" + root : repoPath;
      paths = fs.readdirSync(profileRoot);
      promises = paths.map(function(p) {
        return "" + profileRoot + "/" + p;
      }).filter(function(p) {
        return fs.statSync(p).isDirectory() && fs.existsSync("" + p + "/_profile");
      }).map((function(_this) {
        return function(p) {
          return _this.accessRepo("" + p + "/_profile").find({}).then(function(data) {
            if (data[0]) {
              if (data[0].id !== p.split('/').pop()) {
                console.warn("Profile [" + data[0].id + "] in " + (p.split('/').pop()));
              }
              data[0].subFolders = fs.readdirSync(p).filter(function(sp) {
                var osp;
                osp = "" + p + "/" + sp;
                return fs.statSync(osp).isDirectory() && fs.existsSync("" + osp + "/fileLocal");
              });
            }
            return data[0];
          });
        };
      })(this));
      return Promise.all(promises).then(function(list) {
        return list.filter(function(i) {
          return i;
        });
      });
    };

    RepoManager.prototype.changeUser = function(user) {
      var dump;
      if (user) {
        dump = _.clone(user);
        dump.id = dump.PersonID;
        dump.loginAt = Date.now();
        return this.users.put(dump);
      }
    };

    RepoManager.prototype.lastUser = function() {
      return this.users.getTransaction().then(function(db) {
        return new Promise(function(resolve, reject) {
          return db.find({}, {
            _id: 0
          }).sort({
            loginAt: -1
          }).limit(1).exec(function(err, docs) {
            if (err) {
              return reject(err);
            }
            return resolve(docs[0]);
          });
        });
      });
    };

    RepoManager.prototype.reset = function() {
      return this.repoCache = {};
    };

    RepoManager.prototype.resolveRepo = function(name) {
      return instruction.resolveUser().then((function(_this) {
        return function(user) {
          return _this.accessRepo("" + repoPath + "/" + user.PersonID + "/" + name);
        };
      })(this));
    };

    RepoManager.prototype.accessRepo = function(p) {
      if (this.repoCache[p]) {
        return this.repoCache[p];
      }
      return this.repoCache[p] = new Repository({
        filename: p
      });
    };

    RepoManager.prototype.find = function(name, options) {
      var repo;
      repo = this.accessRepo(name);
      return repo.find(options);
    };

    RepoManager.prototype.patch = function(name, obj) {
      var repo;
      repo = this.accessRepo(name);
      return repo.patch(obj);
    };

    RepoManager.prototype.put = function(name, obj) {
      var repo;
      repo = this.accessRepo(name);
      return repo.put(obj);
    };

    RepoManager.prototype.remove = function(name, id) {
      var repo;
      repo = this.accessRepo(name);
      return repo.remove(id);
    };

    return RepoManager;

  })();

  loader.register('repoManager', new RepoManager);

}).call(this);

(function() {
  var Datastore, Promise, Q, Repository, fs, loader, path, readonly;

  path = require('path');

  Datastore = require('nedb');

  Q = require('q');

  Promise = Q.Promise;

  fs = require('fs');

  loader = window.loader;

  readonly = loader.env.config.growth.readonly;

  loader.namespaces.Repository = Repository = (function() {
    Repository.prototype.idAttr = 'id';

    function Repository(options) {
      var name;
      name = options.filename;
      if (readonly) {
        this.db = new Datastore({
          filename: name,
          inMemoryOnly: true
        });
        this.memoryOnly = true;
      } else {
        this.db = new Datastore(name);
      }
    }

    Repository.prototype.getTransaction = function() {
      if (this.transaction) {
        return this.transaction;
      }
      return this.transaction = new Promise((function(_this) {
        return function(resolve, reject) {
          var filename;
          if (readonly) {
            filename = _this.db.persistence.filename;
            if (fs.existsSync(filename)) {
              return fs.readFile(filename, {
                encoding: 'utf-8'
              }, function(err, data) {
                return _this.db.insert(_this.db.persistence.treatRawData(data).data, function(err) {
                  return resolve(_this.db);
                });
              });
            } else {
              return resolve(_this.db);
            }
          } else {
            return _this.db.loadDatabase(function(err) {
              if (err) {
                return reject(err);
              }
              return resolve(_this.db);
            });
          }
        };
      })(this));
    };

    Repository.prototype.resolveNeId = function(obj) {
      var id;
      id = obj[this.idAttr];
      if (id) {
        delete obj[this.idAttr];
        obj._id = id;
      }
      return obj;
    };

    Repository.prototype.resolveNormalId = function(obj) {
      var id;
      id = obj._id;
      delete obj._id;
      obj[this.idAttr] = id;
      return obj;
    };

    Repository.prototype.find = function(options, projections) {
      if (options == null) {
        options = {};
      }
      this.resolveNeId(options);
      return this.getTransaction().then((function(_this) {
        return function(db) {
          return new Promise(function(resolve, reject) {
            var handle;
            handle = function(err, docs) {
              if (err) {
                return reject(err);
              }
              return resolve(docs.map(function(d) {
                return _this.resolveNormalId(d);
              }));
            };
            if (projections) {
              return db.find(options, projections, handle);
            } else {
              return db.find(options, handle);
            }
          });
        };
      })(this));
    };

    Repository.prototype.put = function(obj) {
      this.resolveNeId(obj);
      return this.getTransaction().then((function(_this) {
        return function(db) {
          return new Promise(function(resolve, reject) {
            return db.update({
              _id: obj._id
            }, obj, {
              upsert: true
            }, function(err) {
              if (err) {
                return reject(err);
              }
              return resolve();
            });
          });
        };
      })(this));
    };

    Repository.prototype.patch = function(obj) {
      this.resolveNeId(obj);
      return this.getTransaction().then((function(_this) {
        return function(db) {
          return new Promise(function(resolve, reject) {
            return db.update({
              _id: obj._id
            }, {
              $set: obj
            }, {
              upsert: true
            }, function(err) {
              if (err) {
                return reject(err);
              }
              return resolve();
            });
          });
        };
      })(this));
    };

    Repository.prototype.remove = function(id) {
      return this.getTransaction().then(function(db) {
        return new Promise(function(resolve, reject) {
          return db.remove({
            _id: id
          }, {
            multi: true
          }, function(err) {
            if (err) {
              return reject(err);
            }
            return resolve();
          });
        });
      });
    };

    Repository.prototype.checkWriteable = function() {
      if (!readonly || this.memoryOnly) {
        return {
          permitted: true
        };
      }
      return {
        permitted: false,
        rej: Q.fcall(function() {
          throw {
            message: 'In readonly mode'
          };
        })
      };
    };

    return Repository;

  })();

}).call(this);

(function() {
  var Splash, splash;

  splash = document.getElementById('splash');

  Splash = (function() {
    function Splash() {}

    Splash.prototype.hide = function() {
      if (splash) {
        return splash.style.display = 'none';
      }
    };

    return Splash;

  })();

  window.loader.register('splash', new Splash);

}).call(this);

(function() {
  var Promise, Store, idb, _;

  idb = require('idb-wrapper');

  _ = require('underscore');

  Promise = (require('q')).Promise;

  loader.namespaces.Store = Store = (function() {
    function Store(options) {
      this.options = options;
      this.getTransaction();
    }

    Store.prototype.getTransaction = function() {
      if (this.transaction) {
        return this.transaction;
      }
      return this.transaction = new Promise((function(_this) {
        return function(resolve, reject) {
          var db;
          return db = new idb(_.extend({
            onStoreReady: function() {
              return resolve(db);
            },
            onError: function() {
              return reject.apply(null, arguments);
            }
          }, _this.options));
        };
      })(this));
    };

    Store.prototype.wrapByPromise = function(request, options, args) {
      args = Array.prototype.slice.call(args);
      return new Promise(function(resolve, reject) {
        ['resolve', 'reject'].forEach(function(method) {
          var index;
          index = options[method];
          if (index == null) {
            return true;
          }
          switch (method) {
            case 'resolve':
              args.splice(options[method], 0, function() {
                return resolve.apply(null, arguments);
              });
              break;
            case 'reject':
              args.splice(options[method], 0, function() {
                return reject.apply(null, arguments);
              });
          }
          return true;
        });
        return request.apply(null, args);
      });
    };

    Store.prototype.request = function(method, options, args) {
      if (args == null) {
        args = [];
      }
      return this.getTransaction().then((function(_this) {
        return function(db) {
          return _this.wrapByPromise(db[method].bind(db), options, args);
        };
      })(this));
    };

    Store.prototype.put = function() {
      return this.request('put', {
        resolve: 1,
        reject: 2
      }, arguments).then((function(_this) {
        return function(id) {
          return _this.get(id);
        };
      })(this));
    };

    Store.prototype.getAll = function() {
      return this.request('getAll', {
        resolve: 0,
        reject: 1
      });
    };

    Store.prototype.get = function() {
      return this.request('get', {
        resolve: 1,
        reject: 2
      }, arguments);
    };

    Store.prototype.remove = function() {
      return this.request('remove', {
        resolve: 1,
        reject: 2
      }, arguments);
    };

    Store.prototype.where = function(properties) {
      var matched;
      matched = _.matches(properties);
      return this.getTransaction().then((function(_this) {
        return function(db) {
          var result;
          result = [];
          return new Promise(function(resolve, reject) {
            return db.iterate(function(obj, cursor) {
              if ((obj != null) && matched(obj)) {
                return result.push(obj);
              }
            }, {
              onEnd: function() {
                return resolve(result);
              },
              onError: function() {
                return reject.apply(arguments);
              }
            });
          });
        };
      })(this));
    };

    Store.prototype.filter = function(predicate, context) {
      if (context == null) {
        context = null;
      }
      return this.getTransaction().then((function(_this) {
        return function(db) {
          var result;
          result = [];
          return new Promise(function(resolve, reject) {
            return db.iterate(function(obj, cursor) {
              if (predicate.apply(context, arguments)) {
                return result.push(obj);
              }
            }, {
              onEnd: function() {
                return resolve(result);
              },
              onError: function() {
                return reject.apply(arguments);
              }
            });
          });
        };
      })(this));
    };

    Store.prototype.querySingle = function(options) {
      var index, value;
      index = options.index, value = options.value;
      return this.getTransaction().then((function(_this) {
        return function(db) {
          return new Promise(function(resolve, reject) {
            return db.query(function() {
              return resolve.apply(null, arguments);
            }, {
              index: index,
              filterDuplicates: true,
              keyRange: db.makeKeyRange({
                lower: value,
                upper: value
              }),
              onError: function() {
                return reject(arguments);
              }
            });
          });
        };
      })(this));
    };

    Store.prototype.clear = function() {
      return this.request('clear', {
        resolve: 0,
        reject: 1
      });
    };

    return Store;

  })();

}).call(this);

(function() {
  var Store, UserManager, crypto, decrypt, encrypt, secret;

  crypto = require('crypto');

  Store = loader.namespaces.Store;

  secret = 'bhyf';

  encrypt = function(text) {
    var cipher, crypted;
    cipher = crypto.createCipher('aes-256-cbc', secret);
    crypted = cipher.update(text, 'utf8', 'hex');
    crypted += cipher.final('hex');
    return crypted;
  };

  decrypt = function(text) {
    var dec, decipher;
    decipher = crypto.createDecipher('aes-256-cbc', secret);
    dec = decipher.update(text, 'hex', 'utf8');
    dec += decipher.final('utf8');
    return dec;
  };

  UserManager = (function() {
    function UserManager() {
      this.store = new Store({
        storeName: 'growth-user',
        indexes: [
          {
            name: 'name',
            keyPath: 'name',
            unique: true
          }, {
            name: 'personId',
            keyPath: 'personId',
            unique: true
          }
        ]
      });
    }

    UserManager.prototype.execute = function() {
      return console.log(arguments);
    };

    UserManager.prototype.put = function(obj) {
      if (obj.password) {
        obj.password = encrypt(obj.password);
      }
      return this.store.put(obj);
    };

    UserManager.prototype.getAll = function() {
      return this.store.getAll().then(function(list) {
        return list.map(function(i) {
          if (i.password) {
            i.password = decrypt(i.password);
          }
          return i;
        });
      });
    };

    UserManager.prototype.remove = function(id) {
      return this.store.remove(id);
    };

    return UserManager;

  })();

  loader.register('userManager', new UserManager);

}).call(this);

(function() {
  var EventEmitter, FileUtility, Promise, Q, Utility, Version, cfg, client, clientServer, clientUpgradeServer, compareInt, fs, isClientLocal, loader, logger, nodeReq, offline, packagePath, parseIntOrDefault, pkgMap, pkgPath, readonly, unzip, version, _, _ref,
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

  fs = require('fs');

  nodeReq = require('request');

  Q = require('q');

  Promise = Q.Promise;

  _ = require('underscore');

  unzip = require('unzip');

  EventEmitter = require('events').EventEmitter;

  loader = window.loader;

  _ref = loader.namespaces, Utility = _ref.Utility, FileUtility = _ref.FileUtility;

  logger = loader.modules.logger;

  cfg = loader.env.config.growth;

  version = cfg.version, client = cfg.client, isClientLocal = cfg['is-client-local'], clientUpgradeServer = cfg['client-upgrade-server'], clientServer = cfg['client-server'], offline = cfg.offline, readonly = cfg.readonly;

  if (clientUpgradeServer == null) {
    clientUpgradeServer = clientServer;
  }

  packagePath = "" + client + "/upgrade.zip";

  pkgPath = {
    client: 'package',
    server: 'update'
  };

  pkgMap = (function() {
    return {
      client: {
        version: version,
        manifest: "http://" + clientUpgradeServer + "/" + pkgPath['client'] + "/" + client + "/manifest.json",
        upgradePackage: "http://" + clientUpgradeServer + "/" + pkgPath['client'] + "/" + packagePath,
        localPackagePath: "../" + packagePath,
        extract: '../'
      },
      server: {
        manifest: "http://" + clientUpgradeServer + "/" + pkgPath['server'] + "/" + client + "/manifest.json",
        upgradePackage: "http://" + clientUpgradeServer + "/" + pkgPath['server'] + "/" + packagePath,
        localPackagePath: "../../server/" + packagePath,
        extract: '../../server/'
      }
    };
  })();

  parseIntOrDefault = function(i) {
    var result;
    result = parseInt(i);
    if (isNaN(result)) {
      result = 0;
    }
    return result;
  };

  compareInt = function(i, oi) {
    if (i === oi) {
      return 0;
    }
    if (i > oi) {
      return 1;
    } else {
      return -1;
    }
  };

  Version = (function(_super) {
    __extends(Version, _super);

    function Version() {
      return Version.__super__.constructor.apply(this, arguments);
    }

    Version.prototype.report = function() {
      return logger.info("Current version is [" + version + "]");
    };

    Version.prototype.setWebVersion = function(version) {
      this.webVersion = version;
      logger.info("Web version is [*" + version + "*]");
      if (isClientLocal && !offline) {
        return this.upgrade({
          target: 'server',
          currentVer: this.webVersion
        });
      }
    };

    Version.prototype.get = function(now) {
      if (now == null) {
        now = false;
      }
      if ((now && !this.manifest) || offline) {
        return {
          current: version,
          option: {
            readonly: readonly,
            offline: offline
          }
        };
      }
      return this.fetch().then((function(_this) {
        return function() {
          return {
            current: version,
            remote: _this.manifest.version,
            minimum: _this.manifest.minimum,
            dependencies: _this.manifest.dependencies,
            option: {
              readonly: readonly,
              offline: offline
            }
          };
        };
      })(this));
    };

    Version.prototype.compare = function(v, ov) {
      var length, result, _i, _ref1, _results;
      v = _(v.split('.')).map(parseIntOrDefault);
      ov = _(ov.split('.')).map(parseIntOrDefault);
      length = _([v.length, ov.length]).min();
      if (length < 1) {
        return 0;
      }
      result = 0;
      (function() {
        _results = [];
        for (var _i = 0, _ref1 = length - 1; 0 <= _ref1 ? _i <= _ref1 : _i >= _ref1; 0 <= _ref1 ? _i++ : _i--){ _results.push(_i); }
        return _results;
      }).apply(this).forEach(function(i) {
        if (result === 0) {
          return result = compareInt(v[i], ov[i]);
        }
      });
      if (result === 0 && v.length !== ov.length) {
        result = compareInt(v.length, ov.length);
      }
      return result;
    };

    Version.prototype.fetch = function() {
      var _ref1;
      return (_ref1 = this.fetchHandle) != null ? _ref1 : this.fetchHandle = this._fetch('client');
    };

    Version.prototype.fetchServer = function() {
      var _ref1;
      return (_ref1 = this.fetchServerHandle) != null ? _ref1 : this.fetchServerHandle = this._fetch('server');
    };

    Version.prototype._fetch = function(target) {
      var manifest;
      manifest = pkgMap[target].manifest;
      return new Promise((function(_this) {
        return function(resolve, reject) {
          return nodeReq.get({
            url: manifest
          }, function(err, resp, body) {
            if (err || resp.statusCode === 404) {
              reject(err);
              return console.error("Cannot fetch " + target + " remote version: " + err);
            }
            manifest = JSON.parse(body);
            if (target === 'client') {
              _this.manifest = manifest;
            }
            return resolve(manifest);
          });
        };
      })(this));
    };

    Version.prototype.upgrade = function(options) {
      var currentVer, extract, fetchHandle, info, localPackagePath, target;
      if (options == null) {
        options = {};
      }
      if (offline) {
        return false;
      }
      target = options.target, currentVer = options.currentVer;
      if (target == null) {
        target = 'client';
      }
      info = pkgMap[target];
      if (currentVer == null) {
        currentVer = pkgMap[target].version;
      }
      localPackagePath = info.localPackagePath, extract = info.extract;
      fetchHandle = target === 'client' ? this.fetch() : this.fetchServer();
      return fetchHandle.then((function(_this) {
        return function(data) {
          console.log("Remote " + target + " version is [" + data.version + "]");
          if (currentVer && _this.compare(currentVer, data.version) < 0) {
            console.log("Upgrade " + target + "...");
            return _this._upgrade(target).then(function() {
              console.log("Download " + target + " successfully");
              return Utility.delay(5000).then(function() {
                return fs.createReadStream(localPackagePath).pipe(unzip.Extract({
                  path: extract
                })).on('close', function() {
                  _this.upgraded = true;
                  _this.emit('upgraded', data.version);
                  console.log("Upgrade " + target + " successfully");
                  return FileUtility.destroy(localPackagePath);
                });
              });
            })["catch"](function() {
              return FileUtility.destroy(localPackagePath);
            });
          }
        };
      })(this));
    };

    Version.prototype._upgrade = function(target) {
      var localPackagePath, upgradePackage, _ref1;
      _ref1 = pkgMap[target], localPackagePath = _ref1.localPackagePath, upgradePackage = _ref1.upgradePackage;
      return new Promise(function(resolve, reject) {
        var error, fsws;
        error = null;
        fsws = fs.createWriteStream(localPackagePath);
        return nodeReq.get(upgradePackage).on('response', function(resp) {
          if (resp.statusCode !== 200) {
            console.error("Cannot get upgrade package: " + resp.statusCode);
            return error = 'Response code error';
          }
        }).on('end', function() {
          if (error) {
            return reject(error);
          } else {
            return resolve();
          }
        }).on('error', function(err) {
          console.error("Cannot get upgrade package: " + err);
          error = err;
          return fsws.end();
        }).pipe(fsws);
      });
    };

    return Version;

  })(EventEmitter);

  loader.register('version', new Version);

}).call(this);

(function() {
  var Promise, Q, loader, _;

  Q = require('q');

  Promise = Q.Promise;

  _ = require('underscore');

  loader = window.loader;

  process.nextTick(function() {
    var fileManager, http, instruction, logger, messageHost, rm, setting, version, _ref;
    _ref = loader.modules, version = _ref.version, fileManager = _ref.fileManager, setting = _ref.setting, instruction = _ref.instruction, http = _ref.http, messageHost = _ref.messageHost, logger = _ref.logger, rm = _ref.repoManager;
    version.report();
    version.upgrade();
    http.on('upload', function(data) {
      return messageHost.post(_.extend({
        event: 'upload'
      }, data));
    });
    http.on('download', function(data) {
      return messageHost.post(_.extend({
        event: 'download'
      }, data));
    });
    return Q().then(function() {
      return fileManager.resetStore();
    }).then(function() {
      logger.info('Recover file task');
      return fileManager.recover();
    });
  });

}).call(this);

(function() {
  var Promise, Q, fs, loader, _;

  loader = window.loader;

  if (!loader.env.config.growth.test) {
    return;
  }

  Q = require('q');

  Promise = Q.Promise;

  _ = require('underscore');

  fs = require('fs');

  process.nextTick(function() {
    var FFmpeg, Repository, Store, Utility, fm, http, instruction, logger, messageHost, rm, setting, version, _ref, _ref1;
    _ref = loader.modules, fm = _ref.fileManager, http = _ref.http, version = _ref.version, logger = _ref.logger, setting = _ref.setting, messageHost = _ref.messageHost, rm = _ref.repoManager, instruction = _ref.instruction;
    return _ref1 = loader.namespaces, FFmpeg = _ref1.FFmpeg, Utility = _ref1.Utility, Store = _ref1.Store, Repository = _ref1.Repository, _ref1;
  });

}).call(this);
