docs: function zip_dir(dir, zipped_dir) {
  
      var deferred = Q.defer();
  
      fs.readdir(dir, function (err, entries) {
  
          if (err) {
              deferred.reject(err);
              return;
          }
  
          var entries_paths = entries.map(function (entry) {
              return path.normalize(dir + path.sep + entry);
          });
  
          async.map(entries_paths, fs.stat, function (err, stats) {
  
              if(err) {
                  deferred.reject(err);
                  return;
              }
  
              var entries_count = entries_paths.length;
  
              // construct a an array of objects each contain an with-parent entry and its type
              var typed_entries = Array(entries_count);
              for (var i = 0; i < entries_count; i++) {
  
                  typed_entries[i] = {
                      path: entries_paths[i],
                      type: stats[i].isDirectory() ? 'dir' : 'file'
                  }
              }
  
              async.each(typed_entries, function (entry, callback) {
  
                  var parsed_entry_path = path.parse(entry.path);
  
                  if (entry.type === 'dir') {
  
                      var new_zipped_dir = zipped_dir.folder(parsed_entry_path.base);
  
                      // recursively zip the newly found dir
                      Q.fcall(zip_dir, entry.path, new_zipped_dir).then(function () {
                          //the end of this iteration
                          callback();
                      })
                      .catch(function(error) {
                          callback(error);
                      }).done();
                  }
                  else {
  
                      fs.readFile(entry.path, function (err, data) {
  
                          if (err) {
                              callback(err);
                              return;
                          }
  
                          //zip the file within the current subdir
                          zipped_dir.file(parsed_entry_path.base, data);
  
                          // the end of this iteration
                          callback();
                      });
                  }
  
              }, function (err) {
  
                  // here all iterations are over
                  if (err)
                      deferred.reject(err);
                  else
                      // resolve the deferred and fullfil the promise
                      deferred.resolve();
              });
          });
      });
  
      return deferred.promise;
  }