         @_items.splice(--index, 1) if exists == 0
     return
 
+  ###*
+  @method
+    Build sketch
+  @param {boolean} [force=false]
+    Force build all files
+  @param {function(string,number,Error)} [progress=null]
+    Hook function for show progress
+  @return {Promise}
+    Promise object
+  ###
+  build: (force = false, progress = null) ->
+    buildItems = (item for item in @_items when item.engine?)
+    done = 0
+    return buildItems.reduce(
+      (promise, item) =>
+        return promise.then(=>
+          engine = item.engine
+          progress?(item.path, (100 * done / buildItems.length))
+          return engine.build(this, item).catch((error) =>
+            progress?(item.path, null, error)
+            return Promise.reject(error)
+          )
+        ).then(=>
+          progress?(item.path, (100 * ++done / buildItems.length))
+          return
+        )
+      Promise.resolve()
+    ) # return buildItems.reduce()
+
+  ###*
+  @method
+    Transfer sketch (Rubic->Board)
+  @param {boolean} [force=false]
+    Force download all files
+  @param {function(string,number,Error)} [progress=null]
+    Hook function for show progress
+  @return {Promise}
+    Promise object
+  ###
+  transfer: (force = false, progress = null) ->
+    return Promise.reject(Error("No board")) unless @_board?
+    transferItems = (item for item in @_items when item.transfer)
+    boardFs = null
+    done = 0
+    writeData = null
+    return transferItems.reduce(
+      (promise, item) =>
+        return promise.then(=>
+          progress?(item.path, (100 * done / transferItems.length))
+          return @_dirFs.readFile(item.path).catch((error) =>
+            progress?(item.path, null, error)
+            return Promise.reject(error)
+          )
+        ).then((readData) =>
+          writeData = readData
+          return if force # Skip readback when force==true
+          return if item.alreadyTransfered
+          return boardFs.readFile(item.path).catch(=>
+            return  # Ignore errors on readFile()
+          )
+        ).then((compareData) =>
+          return if !force and item.alreadyTransfered
+          return if !force and compareData? and arrayEqual(
+            new Uint8Array(writeData)
+            new Uint8Array(compareData)
+          )
+          return boardFs.writeFile(item.path, data)
+        ).then(=>
+          progress?(item.path, (100 * ++done / transferItems.length))
+          return
+        )
+      @_board.requestFileSystem().then((fs) =>
+        boardFs = fs
+        return
+      )
+    ) # return transferItems.reduce()
+
   #--------------------------------------------------------------------------------
   # Protected methods
   #

      return sketch
    ).catch(=>
      return I18n.rejectPromise("Invalid_sketch")
    )

  ###*
  @method

    @_items.splice(index, 1)
    @_modify()
    @dispatchEvent({type: "removeItem", item: itemRemoved})
    return true

  ###*
  @method
