Initialize paths in constructor

Initialize paths in constructor

Previously this was done at eval time which
required globals to be set before the class could
be required.

--- src/config.coffee
+++ src/config.coffee
@@ -8,12 +8,6 @@
 pathWatcher = require 'pathwatcher'

 configDirPath = fsUtils.absolute("~/.atom")
-nodeModulesDirPath = path.join(resourcePath, "node_modules")
-bundledKeymapsDirPath = path.join(resourcePath, "keymaps")
-userPackagesDirPath = path.join(configDirPath, "packages")
-userPackageDirPaths = [userPackagesDirPath]
-userPackageDirPaths.unshift(path.join(configDirPath, "dev", "packages")) if atom.getLoadSettings().devMode
-userStoragePath = path.join(configDirPath, "storage")

 # Public: Used to access all of Atom's configuration details.
 #
@@ -36,23 +30,25 @@
 class Config
   _.extend @prototype, EventEmitter

-  configDirPath: configDirPath
-  bundledPackageDirPaths: [nodeModulesDirPath]
-  bundledKeymapsDirPath: bundledKeymapsDirPath
-  nodeModulesDirPath: nodeModulesDirPath
-  packageDirPaths: _.clone(userPackageDirPaths)
-  userPackageDirPaths: userPackageDirPaths
-  userStoragePath: userStoragePath
-  lessSearchPaths: [
-    path.join(resourcePath, 'static', 'variables')
-    path.join(resourcePath, 'static')
-  ]
   defaultSettings: null
   settings: null
   configFileHasErrors: null

   # Private: Created during initialization, available as `global.config`
   constructor: ->
+    @configDirPath = configDirPath
+    @bundledKeymapsDirPath = path.join(resourcePath, "keymaps")
+    @nodeModulesDirPath = path.join(resourcePath, "node_modules")
+    @bundledPackageDirPaths = [@nodeModulesDirPath]
+    @lessSearchPaths = [
+      path.join(resourcePath, 'static', 'variables')
+      path.join(resourcePath, 'static')
+    ]
+    @packageDirPaths = [path.join(configDirPath, "packages")]
+    if atom.getLoadSettings().devMode
+      @packageDirPaths.unshift(path.join(configDirPath, "dev", "packages"))
+    @userStoragePath = path.join(configDirPath, "storage")
+
     @defaultSettings =
       core: _.clone(require('./root-view').configDefaults)
       editor: _.clone(require('./editor').configDefaults)


rework access control

rework access control

--- src/factories/access-control.coffee
+++ src/factories/access-control.coffee
@@ -1,30 +1,3 @@
-module.exports.rightsStringToRightsArray = (
-) ->
-  (string) ->
-    string
-      .split('\n')
-      # remove leading and trailing whitespace
-      .map((x) -> x.trim())
-      # remove empty lines
-      .filter((x) -> x isnt '')
-      # remove comments
-      .filter((x) -> x.charAt(0) isnt '#')
-
-module.exports.rightsArrayToRightsObject = (
-) ->
-  (array) ->
-    result = {}
-    array.forEach (x) ->
-      result[x] = true
-    return result
-
-module.exports.rightsStringToRightsObject = (
-  rightsStringToRightsArray
-  rightsArrayToRightsObject
-) ->
-  (string) ->
-    rightsArrayToRightsObject rightsStringToRightsArray string
-
 module.exports.currentUser = (
   token
   firstUserWhereId
@@ -38,6 +11,42 @@
     unless user?
       return null
     _.omit user, 'password'
+
+module.exports.rightsStringToRightsArray = (
+  _
+) ->
+  (string) ->
+    results = string
+      .split('\n')
+      # remove leading and trailing whitespace
+      .map((x) -> x.trim())
+      # remove empty lines
+      .filter((x) -> x isnt '')
+      # remove comments
+      .filter((x) -> x.charAt(0) isnt '#')
+    # remove duplicates
+    return _.uniq results
+
+module.exports.rightsArrayToRightsObject = (
+  parseRight
+) ->
+  (rightsArray) ->
+    rightsObject = {}
+    rightsArray.forEach (string) ->
+      right = parseRight string
+      # we ignore invalid permission strings right now
+      if right?
+        unless rightsObject[right.name]?
+          rightsObject[right.name] = []
+        rightsObject[right.name].push right.args
+    return rightsObject
+
+module.exports.rightsStringToRightsObject = (
+  rightsStringToRightsArray
+  rightsArrayToRightsObject
+) ->
+  (string) ->
+    rightsArrayToRightsObject rightsStringToRightsArray string

 module.exports.currentRightsArray = (
   currentUser
@@ -57,15 +66,46 @@

   rightsStringToRightsObject currentUser.rights

+module.exports.tryCoerceNumber = (
+) ->
+  (value) ->
+    unless 'string' is typeof value
+      return value
+    maybeNumber = parseInt value, 10
+    if isNaN maybeNumber
+      return value
+    if maybeNumber.toString() isnt value
+      return value
+    return maybeNumber
+
 module.exports.currentUserHasRight = (
   currentRightsObject
   isjs
+  tryCoerceNumber
   _
 ) ->
   (right, args...) ->
-    filteredArgs = _.filter args, isjs.not.undefined
-    result = if filteredArgs.length is 0
-      currentRightsObject[right]? or currentRightsObject[right + '()']?
-    else
-      currentRightsObject[right + '(' + filteredArgs.join(',') + ')']?
-    return result
+    # filteredArgs = _.filter args, isjs.not.undefined
+
+    args = args.map tryCoerceNumber
+    rightArgsArray = currentRightsObject[right]
+    # console.log 'currentUserHasRight',
+    #   right: right
+    #   args: args
+    #   currentRightsObject: currentRightsObject
+    #   rightArgsArray: rightArgsArray
+    unless rightArgsArray?
+      return false
+    _.some rightArgsArray, (rightArgs) ->
+      # console.log 'equal',
+      #   right: right
+      #   args: args
+      #   rightArgs: rightArgs
+      #   equal: _.isEqual args, rightArgs
+      _.isEqual args, rightArgs
+
+module.exports.currentUserRightArgs = (
+  currentRightsObject
+) ->
+  (right) ->
+    currentRightsObject[right]


"Prevent browser from caching ajax calls to plunker"

--- assets/js/models/plunks.coffee
+++ assets/js/models/plunks.coffee
@@ -16,6 +16,7 @@
     sync: (method, model, options) ->
       params = _.extend {}, options,
         url: @url()
+        cache: false
         dataType: "json"

       switch method


- Check whether changes reflect.

- Check whether changes reflect.

--- src/javascripts/math_buttons.coffee
+++ src/javascripts/math_buttons.coffee
@@ -16,7 +16,7 @@
   decimal: (opts)->
     @button({
       value: "."
-      class: "jc--button jc--button-decimal"
+      class: "jc--button jc--button-decimal decimalButton"
     }, opts)

   negative: (opts)->
@@ -30,7 +30,7 @@
   addition: (opts)->
     @button({
       value: "+"
-      class: "jc--button jc--button-operation jc--button-add"
+      class: "jc--button jc--button-operation jc--button-add addButton"
     }, opts)

   subtraction: (opts)->


Remove the max call

Remove the max call

--- src/cursor.coffee
+++ src/cursor.coffee
@@ -281,7 +281,6 @@
           rowLength = @editor.lineTextForScreenRow(row).length
           column = rowLength - columnDelta
           columnDelta -= rowLength
-        column = Math.max(column, 0)

       @setScreenPosition({row, column})


Only use core for keymaps folder in resource path

--- lib/keybinding-panel.coffee
+++ lib/keybinding-panel.coffee
@@ -76,11 +76,11 @@
   determineSource: (filePath) ->
     return 'Unknown' unless filePath

-    pathParts = filePath.split(path.sep)
-    if _.contains(pathParts, 'node_modules') or _.contains(pathParts, 'atom') or _.contains(pathParts, 'src')
+    if filePath.indexOf(path.join(atom.getLoadSettings().resourcePath, 'keymaps')) is 0
       'Core'
     else if filePath is atom.keymap.getUserKeymapPath()
       'User'
     else
+      pathParts = filePath.split(path.sep)
       packageNameIndex = pathParts.length - 3
       pathParts[packageNameIndex]


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -22,7 +22,7 @@

   engine.each (obj, index) ->
     if index is 0
-      e
+      equal

 test "#find", ->
   engine = Engine()


Support providing a defaultLevel when in logger factory

--- LoggerFactory.coffee
+++ LoggerFactory.coffee
@@ -4,13 +4,15 @@
   @get: ->
     instance ?= new LoggerFactory

-  createLogger: (namespace)->
+  createLogger: (namespace, defaultLevel)->
     log.debug 'LoggerFactory.createLogger()', arguments
     if namespace?
       expect(namespace).to.be.a('string').that.has.length.above(0)
       prefix = namespace + ':'
     expect(Loglevel).to.be.a 'function'
-    return Loglevel(prefix)
+    logger = Loglevel(prefix)
+    logger.setLevel(defaultLevel) if defaultLevel?
+    return logger

   createPackageLogger: (packageName)->
     return @createLogger(packageName)


UI/slideshow adding the touchscreen support

--- ui/slideshow/src/slideshow.coffee
+++ ui/slideshow/src/slideshow.coffee
@@ -28,9 +28,26 @@
       @prev_button = new Icon(class: 'lui-icon-previous2').on('click', => @previous()),
       @next_button = new Icon(class: 'lui-icon-next2').on('click', => @next()))

+    if typeof(window.ontouchstart) isnt 'undefined'
+      @prev_button.remove(); @next_button.remove();
+
     @on
       mouseenter: => @__hovering = true
       mouseleave: => @__hovering = false
+      touchstart: (event)=>
+        @__touchstart = event.position().x
+      touchmove: (event)=>
+        return if @__sliding
+        x_position = event.position().x
+        threshold  = 20
+
+        if (x_position - @__touchstart) > threshold
+          @previous()
+          @__touchstart = x_position
+        else if (@__touchstart - x_position) > threshold
+          @next()
+          @__touchstart = x_position
+

     @append(@controls).slideTo(0)
     @play() if @options.autoplay
@@ -121,7 +138,7 @@
   #
   pause: ->
     if @_timer
-      window.clearInterval(@_timer)
+      global.clearInterval(@_timer)
       delete(@_timer)

     return @
@@ -158,7 +175,7 @@
     # animating the size change
     @animate box_size, duration: @options.fxDuration, finish: =>
       @removeClass('lui-slideshow-resizing')
-      @__sliding = false
+      global.setTimeout((=>@__sliding = false), 50)

   # calculates the end size of the whole block


Refactor drop of powerups

Refactor drop of powerups

--- src/lib/script_modules/level.coffee
+++ src/lib/script_modules/level.coffee
@@ -166,19 +166,19 @@
       @_verify(sequence)
       return WhenJS() if @_skippingToCheckpoint()
       itemSettings = @inventory(options.item)
-      item = -> Crafty.e('PowerUp').powerUp(itemSettings)
+      item = (attrs) -> Crafty.e('PowerUp').attr(attrs).powerUp(itemSettings)
       unless itemSettings
         console.warn 'Item ', options.item, ' is not known'
         return WhenJS()
       if player = options.inFrontOf
         ship = player.ship()
         if ship
-          @level.addComponent item().attr(z: -1), x: Crafty.viewport.width, y: player.ship().y + Crafty.viewport.y
+          item(z: -1, x: Crafty.viewport.width, y: player.ship().y + Crafty.viewport.y)
         else
           unless player.gameOver
             d = WhenJS.defer()
             player.entity.one 'ShipSpawned', (ship) =>
-              @level.addComponent item().attr(z: -1), x: Crafty.viewport.width, y: ship.y + Crafty.viewport.y
+              item(z: -1, x: Crafty.viewport.width, y: ship.y + Crafty.viewport.y)
               d.resolve()
             return d.promise

@@ -192,7 +192,7 @@
         else
           coords = pos

-        item().attr(x: coords.x, y: coords.y, z: -1)
+        item(x: coords.x, y: coords.y, z: -1)

   # Returns an object with information about a player
   #


Just use our own line endings

Just use our own line endings

--- lib/models/synced-fs.coffee
+++ lib/models/synced-fs.coffee
@@ -104,20 +104,19 @@
       panel.destroy()

   sendSave: (project, file, buffer) ->
-    @convertLineEndingsToUnixFormat(buffer).then =>
-      ipc.send 'fs-local-save', JSON.stringify({
-        action: 'local_save',
-        project: {
-          path: this.formatFilePath(project.getPaths()[0])
-        },
-        file: {
-          path: this.formatFilePath(file.path)
-          digest: file.digest,
-        },
-        buffer: {
-          content: window.btoa(unescape(encodeURIComponent(buffer.getText())))
-        }
-      })
+    ipc.send 'fs-local-save', JSON.stringify({
+      action: 'local_save',
+      project: {
+        path: this.formatFilePath(project.getPaths()[0])
+      },
+      file: {
+        path: this.formatFilePath(file.path)
+        digest: file.digest,
+      },
+      buffer: {
+        content: window.btoa(unescape(encodeURIComponent(@getText(buffer))))
+      }
+    })

   #formattedText: (text) ->
     #try
@@ -131,19 +130,9 @@
     else
       return path

-  convertLineEndingsToUnixFormat: (buffer) ->
-    return new Promise (resolve, reject) ->
-      format = '\n'
-      lastRowIndex = buffer.getLastRow()
-      buffer.transact ->
-        for rowIndex in [0...lastRowIndex]
-          do (rowIndex) ->
-            currEol = buffer.lineEndingForRow rowIndex
-            if currEol isnt format
-              lineEndingRange = new Range(
-                new Point(rowIndex, buffer.lineLengthForRow(rowIndex)),
-                new Point(rowIndex + 1, 0)
-              )
-              buffer.setTextInRange lineEndingRange, format,
-                { normalizeLineEndings: false }
-      resolve true
+  getText: (buffer) ->
+    text = ''
+    for rowIndex in [0...buffer.getLastRow()]
+      text += buffer.lines[rowIndex] + '\n'
+
+    return text


Extract method _save_args().

Extract method _save_args().

--- src/TinyMockJS.coffee
+++ src/TinyMockJS.coffee
@@ -39,7 +39,7 @@
   #
   args: (args...) ->
     _check_args_usage(@, args...)
-    @_args = args
+    _save_args(@, args)
     @

   #
@@ -231,6 +231,9 @@

 _set_args_for_current_expectation = (mock, args) ->
   _current_expectation(mock)._args = args
+
+_save_args = (expectation, args) ->
+  expectation._args = args

 _set_return_for_current_expectation = (mock, value) ->
   _current_expectation(mock).returns = value


ComputeController::info to get real information about machine, it starts listening corresponding events from kloud when needed

--- client/Main/providers/computecontroller.coffee
+++ client/Main/providers/computecontroller.coffee
@@ -90,3 +90,31 @@
     .catch (err)->
       warn "build err:", err

+
+  info: (machine)->
+
+    log "[info]", machine
+
+    # If machine state is NotInitialized or Terminated
+    # we don't need to ask info to kloud kite.
+    { NotInitialized, Terminated, Building } = Machine.State
+    if machine.status.state in [ NotInitialized, Terminated ]
+      @emit "public-#{machine._id}", { status: machine.status.state }
+      return Promise.resolve()
+
+    if machine.status.state is Building
+      log "state is building, start polling"
+      @eventListener.addListener 'build', machine._id
+      return Promise.resolve()
+
+
+    @kloud.info { machineId: machine._id }
+
+    .then (res)=>
+
+      log "info res:", res
+      @emit "public-#{machine._id}", { status: res.State }
+
+    .catch (err)->
+      warn "info err:", err
+


MachineStateModal: change method orders

MachineStateModal: change method orders

--- client/Main/providers/machinestatemodal.coffee
+++ client/Main/providers/machinestatemodal.coffee
@@ -175,6 +175,48 @@

     else
       @buildViews()
+
+
+  buildVerifyView: ->
+
+    @container.destroySubViews()
+
+    @codeEntryView = new KDHitEnterInputView
+      type         : 'text'
+      cssClass     : 'verify-pin-input'
+      placeholder  : 'Enter code here'
+      callback     : @bound 'verifyAccount'
+
+    @button    = new KDButtonView
+      title    : 'Verify account'
+      cssClass : 'solid green medium'
+      callback : @bound 'verifyAccount'
+
+    @container.addSubView new KDCustomHTMLView
+      cssClass : 'verify-message'
+      partial  : """
+
Before you can access your VM, we need to verify your account.
+        A verification email should already be in your inbox.
+        If you did not receive it yet, you can request a new code.

+      """
+      click    : (event)=>
+
+        return  unless $(event.target).is 'cite'
+
+        KD.remote.api.JUser.verifyByPin resendIfExists: yes, (err)=>
+
+          unless KD.showError err
+
+            @container.addSubView @retryView = new KDCustomHTMLView
+              cssClass : 'error-message warning'
+              partial  : """
+
Email sent, please check your inbox.

+              """
+
+            KD.utils.wait 3000, @retryView.bound 'destroy'
+
+    @container.addSubView @codeEntryView
+    @container.addSubView @button

   buildViews: (response)->
@@ -260,49 +302,6 @@
         height   : 40

     @container.addSubView @loader
-
-
-  buildVerifyView: ->
-
-    @container.destroySubViews()
-
-    @codeEntryView = new KDHitEnterInputView
-      type         : 'text'
-      cssClass     : 'verify-pin-input'
-      placeholder  : 'Enter code here'
-      callback     : @bound 'verifyAccount'
-
-    @button    = new KDButtonView
-      title    : 'Verify account'
-      cssClass : 'solid green medium'
-      callback : @bound 'verifyAccount'
-
-    @container.addSubView new KDCustomHTMLView
-      cssClass : 'verify-message'
-      partial  : """
-
Before you can access your VM, we need to verify your account.
-        A verification email should already be in your inbox.
-        If you did not receive it yet, you can request a new code.

-      """
-      click    : (event)=>
-
-        return  unless $(event.target).is 'cite'
-
-        KD.remote.api.JUser.verifyByPin resendIfExists: yes, (err)=>
-
-          unless KD.showError err
-
-            @container.addSubView @retryView = new KDCustomHTMLView
-              cssClass : 'error-message warning'
-              partial  : """
-
Email sent, please check your inbox.

-              """
-
-            KD.utils.wait 3000, @retryView.bound 'destroy'
-
-    @container.addSubView @codeEntryView
-    @container.addSubView @button
-

   createProgressBar: (initial = 10)->
@@ -390,47 +389,6 @@
     @hasError = null

-  turnOnMachine: ->
-
-    computeController = KD.getSingleton 'computeController'
-    computeController.off  "error-#{@machineId}"
-
-    @emit 'MachineTurnOnStarted'
-
-    methodName   = 'start'
-    nextState    = 'Starting'
-
-    if @state in [ NotInitialized, Terminated ]
-      methodName = 'build'
-      nextState  = 'Building'
-
-    computeController.once "error-#{@machineId}", ({err})=>
-
-      unless err?.code is ComputeController.Error.NotVerified
-        @hasError = yes
-
-      @buildViews State: @machine.status.state
-
-    KD.singletons.computeController[methodName] @machine
-
-    @state = nextState
-    @buildViews()
-
-
-  prepareIDE: ->
-
-    KD.getSingleton('computeController').fetchMachines (err, machines) =>
-      return KD.showError "Couldn't fetch your VMs"  if err
-
-      m = machine for machine in machines when machine._id is @machine._id
-
-      KD.getSingleton('appManager').tell 'IDE', 'mountMachine', m
-      @machine = m
-      @setData m
-
-      @emit 'IDEBecameReady', m
-
-
   handleNoMachineFound: ->

     {@state} = @getOptions()
@@ -438,6 +396,47 @@
     @buildViews()
     @createFooter()
     return @show()
+
+
+  turnOnMachine: ->
+
+    computeController = KD.getSingleton 'computeController'
+    computeController.off  "error-#{@machineId}"
+
+    @emit 'MachineTurnOnStarted'
+
+    methodName   = 'start'
+    nextState    = 'Starting'
+
+    if @state in [ NotInitialized, Terminated ]
+      methodName = 'build'
+      nextState  = 'Building'
+
+    computeController.once "error-#{@machineId}", ({err})=>
+
+      unless err?.code is ComputeController.Error.NotVerified
+        @hasError = yes
+
+      @buildViews State: @machine.status.state
+
+    KD.singletons.computeController[methodName] @machine
+
+    @state = nextState
+    @buildViews()
+
+
+  prepareIDE: ->
+
+    KD.getSingleton('computeController').fetchMachines (err, machines) =>
+      return KD.showError "Couldn't fetch your VMs"  if err
+
+      m = machine for machine in machines when machine._id is @machine._id
+
+      KD.getSingleton('appManager').tell 'IDE', 'mountMachine', m
+      @machine = m
+      @setData m
+
+      @emit 'IDEBecameReady', m

   verifyAccount: ->


resurrection.teamwork: remove workspace on window "unload"

--- client/Teamwork/Views/teamworkworkspace.coffee
+++ client/Teamwork/Views/teamworkworkspace.coffee
@@ -60,6 +60,9 @@
     @on "NewHistoryItemAdded", (data) =>
       # log data
       @sendSystemMessage data
+
+    KD.singleton("windowController").addUnloadListener "window", =>
+      @workspaceRef.remove()

   createButtons: (panel) ->
     panel.addSubView @buttonsContainer = new KDCustomHTMLView


Code refactoring

Code refactoring

--- client/account/lib/views/accountbilling.coffee
+++ client/account/lib/views/accountbilling.coffee
@@ -102,7 +102,7 @@
       style    : 'solid small green'
       cssClass : 'hidden'
       title    : 'Update'
-      callback : => @preventBlockedUser()
+      callback : => @bound 'preventBlockedUser'

     @paymentMethodHeader = header
     @paymentMethodButton = button
@@ -154,7 +154,7 @@
       @paymentHistoryWrapper.addSubView @listController.getView()

-  preventBlockedUser: () ->
+  preventBlockedUser: ->

     { KEY, DURATION } = PaymentConstants.FAILED_ATTEMPTS.UPDATE_CREDIT_CARD
     now               = Date.now()
@@ -172,7 +172,7 @@
         @removeBlockFromUser()

-  startWorkflow: (isFailedLimitReached = no) ->
+  startWorkflow: (isFailedLimitReached) ->

     @workflow = new UpdateCreditCardWorkflow { delegate: this }
     @workflow.once 'UpdateCreditCardWorkflowFinishedSuccessfully', @bound 'handleFinishedWithSuccess'


Add recovered accounts default color

Add recovered accounts default color

--- app/src/preferences/defaults.coffee
+++ app/src/preferences/defaults.coffee
@@ -81,6 +81,7 @@

   # accounts preferences
   Accounts:
+    recoveredAccountColor: '#cccccc'
     colors:
       turquoise:
         localization: "common.colors.turquoise"


fix indentation

fix indentation

--- packages/rocketchat-integrations/server/triggers.coffee
+++ packages/rocketchat-integrations/server/triggers.coffee
@@ -91,10 +91,10 @@
 			HTTP: (method, url, options) ->
 				try
 					return {} =
-					result: HTTP.call method, url, options
+						result: HTTP.call method, url, options
 				catch e
 					return {} =
-					error: e
+						error: e
 			script: script
 			method: method
 			params: params


Firefox: Fix createTab.

Firefox: Fix createTab.

Firefox baulks at "about:newtab" in createTab (but seems happy with no
URL specified).  Chrome is also happy with no URL specified.

(Does this mean that we don't need "about:newtab" ANYWHERE in the code
base?  Could Settings.defaults.newTabUrl just be ""?)

Mention @mrmr1993.

--- background_scripts/main.coffee
+++ background_scripts/main.coffee
@@ -101,6 +101,8 @@
       index: request.tab.index + 1
       active: true
       windowId: request.tab.windowId
+    # Firefox does not support "about:newtab" in chrome.tabs.create.
+    delete tabConfig["url"] if tabConfig["url"] == Settings.defaults.newTabUrl
     chrome.tabs.create tabConfig, (tab) ->
       # NOTE(mrmr1993, 2017-02-08): Firefox currently doesn't support openerTabId (issue 1238314) and throws
       # a type error if it is present. We work around this by attempting to set it separately from creating


Fix background-page error on "yy".

Fix background-page error on "yy".

The return value from copyToClipboard is passed to sendResponse by the
chrome.runtime.onMessage.addListener listener.  This was using the
(somewhat arbitrary) value returned by Clipboard.copy, which turns out
to be circular, causing an error.

This fixes that.

--- background_scripts/main.coffee
+++ background_scripts/main.coffee
@@ -170,7 +170,7 @@
 #
 # Copies some data (request.data) to the clipboard.
 #
-copyToClipboard = (request) -> Clipboard.copy(request.data)
+copyToClipboard = (request) -> Clipboard.copy(request.data); null

 #
 # Selects the tab with the ID specified in request.id


groups link in group route handler added

--- client/landing/app/MainApp/kodingrouter.coffee
+++ client/landing/app/MainApp/kodingrouter.coffee
@@ -244,6 +244,8 @@
       '/:name?/Topics/:slug'            : createContentHandler 'Topics'
       '/:name?/Activity/:slug'          : createContentHandler 'Activity'
       '/:name?/Apps/:slug'              : createContentHandler 'Apps'
+
+      '/:name/Groups'                   : createSectionHandler 'Groups'

       '/:name/Followers'                : createContentHandler 'Members', yes
       '/:name/Following'                : createContentHandler 'Members', yes


include formGroupClass on read-only as well as write

--- client/lanes/components/shared/FieldMixin.cjsx
+++ client/lanes/components/shared/FieldMixin.cjsx
@@ -56,13 +56,11 @@
         <span>{value}</span>

     formGroupClassNames: ->
-        _.classnames(
-            _.result(this, 'formGroupClass')
-        )
+        _.result(this, 'formGroupClass')

     _mixinRenderValue: (label, className) ->
         value = (@renderDisplayValue || @renderMixinDisplayValue)?()
-        className = _.classnames(@props.className, className, {
+        className = _.classnames(@props.className, className, @formGroupClassNames(), {
             "align-#{@props.align}": @props.align
         })
         if @props.unstyled


Don't render anything anymore when we are deleting a highlight.

Otherwise there are errors when template tries to access now undefined
document in the process of rendering. But things should not be rendered
anymore at all.

--- client/lib/annotator/pdf-text-highlight.coffee
+++ client/lib/annotator/pdf-text-highlight.coffee
@@ -126,7 +126,8 @@
     # based on _id (which is immutable) to rerender the fragment
     # as document changes.
     highlightsControl = Meteor.render =>
-      Template.highlightsControl Highlight.documents.findOne @annotation?._id
+      highlight = Highlight.documents.findOne @annotation?._id
+      Template.highlightsControl highlight if highlight

     $control.find('.meta-content').empty().append(highlightsControl)
     $control.show()


Restore conditional loading of react editor renderer

--- src/editor.coffee
+++ src/editor.coffee
@@ -214,10 +214,10 @@
     @subscribe @displayBuffer, 'soft-wrap-changed', (args...) => @emit 'soft-wrap-changed', args...

   getViewClass: ->
-    # if atom.config.get('core.useReactEditor')
-    require './react-editor-view'
-    # else
-      # require './editor-view'
+    if atom.config.get('core.useReactEditor')
+      require './react-editor-view'
+    else
+      require './editor-view'

   destroyed: ->
     @unsubscribe()


Don't apply all editor bindings to mini editors

--- src/app/editor.coffee
+++ src/app/editor.coffee
@@ -83,7 +83,6 @@

   bindKeys: ->
     editorBindings =
-      'save': @save
       'move-right': @moveCursorRight
       'move-left': @moveCursorLeft
       'move-down': @moveCursorDown
@@ -96,7 +95,6 @@
       'select-down': @selectDown
       'select-word': @selectWord
       'newline': @insertNewline
-      'newline-below': @insertNewlineBelow
       'tab': @insertTab
       'indent-selected-rows': @indentSelectedRows
       'outdent-selected-rows': @outdentSelectedRows
@@ -110,19 +108,6 @@
       'paste': @paste
       'undo': @undo
       'redo': @redo
-      'toggle-soft-wrap': @toggleSoftWrap
-      'fold-all': @foldAll
-      'toggle-fold': @toggleFold
-      'fold-selection': @foldSelection
-      'unfold': => @unfoldCurrentRow()
-      'split-left': @splitLeft
-      'split-right': @splitRight
-      'split-up': @splitUp
-      'split-down': @splitDown
-      'close': @close
-      'show-next-buffer': @loadNextEditSession
-      'show-previous-buffer': @loadPreviousEditSession
-
       'move-to-top': @moveCursorToTop
       'move-to-bottom': @moveCursorToBottom
       'move-to-beginning-of-line': @moveCursorToBeginningOfLine
@@ -137,7 +122,25 @@
       'select-to-end-of-word': @selectToEndOfWord
       'select-to-beginning-of-word': @selectToBeginningOfWord
       'select-all': @selectAll
-      'toggle-line-comments': @toggleLineCommentsInSelection
+
+    if not @mini
+      _.extend editorBindings,
+        'save': @save
+        'newline-below': @insertNewlineBelow
+        'toggle-soft-wrap': @toggleSoftWrap
+        'fold-all': @foldAll
+        'toggle-fold': @toggleFold
+        'fold-selection': @foldSelection
+        'unfold': => @unfoldCurrentRow()
+        'split-left': @splitLeft
+        'split-right': @splitRight
+        'split-up': @splitUp
+        'split-down': @splitDown
+        'close': @close
+        'show-next-buffer': @loadNextEditSession
+        'show-previous-buffer': @loadPreviousEditSession
+        'toggle-line-comments': @toggleLineCommentsInSelection
+

     for name, method of editorBindings
       do (name, method) =>


engine data module

engine data module

--- src/engine.coffee
+++ src/engine.coffee
@@ -286,6 +286,7 @@
     return self

   Engine.defaultModules = [
+    "Data"
     "Keyboard"
     "Mouse"
     "Background"


Mount only new app <back>

Mount only new app <back>

--- src/apps/index.coffee
+++ src/apps/index.coffee
@@ -4,108 +4,114 @@
 app = module.exports = express()

 # Normal routing
-console.time('actions')
-app.use(require('../apps/actions'))
-console.timeEnd('actions')
+# console.time('actions')
+# app.use(require('../apps/actions'))
+# console.timeEnd('actions')

-console.time('feed')
-app.use(require('../apps/feed'))
-console.timeEnd('feed')
+# console.time('feed')
+# app.use(require('../apps/feed'))
+# console.timeEnd('feed')

-console.time('home')
-app.use(require('../apps/home'))
-console.timeEnd('home')
+# console.time('home')
+# app.use(require('../apps/home'))
+# console.timeEnd('home')

-console.time('blog')
-app.use(require('../apps/blog'))
-console.timeEnd('blog')
+# console.time('blog')
+# app.use(require('../apps/blog'))
+# console.timeEnd('blog')

-console.time('authentication')
-app.use(require('../apps/authentication'))
-console.timeEnd('authentication')
+# console.time('authentication')
+# app.use(require('../apps/authentication'))
+# console.timeEnd('authentication')

-console.time('confirmation')
-app.use(require('../apps/confirmation'))
-console.timeEnd('confirmation')
+# console.time('confirmation')
+# app.use(require('../apps/confirmation'))
+# console.timeEnd('confirmation')

-console.time('getting_started')
-app.use(require('../apps/getting_started'))
-console.timeEnd('getting_started')
+# console.time('getting_started')
+# app.use(require('../apps/getting_started'))
+# console.timeEnd('getting_started')

-console.time('tools')
-app.use(require('../apps/tools'))
-console.timeEnd('tools')
+# console.time('tools')
+# app.use(require('../apps/tools'))
+# console.timeEnd('tools')

-console.time('util')
-app.use(require('../apps/util'))
-console.timeEnd('util')
+# console.time('util')
+# app.use(require('../apps/util'))
+# console.timeEnd('util')

-console.time('about')
-app.use(require('../apps/about'))
-console.timeEnd('about')
+# console.time('about')
+# app.use(require('../apps/about'))
+# console.timeEnd('about')

-console.time('search')
-app.use(require('../apps/search'))
-console.timeEnd('search')
+# console.time('search')
+# app.use(require('../apps/search'))
+# console.timeEnd('search')

-console.time('manage')
-app.use(require('../apps/manage'))
-console.timeEnd('manage')
+# console.time('manage')
+# app.use(require('../apps/manage'))
+# console.timeEnd('manage')

-console.time('marklet')
-app.use(require('../apps/marklet'))
-console.timeEnd('marklet')
+# console.time('marklet')
+# app.use(require('../apps/marklet'))
+# console.timeEnd('marklet')

-console.time('import')
-app.use(require('../apps/import'))
-console.timeEnd('import')
+# console.time('import')
+# app.use(require('../apps/import'))
+# console.timeEnd('import')

-console.time('settings')
-app.use(require('../apps/settings'))
-console.timeEnd('settings')
+# console.time('settings')
+# app.use(require('../apps/settings'))
+# console.timeEnd('settings')

-console.time('onboarding')
-app.use(require('../apps/onboarding'))
-console.timeEnd('onboarding')
+# console.time('onboarding')
+# app.use(require('../apps/onboarding'))
+# console.timeEnd('onboarding')

-console.time('graphql')
-app.use(require('../apps/graphql'))
-console.timeEnd('graphql')
+# console.time('graphql')
+# app.use(require('../apps/graphql'))
+# console.timeEnd('graphql')

-console.time('examples')
-app.use(require('../apps/examples'))
-console.timeEnd('examples')
+# console.time('examples')
+# app.use(require('../apps/examples'))
+# console.timeEnd('examples')

-console.time('vanity_redirects')
-app.use(require('../apps/vanity_redirects'))
-console.timeEnd('vanity_redirects')
+# console.time('vanity_redirects')
+# app.use(require('../apps/vanity_redirects'))
+# console.timeEnd('vanity_redirects')

-console.time('deeplink')
-app.use(require('../apps/deeplink'))
-console.timeEnd('deeplink')
+# console.time('deeplink')
+# app.use(require('../apps/deeplink'))
+# console.timeEnd('deeplink')

-console.time('apple-site-association')
-app.use(require('../apps/apple_site_association'))
-console.timeEnd('apple-site-association')
+# console.time('apple-site-association')
+# app.use(require('../apps/apple_site_association'))
+# console.timeEnd('apple-site-association')

-# Dynamic routing (in order)
-console.time('profile')
-app.use(require('../apps/profile'))
-console.timeEnd('profile')
+# # Dynamic routing (in order)
+# console.time('profile')
+# app.use(require('../apps/profile'))
+# console.timeEnd('profile')

-console.time('block')
-app.use(require('../apps/block'))
-console.timeEnd('block')
+# console.time('block')
+# app.use(require('../apps/block'))
+# console.timeEnd('block')

-console.time('new_channel')
-app.use(require('../apps/new_channel'))
-console.timeEnd('new_channel')
+# console.time('new_channel')
+# app.use(require('../apps/new_channel'))
+# console.timeEnd('new_channel')

-console.time('rss')
-app.use(require('../apps/rss'))
-console.timeEnd('rss')
+# console.time('rss')
+# app.use(require('../apps/rss'))
+# console.timeEnd('rss')

-# Ennvironment specific
-switch NODE_ENV
-  when 'development'
-    app.use require '../apps/statuses'
+# # Ennvironment specific
+# switch NODE_ENV
+#   when 'development'
+#     app.use require '../apps/statuses'
+
+
+# New Application
+console.time('app')
+app.use(require('../apps/app'))
+console.timeEnd('app')


clean js self WIP ...

clean js self WIP ...

--- app/views/chart/simple-graph.coffee
+++ app/views/chart/simple-graph.coffee
@@ -156,12 +156,12 @@
       return "translate(0," + self.y(d) + ")"
     stroke = (d) ->
       return if d then "#ccc" else "#666"
-    fx = self.x.tickFormat(10)
-    fy = self.y.tickFormat(10)
+    fx = @x.tickFormat(10)
+    fy = @y.tickFormat(10)

     # Regenerate x-ticks…
-    gx = self.vis.selectAll("g.x")
-        .data(self.x.ticks(10), String)
+    gx = @vis.selectAll("g.x")
+        .data(@x.ticks(10), String)
         .attr("transform", tx)

     gx.select("text")
@@ -174,25 +174,25 @@
     gxe.append("line")
         .attr("stroke", stroke)
         .attr("y1", 0)
-        .attr("y2", self.size.height)
+        .attr("y2", @size.height)

     gxe.append("text")
         .attr("class", "axis")
-        .attr("y", self.size.height)
+        .attr("y", @size.height)
         .attr("dy", "1em")
         .attr("text-anchor", "middle")
         .text(fx)
         .style("cursor", "ew-resize")
         .on("mouseover", (d) -> d3.select(this).style("font-weight", "bold"))
         .on("mouseout",  (d) -> d3.select(this).style("font-weight", "normal"))
-        .on("mousedown.drag",  self.xaxis_drag)
-        .on("touchstart.drag", self.xaxis_drag);
+        .on("mousedown.drag",  @xaxis_drag)
+        .on("touchstart.drag", @xaxis_drag);

     gx.exit().remove();

     # Regenerate y-ticks…
-    gy = self.vis.selectAll("g.y")
-        .data(self.y.ticks(10), String)
+    gy = @vis.selectAll("g.y")
+        .data(@y.ticks(10), String)
         .attr("transform", ty)

     gy.select("text")
@@ -206,7 +206,7 @@
     gye.append("line")
         .attr("stroke", stroke)
         .attr("x1", 0)
-        .attr("x2", self.size.width)
+        .attr("x2", @size.width)

     gye.append("text")
         .attr("class", "axis")
@@ -217,12 +217,12 @@
         .style("cursor", "ns-resize")
         .on("mouseover", (d) -> d3.select(this).style("font-weight", "bold"))
         .on("mouseout",  (d) -> d3.select(this).style("font-weight", "normal"))
-        .on("mousedown.drag",  self.yaxis_drag)
-        .on("touchstart.drag", self.yaxis_drag)
+        .on("mousedown.drag",  @yaxis_drag)
+        .on("touchstart.drag", @yaxis_drag)

     gy.exit().remove();
-    self.plot.call(d3.behavior.zoom().x(self.x).y(self.y).on("zoom", self.redraw));
-    self.update();
+    @plot.call(d3.behavior.zoom().x(@x).y(@y).on("zoom", @redraw));
+    @update();

   update: () =>
     lines = @vis.select("path").attr("d", @line(@points));


take observable in compat.graph

take observable in compat.graph

--- app/compat.coffee
+++ app/compat.coffee
@@ -27,17 +27,25 @@
     else if _.isArray(args[0]) and args[0][0]?.datapoints?
       promise = Q args[0]
       params = _.extend {}, ctx.options(), args[1]
+    else if args[0] instanceof Bacon.Observable
+      data = args[0]
+      params = _.extend {}, ctx.options(), args[1]
     else
       all_params = Server.args_to_params {args, default_options: ctx.options()}
       params = all_params.client
       promise = Server.get_data all_params.server

-    data = Bacon.fromPromise(promise)
-    Context.AsyncComponent {promise},
+    if promise
+      data = Bacon.fromPromise(promise)
+      Context.AsyncComponent {promise},
+        React.DOM.div {style: {width: '-webkit-min-content'}},
+          Builtins.ComponentAndError {promise},
+            graph.create_component(data, params)
+          Builtins.PromiseStatusComponent {promise, start_time: new Date}
+    else
+      # TODO async, error
       React.DOM.div {style: {width: '-webkit-min-content'}},
-        Builtins.ComponentAndError {promise},
-          graph.create_component(data, params),
-        Builtins.PromiseStatusComponent {promise, start_time: new Date}
+        graph.create_component(data, params)

   context_vars:
     moment: moment


Check for new slides after every cycle

Check for new slides after every cycle

--- app/config.coffee
+++ app/config.coffee
@@ -7,4 +7,4 @@
     defaultDelay: 3
     defaultDuration: 0.5
     defaultTransition: "none"
-    checkCycles: 2+    checkCycles: 1


PassThrough

PassThrough

Why was i making my own passthrough when Node comes with one o_O

At any rate, mine had a bug where next was not being called on the
transform method. This was easy to resolve, but then i discovered
the PassThrough builtin, and removed my implementation entirely.

--- lib/streams/commonjs.coffee
+++ lib/streams/commonjs.coffee
@@ -5,8 +5,8 @@
 #
 path              = require 'path'
 {
+  PassThrough
   Readable
-  Transform
 }                 = require 'stream'
 browserify        = require 'browserify'
 {CoffeeTransform} = require './coffee'
@@ -49,20 +49,8 @@
   transform: (transformProvider) -> @_browserify.transform (file) ->
     ext = path.extname file
     transform = transformProvider file, ext
-    if not transform? then return new PassTransform()
+    if not transform? then return new PassThrough()
     transform
-
-
-# ## PassTransform
-#
-# Our PassTransform is a workaround to the fact that i can't figure out how
-# to make Browserify let me choose *not* to transform that specific stream.
-# Browserify seemingly requires all transforms return streams, so this
-# is here to make a passthrough stream for when callers opt out of returning
-# a stream for that specific transform-file.
-class PassTransform extends Transform
-  constructor: -> super
-  _transform: (chunk) -> @push chunk

 # ## coffeeifyTransform


doc update; add callback

doc update; add callback

--- src/base_model.coffee
+++ src/base_model.coffee
@@ -49,106 +49,121 @@
 #
 # @todo Callback support
 class Sirius.BaseModel
-  # @property [Array<String|Object> the attributes for model
-  # When attribute defined as object, then key, will be a `attribute` and `value` it's default value for this `attribute`
-  # @example
-  #   @attrs: ["id", "title", {description : "Lorem ipsum ..."}]
-  #   //now, model attribute `description` have a default value "Lorem ipsum ..."
-  #
+  ###
+    the attributes for model.
+
+    When attribute defined as object, then key, will be a `attribute` and `value` it's default value for this `attribute`
+    @example
+      @attrs: ["id", "title", {description : "Lorem ipsum ..."}]
+      //now, model attribute `description` have a default value "Lorem ipsum ..."
+  ###
   @attrs: []

-  # @property [Array<String>] model names for relations
-  # From this property, will be generated helper methods: `add_x`, where `x` is a model name
-  # @note model names, should be written in the next format: ModelName => model_name
-  # @example
-  #   class Model extends Sirius.BaseModel
-  #     @has_many: ["other_model"]
-  #
-  #   my_model = new Model()
-  #   my_model.add_other_model(new OtherModel())
-  #
+  ###
+    model names for relations.
+
+    From this property, will be generated helper methods: `add_x`, where `x` is a model name
+    @note model names, should be written in the next format: ModelName => model_name
+    @example
+      class Model extends Sirius.BaseModel
+        @has_many: ["other_model"]
+
+      my_model = new Model()
+      my_model.add_other_model(new OtherModel())
+  ###
   @has_many: []

-  # @property [Array<String>] model names for relations
-  # From this property, will be generated helper methods: `add_x`, where `x` is a model name
-  # @note model names, should be written in the next format: ModelName => model_name
-  # @note when you call `add_model` when `model` already exist
-  # @example
-  #   class MyModel extends Sirius.BaseModel
-  #     @has_one: ["model"]
-  #   my_model = new MyModel()
-  #   my_model.add_model(new Model()) // => ok
-  #   my_model.add_model(new Model()) // => oops, exception
-  #   my_model.set("model", null)
-  #   my_model.add_model(new Model()) // => ok
+  ###
+    model names for relations.
+
+    From this property, will be generated helper methods: `add_x`, where `x` is a model name
+    @note model names, should be written in the next format: ModelName => model_name
+    @note when you call `add_model` when `model` already exist
+    @example
+       class MyModel extends Sirius.BaseModel
+         @has_one: ["model"]
+       my_model = new MyModel()
+       my_model.add_model(new Model()) // => ok
+       my_model.add_model(new Model()) // => oops, exception
+       my_model.set("model", null)
+       my_model.add_model(new Model()) // => ok
+  ###
   @has_one: []
-
-  # @property [Array<Object>] take a object `model` as model for association, and `back` as an `attributes` from `has_*` model
-  # @note for use need to add into `@attrs` the next attribute: `model_back`, see example
-  # @example
-  #   class Person extends Sirius.BaseModel
-  #     @attrs: ["id"]
-  #     @has_many: ["group"]
-  #
-  #   class Group extends Sirius.BaseModel
-  #     @attrs: ["person_id"]
-  #     @belongs_to [{model: "person", back: "id"}]
-  #
-  #   person = new Person({id: 1})
-  #   group  = new Group()
-  #   person.add_group(group) // when add new group, then in `group` set a `person_id` as id from Person instance
-  #
-  #   group.get('person_id') // => 1
+  ###
+    take a object `model` as model for association, and `back` as an `attributes` from `has_*` model
+
+  @note for use need to add into `@attrs` the next attribute: `model_back`, see example
+    @example
+       class Person extends Sirius.BaseModel
+         @attrs: ["id"]
+         @has_many: ["group"]
+
+       class Group extends Sirius.BaseModel
+         @attrs: ["person_id"]
+         @belongs_to [{model: "person", back: "id"}]
+
+       person = new Person({id: 1})
+       group  = new Group()
+       person.add_group(group) // when add new group, then in `group` set a `person_id` as id from Person instance
+
+       group.get('person_id') // => 1
+  ###
   @belongs_to: []

-  # @property [Object] - object, which contain attributes names as keys, and values is a object, with properties for html element
-  # @note when not set a `tag` for `attribute` default `tag` is a `div`
-  # @example
-  #   class Person extends Sirius.BaseModel
-  #     @attrs: ["id", "name"]
-  #     @to :
-  #       id : tag: b, class: 'person-class'
-  #  (new Person({id: 1, name: "Abc"})).to_html() # => 1
Abc

+  ###
+    object, which contain attributes names as keys, and values is a object, with properties for html element
+    @note when not set a `tag` for `attribute` default `tag` is a `div`
+    @example
+       class Person extends Sirius.BaseModel
+         @attrs: ["id", "name"]
+         @to :
+           id : tag: b, class: 'person-class'
+      (new Person({id: 1, name: "Abc"})).to_html() # => 1
Abc

+  ###
   @to: {}

-  # @property [String] - name for element, when you want convert html to Model
-  # @note when it not define, then it's create from model name as: ModelName => model_name
-  # @example
-  #   class Person extends
-  #     @form_name: 'a-b-c'
-  #
+  ###
+    name for element, when you want convert html to Model
+    @note when it not define, then it's create from model name as: ModelName => model_name
+    @example
+       class Person extends
+         @form_name: 'a-b-c'
+  ###
   @form_name: null

-  # @property [String] - attribute name, for which generate guid
-  # @example
-  #   class Person extends
-  #     @attrs: ["id", "name"]
-  #     @guid_for: "id"
-  #
+  ###
+    attribute name, for which generate guid
+    @example
+       class Person extends
+         @attrs: ["id", "name"]
+         @guid_for: "id"
+  ###
   @guid_for: null

-  # @property [Object] - object, where keys, is a defined `@attrs` and values is a validator objects or function
-  # @note validator object, it's a default Validators @see Sirius.Validator
-  # @example
-  #   class ModelwithValidators extends Sirius.BaseModel
-  #   @attrs: ["id", {title: "t"}, "description"]
-  #   @validate :
-  #     id:
-  #       presence: true,
-  #       numericality: only_integers: true
-  #       inclusion: within: [1..10]
-  #       validate_with:  (value) ->
-  #         if not condition ....
-  #           @msg = .... #define a user friendly message
-  #         else
-  #           true
-  #
-  #     title:
-  #       presence: true
-  #       format: with: /^[A-Z].+/
-  #       length: min: 3, max: 7
-  #       exclusion: ["title"]
-  #
+  ###
+    object, where keys, is a defined `@attrs` and values is a validator objects or function
+
+    @note validator object, it's a default Validators @see Sirius.Validator
+    @example
+       class ModelwithValidators extends Sirius.BaseModel
+       @attrs: ["id", {title: "t"}, "description"]
+       @validate :
+         id:
+           presence: true,
+           numericality: only_integers: true
+           inclusion: within: [1..10]
+           validate_with:  (value) ->
+             if not condition ....
+               @msg = .... #define a user friendly message
+             else
+               true
+
+         title:
+           presence: true
+           format: with: /^[A-Z].+/
+           length: min: 3, max: 7
+           exclusion: ["title"]
+  ###
   @validate : {}

   # @nodoc
@@ -235,6 +250,8 @@

     if g = @guid_for()
       @set(g, @_generate_guid())
+
+    @after_create() || ->

   # @private
   # @nodoc
@@ -509,6 +526,11 @@

   # usage for comparing models
   # When equal return true, otherwise return false
-  #
+  # @param other [T] - other model instance
   compare: (other) ->
-    throw new Error("`compare` method must be overridden")+    throw new Error("`compare` method must be overridden")
+
+  # callback, run after model created
+  # must be overridden in user model
+  after_create: () ->
+


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/follow.coffee
+++ src/follow.coffee
@@ -1,5 +1,5 @@
 ###*
-The Follow module provides a simple method to set
+The Follow module provides a simple method to set an object

 # Health regeneration


FIX: Add e.stopPropagation() in event handler to prevent calling multiple times.

--- lib/tree-view-finder.coffee
+++ lib/tree-view-finder.coffee
@@ -192,13 +192,14 @@
           console.log 'tree-view-finder: double click: file' if @debug
           @openUri(e.target.dataset.path)
       )
-    click_ts = 0
+    #click_ts = 0
     @treeView.on 'click', '.entry', (e) =>
       #console.log 'tree-view-finder: click event', e if @debug
-      if (click_ts != e.timeStamp)
-        click_ts = e.timeStamp
+      #if (click_ts != e.timeStamp)
+      #  click_ts = e.timeStamp
         return if e.target.classList.contains('entries')
         return if e.shiftKey or e.metaKey or e.ctrlKey
+        e.stopPropagation()
         if name = e.target.querySelector('.icon-file-directory')
           if @debug
             console.log 'tree-vire-finder: click w/o double click.',


moar documentation: documented fields/methods for Repository and Reference.

--- src/gitteh.coffee
+++ src/gitteh.coffee
@@ -269,7 +269,22 @@
 		cb: type: "function"
 	_priv.native.write cb

-Gitteh.Reference = Reference = (repo, nativeRef) ->
+###*
+ * @class
+ * A Reference is a named pointer to a {@link Commit} object. That is, refs are
+ * the DNS of Git-land. References can either be direct or symbolic. Direct
+ * references point to the object id of a commit. Symbolic refs point to other
+ * references.
+ * @property {String} name
+ * @property {Boolean} direct true if Reference points directly to an object id.
+ * @property {Boolean} packed true if Reference is in a packfile
+ * @property {String} target object id reference points to, or another reference
+ * name if not a direct reference.
+ * @property {Repository} repository the {@link Repository} that owns this ref.
+ * @see Repository#reference
+ * @see Repository#createReference
+###
+Reference = Gitteh.Reference = (repo, nativeRef) ->
 	_priv = createPrivate @
 	_priv.native = nativeRef
 	immutable(@, nativeRef)
@@ -284,6 +299,18 @@
  * @class
  * Represents a local Git repository that has been opened by Gitteh. Used to get
  * access to any objects contained within it.
+ *
+ * Repositories can be bare - they will not have a working directory, in this
+ * case the contents of what is usually in a .git subdirectory will be in the
+ * top level.
+ * @property {Boolean} bare true if this repository is bare.
+ * @property {String} path location of the Git metadata directory
+ * @property {String} workingDirectory location of the working directory, if
+ * applicable (non-bare repository)
+ * @property {Remote[]} remotes List of remotes configured for this repository.
+ * @property {Reference[]} references List of references contained in this
+ * repository.
+ * @property {Index} index The Git index for this repository.
 ###
 Repository = Gitteh.Repository = (nativeRepo) ->
 	if nativeRepo not instanceof NativeRepository
@@ -300,12 +327,32 @@
 	index = new Index nativeRepo.index
 	immutable(@, {index}).set "index"
 	return @
+
+###*
+ * Checks if an object with given objectid exists.
+ * @param {String} oid ID of object in question.
+ * @param {Function} cb Called with status of object existence.
+###
 Repository.prototype.exists = ->
 	_priv = getPrivate @
 	[oid, cb] = args
 		oid: type: "oid"
 		cb: type: "function"
 	_priv.native.exists oid, cb
+
+###*
+ * Fetches an object with given ID. The object returned will be a Gitteh wrapper
+ * corresponding to the type of Git object fetched. Alternatively, objects with
+ * an expected type can be fetched using the {@link #blob}, {@link #commit},
+ * {@link #tag}, {@link #tree}, {@link #reference} methods.
+ * @param {String} oid id of object to be fetched.
+ * @param {Function} cb called when object has been fetched.
+ * @see Commit
+ * @see Blob
+ * @see Tag
+ * @see Tree
+ * @see Reference
+###
 Repository.prototype.object = ->
 	_priv = getPrivate @
 	[oid, type, cb] = args
@@ -321,10 +368,50 @@
 			else undefined
 		return cb new TypeError("Unexpected object type") if clazz is undefined
 		return cb null, new clazz @, object
+
+###*
+ * Fetches a {@link Blob} object from the repository. This is a stricter
+ * variant of {@link #object} - an error will be thrown if object isnt a blob.
+ * @param {String} oid id of blob to be fetched.
+ * @param {Function} cb called when blob has been fetched.
+ * @see #object
+###
 Repository.prototype.blob = (oid, cb) -> @object oid, "blob", cb
+
+###*
+ * Fetches a {@link Commit} object from the repository. This is a stricter
+ * variant of {@link #object} - an error will be thrown if object isnt a commit.
+ * @param {String} oid id of commit to be fetched.
+ * @param {Function} cb called when commit has been fetched.
+ * @see #object
+###
 Repository.prototype.commit = (oid, cb) -> @object oid, "commit", cb
+
+###*
+ * Fetches a {@link Tag} object from the repository. This is a stricter
+ * variant of {@link #object} - an error will be thrown if object isnt a tag.
+ * @param {String} oid id of tag to be fetched.
+ * @param {Function} cb called when tag has been fetched.
+ * @see #object
+###
 Repository.prototype.tag = (oid, cb) -> @object oid, "tag", cb
+
+###*
+ * Fetches a {@link Tree} object from the repository. This is a stricter
+ * variant of {@link #object} - an error will be thrown if object isnt a tree.
+ * @param {String} oid id of tree to be fetched.
+ * @param {Function} cb called when tree has been fetched.
+ * @see #object
+###
 Repository.prototype.tree = (oid, cb) -> @object oid, "tree", cb
+
+###*
+ * Fetches a {@link Reference} object from the repository. This is a stricter
+ * variant of {@link #object} - an error will be thrown if object isnt a ref.
+ * @param {String} oid id of reference to be fetched.
+ * @param {Function} cb called when reference has been fetched.
+ * @see #object
+###
 Repository.prototype.reference = ->
 	_priv = getPrivate @
 	[name, resolve, cb] = args
@@ -333,7 +420,19 @@
 		cb: type: "function"
 	_priv.native.reference name, resolve, wrapCallback cb, (ref) =>
 		cb null, new Reference @, ref
+
+###*
+ * Alias of {@link #reference}.
+ * @param {String} oid id of reference to be fetched.
+ * @param {Function} cb called when reference has been fetched.
+ * @see #reference
+###
 Repository.prototype.ref = Repository.prototype.reference
+
+###*
+ * Creates a new reference, which can either by direct or symbolic.
+ * @see Reference
+###
 Repository.prototype.createReference = ->
 	_priv = getPrivate @
 	[name, target, force, cb] = args


Queue clients once more than MAX_CLIENTS (currently 8) has connected. Send clients a message telling them their position in the queue. Fixes #30.

--- lib/websocket_server.coffee
+++ lib/websocket_server.coffee
@@ -4,6 +4,7 @@
 WSFrame  = require('websocket').frame
 WSRouter = require('websocket').router
 HTTP = require("http")
+MAX_CLIENTS = 8

 debug = (message) ->
   console.log (new Date()) + " " + message
@@ -12,6 +13,22 @@
   constructor: (reflector, @port) ->
     # ...
     @reflectors = {}
+    @clients = []
+
+  addClient: (client) ->
+    @clients.push(client)
+
+  removeClient: (client) ->
+    if @clients.indexOf(client) >= 0
+      @clients.splice(@clients.indexOf(client), 1)
+
+  clientsAheadOf: (client) ->
+    index = @clients.indexOf(client)
+
+    if index < MAX_CLIENTS
+      -1
+    else
+      index - MAX_CLIENTS

   clearReflectors: ->
     @reflectors = {}
@@ -32,35 +49,65 @@

     @wsServer.on "request", @onRequest

+    setInterval @queueInterval, 1000
+
+  queueInterval: =>
+    index = 0
+
+    for client in @clients
+      if index < MAX_CLIENTS and !client.observer
+        @serveConnection(client)
+
+      if index >= MAX_CLIENTS
+        client.send "<packet><queue limit='#{MAX_CLIENTS}' position='#{index - MAX_CLIENTS}' /></packet>"
+
+      index++
+
   onRequest: (request) =>
-    console.log "[server] new request from"
-    console.log request.remoteAddress
+    console.log "[server] new request from #{request.remoteAddress}"

-    # todo - check request.origin maybe?
     try
+      # todo - check request.origin maybe?
       connection = request.accept("scenevr", request.origin)
     catch
       # doesnt want scenevr - drop the client
+      connection.close()
       return

-    reflector = @reflectors[request.resource]
+    connection.request = request
+
+    @addClient(connection)
+
+    connection.on "close", (reasonCode, description) =>
+      console.log "[server] Peer " + connection.remoteAddress + " disconnected."
+      @removeClient(connection)
+
+    if @clientsAheadOf(connection) >= 0
+      @queueConnection(connection)
+    else
+      @serveConnection(connection)
+
+  queueConnection: (connection) ->
+    # Do nothing.. queueInterval calls serveConnection once you get far enough up the queue
+
+  serveConnection: (connection) ->
+    reflector = @reflectors[connection.request.resource]

     if !reflector
-      console.log "[server] 404 scene not found '#{request.resource}'"
-      request.reject()
+      console.log "[server] 404 scene not found '#{connection.request.resource}'"
+      connection.request.reject()
       return

-    console.log "[server] client requested '#{request.resource}'"
+    console.log "[server] client requested '#{connection.request.resource}'"

-    observer = new Observer(connection, reflector)
-    reflector.addObserver(observer)
+    connection.observer = new Observer(connection, reflector)
+    reflector.addObserver(connection.observer)

     connection.on "message", (message) =>
       if message.type is "utf8"
-        observer.recieveMessage(message.utf8Data)
+        connection.observer.recieveMessage(message.utf8Data)

     connection.on "close", (reasonCode, description) =>
-      console.log "[server] Peer " + connection.remoteAddress + " disconnected."
-      reflector.removeObserver(observer)
+      reflector.removeObserver(connection.observer)

 module.exports = WebsocketServer


JCredential: setPermissionFor: to support accessLevels instead of roles and modes

--- workers/social/lib/social/models/computeproviders/credential.coffee
+++ workers/social/lib/social/models/computeproviders/credential.coffee
@@ -356,7 +356,7 @@
             callback null, []

-  setPermissionFor: (target, { user, owner, role, mode }, callback) ->
+  setPermissionFor: (target, { user, owner, accessLevel }, callback) ->

     Relationship.remove
       targetId : @getId()
@@ -365,13 +365,12 @@

       if user
         options = { as: if owner then 'owner' else 'user' }
-
-        if role or mode
-          options.data = {}
-          options.data.role = role  if role
-          options.data.mode = mode  if mode
-
-        target.addCredential this, options, (err) -> callback err
+        if accessLevel
+          @update { $set: { accessLevel } }, (err) =>
+            return callback err  if err?
+            target.addCredential this, options, callback
+        else
+          target.addCredential this, options, callback
       else
         callback err

@@ -379,7 +378,7 @@
   shareWith: (client, options, callback) ->

     { delegate } = client.connection
-    { target, user, owner, role, mode } = options
+    { target, user, owner, accessLevel } = options
     user ?= yes

     # Owners cannot unassign them from a credential
@@ -399,10 +398,10 @@
         target.fetchOwnAccount (err, account) =>
           if err or not account
             return callback new KodingError 'Failed to fetch account.'
-          @setPermissionFor account, { user, owner, mode }, callback
+          @setPermissionFor account, { user, owner }, callback

       else if target instanceof JGroup
-        @setPermissionFor target, { user, owner, role, mode }, callback
+        @setPermissionFor target, { user, owner, accessLevel }, callback

       else
         callback new KodingError 'Target does not support credentials.'


Add class "ie10" to body when using IE10

--- app/core/application.coffee
+++ app/core/application.coffee
@@ -48,6 +48,8 @@
   @isProduction = -> document.location.href.search('https?://localhost:3000') is -1
   @isIPadApp = webkit?.messageHandlers? and navigator.userAgent?.indexOf('iPhone OS') isnt -1
   $('body').addClass 'ipad' if @isIPadApp
+  if $.browser.msie and parseInt($.browser.version) is 10
+    $("html").addClass("ie10")
   @tracker = new Tracker()
   @facebookHandler = new FacebookHandler()
   @gplusHandler = new GPlusHandler()


Remove old View test, which can't possibly work as Views don't have their own persistent model on server side

--- test/unit/model/view.coffee
+++ test/unit/model/view.coffee
@@ -36,34 +36,3 @@
       new Model(name: 'test2')
     ]

-View = require('model/view')(TestDb)
-
-describe 'Server model: View', ->
-
-  before ->
-    @saveSpy = sinon.spy TestDb.prototype, 'save'
-    @findSpy = sinon.spy TestDb, 'find'
-    @view = new View
-      user: 'ickle'
-      name: 'test'
-      displayName: 'Test'
-      box: 'sdjfsdf'
-
-
-  context 'when view.save is called', ->
-    before (done) ->
-      @view.save done
-
-    it 'calls mongoose save method', ->
-      @saveSpy.calledOnce.should.be.true
-
-  context 'when view.findAll is called', ->
-    before (done) ->
-      View.findAll (err, res) =>
-        @results = res
-        done()
-
-    it 'should return View results', ->
-      @results[0].should.be.an.instanceOf View
-      @results[0].name.should.equal 'test'
-      @results.length.should.equal 2


Tweak Google search.

Tweak Google search.

--- config/search/jkn2-google.coffee
+++ config/search/jkn2-google.coffee
@@ -6,7 +6,8 @@
   regexps: "^https?://(www\\.)?google\\.([a-z\\.]+)/search\\?"
   selectors: [
     "div#search li.g"
-    "div.srg div.g"
+    # "div.srg div.g"
+    "div.g > div.rc"
   ]
   style:
     "border-color": "#0266C8"


make curve highlighter triangle equilateral

--- app/lib/canvas-graph.coffee
+++ app/lib/canvas-graph.coffee
@@ -76,14 +76,13 @@
     xClick = e.pageX - e.target.getBoundingClientRect().left - window.scrollX
     yClick = e.pageY - e.target.getBoundingClientRect().top - window.scrollY

-
     @plotPoints(val, val+zoomRanges[@zoomLevel])
     # @rescaleMarks(val, val+zoomRanges[@zoomLevel])

     if xClick < @leftPadding
       # draw triangle
       w = 10
-      s = w*Math.tan(@leftPadding)
+      s = 2*w*Math.tan(@leftPadding)

       @ctx.beginPath()
       @ctx.moveTo(w,yClick)


fix all query for documents + add byFullPath query

--- backend/db.coffee
+++ backend/db.coffee
@@ -20,10 +20,10 @@

     addFilter: (docType, callback) ->
         id = "_design/#{docType.toLowerCase()}"
-        map = """
+        all = """
             function (doc) {
                 if (doc.docType.toLowerCase() === "#{docType}".toLowerCase()) {
-                    return emit(doc._id, doc);
+                    emit(doc._id, doc);
                 }
             }
         """
@@ -32,7 +32,19 @@
             _id: id
             views:
                 all:
-                    map: map
+                    map: all
+
+        if docType in ['file', 'folder', 'File', 'Folder']
+            byFullPath = """
+                function (doc) {
+                    if (doc.docType.toLowerCase() === "#{docType}".toLowerCase()) {
+                        emit(doc.path + '/' + doc.name, doc);
+                    }
+                }
+            """
+
+            newDesignDoc.views.byFullPath =
+                map: byFullPath

         checkCreation = (err, res) ->
             if err?


Calculator now displays html entities again

--- javascripts/widgets/calculator.coffee
+++ javascripts/widgets/calculator.coffee
@@ -29,7 +29,7 @@

       displayValue: ->
         if !@current_expression.isError()
-          val = expression_to_string.toString(@current_expression)
+          val = expression_to_string.toHTMLString(@current_expression)
           if val.length == 0
             '0'
           else


add tranport post route/request into the express server

--- frontend/config/server.coffee
+++ frontend/config/server.coffee
@@ -13,6 +13,9 @@
 ###

 module.exports = drawRoutes: (app) ->
+  #
+  # Auth
+  #
   app.post '/api/v1/auth/login', (req, res) ->
     res.json {
       access_token: 'super_save_token',
@@ -26,7 +29,12 @@
   app.post '/logout', (req, res) ->
     res.json message: 'logging out!'

-  # possible route to call the inventory (it is inventory or inventories ?)
+  #
+  #  Inventory
+  #
+
+  # GET
+  # it is a possible route for the inventory (it is inventory or inventories ?)
   app.get '/api/v1/inventory', (req, res) ->
     list = []
     i = 0
@@ -54,3 +62,19 @@
       access_token: 'super_save_token'
     }

+  #
+  # Transporter
+  #
+
+  # POST
+  # Create a transoporter
+  app.post '/api/v1/transporter', (req, res) ->
+    res.json {
+      name: 'Pepito',
+      document_number: '123456789',
+      phone: '+57300214587',
+      address: 'calle falsa # 12 -3',
+      email: 'pepito@fake.com',
+      access_token: 'super_save_token'
+    }
+


Only listen for keystrokes if there is a controlling terminal.

--- src/master.coffee
+++ src/master.coffee
@@ -185,15 +185,17 @@
     process.on 'SIGINT',  => @shutdown()
     process.on 'SIGUSR1', => @debug()

-    process.stdin.resume()
-    process.stdin.setEncoding 'utf8'
-    process.stdin.setRawMode true
-    process.stdin.on 'data', (char) =>
-      switch char
-        when '\u0003'  # ctrl-c
-          @shutdown()
-        when '\u0004'  # ctrl-d
-          @debug()
+    # listen for keyboard shortcuts if this is a terminal
+    if process.stdin.isTTY
+      process.stdin.resume()
+      process.stdin.setEncoding 'utf8'
+      process.stdin.setRawMode true
+      process.stdin.on 'data', (char) =>
+        switch char
+          when '\u0003'  # ctrl-c
+            @shutdown()
+          when '\u0004'  # ctrl-d
+            @debug()

     @on 'worker:exception', (worker, err) =>
       @logger.log 'error', err, pid: worker.process.pid


Use coffeescript's default value syntax in Matrix

--- src/matrix.coffee
+++ src/matrix.coffee
@@ -65,9 +65,7 @@
 			m = (((if (j == i) then 1 else 0) for j in [0...size]) for i in [0...size])
 			return new Matrix(m)

-		@createBlankMatrix = (numOfRows, numOfCols) ->
-			if not numOfCols?
-				numOfCols = numOfRows
+		@createBlankMatrix = (numOfRows, numOfCols = numOfRows) ->
 			assert(numOfRows).withName('numOfRows').notNegative numOfRows
 			assert(numOfCols).withName('numOfCols').notNegative numOfCols
 			b = ((0 for j in [0...numOfCols]) for i in [0...numOfRows])
@@ -184,16 +182,12 @@

 			return {l: new Matrix(l), u: new Matrix(u), p: new Matrix(p) }

-		set: (row, col) ->
-			if not col?
-				col = 0
+		set: (row, col = 0) ->
 			m = @_m
 			to: (value) ->
 				m[row][col] = value

-		get: (row, col) ->
-			if not col?
-				col = 0
+		get: (row, col = 0) ->
 			@_m[row][col]

 		# @return (Matrix)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/matrix.coffee
+++ src/matrix.coffee
@@ -270,6 +270,7 @@

   ###*
   Returns a matrix that corresponds to a skew of skewX, skewY.
+
   @see Matrix#skew
   @param {Number} skewX The angle of skew in the x dimension.
   @param {Number} skewY The angle of skew in the y dimension.


Defensively copying fields before callback.

--- src/packet.coffee
+++ src/packet.coffee
@@ -262,19 +262,21 @@
       # callback arguments.
       #
       # The pattern is set to null, our terminal condition, before the callback,
-      # because the callback may specify a subsequent packet to parse.
+      # and the fields are defensively copied, because the callback may specify
+      # a subsequent packet to parse.
       else if ++@patternIndex == @pattern.length
-        @fields.push(@pipeline(@pattern[@patternIndex -1 ], @fields.pop()))
-
-        @fields.push(this)
+        fields = @fields.slice()
+
+        fields.push(@pipeline(@pattern[@patternIndex -1 ], fields.pop()))
+
+        fields.push(this)
         for p in @user or []
-          @fields.push(p)
+          fields.push(p)

         @pattern        = null
-
-        @callback.apply null, @fields
-
         @fields.length  = 0
+
+        @callback.apply null, fields

       # Otherwise we proceed to the next field in the packet pattern.
       else


try to use exports again

try to use exports again

--- src/parser.coffee
+++ src/parser.coffee
@@ -132,12 +132,8 @@
 // #{@fullPath}
 var #{scriptName(@name)} = (function(module) {
   var exports = module.exports;
-  //var module = { exports: {} }; // do not use exports only
   #{output.join('')}
-  if (module.exports !== exports) { // exports have been re-assigned.
-    module.exports = exports;
-  }
-  return module.exports;
+  return exports;
 })({exports: {}});

 """


Check for output size for pending list

Check for output size for pending list

--- src/pulsar.coffee
+++ src/pulsar.coffee
@@ -54,7 +54,10 @@
 		if response.changed
 			if response.task.action == 'deploy:pending'
 				pendingList = response.task.output.match(/#[0-9]+:[^\n]+/g)
-				msg.send pendingList.join "\n"
+				if _.size pendingList
+					msg.send pendingList.join "\n"
+				else
+					msg.send '#0000: nothing to deploy'

 		if response.task.status == 'RUNNING'
 			taskChangeListener taskId, msg


test 4

test 4

--- index.coffee
+++ index.coffee
@@ -34,7 +34,6 @@
         res.set 'Content-Type', 'text/plain'
         return res.send JSON.stringify res1, null, 2
       try
-        return res.send JSON.stringify(songs)
         (songs.tracks or songs).forEach (o) ->
           secs = Math.floor(o.duration / 1000)
           mins = Math.floor(secs / 60)


Handle file symlinks. Fixes #19

Handle file symlinks. Fixes #19

--- index.coffee
+++ index.coffee
@@ -35,10 +35,12 @@
 open = (filepath) ->
   if not filepath
     dirpath = getRootDir()
-  else if require('fs').lstatSync(filepath).isFile()
-    dirpath = require('path').dirname(filepath)
   else
-    dirpath = filepath
+    fs = require('fs')
+    if fs.lstatSync(fs.realpathSync(filepath)).isFile()
+      dirpath = require('path').dirname(filepath)
+    else
+      dirpath = filepath
   return if not dirpath
   command = atom.config.get 'open-terminal-here.command'
   require('child_process').exec command, cwd: dirpath, env: filterProcessEnv()


Log command and args

Log command and args

--- index.coffee
+++ index.coffee
@@ -32,4 +32,7 @@
       outputDirectory
     ]

+    console.log cmd
+    console.log args
+
     grunt.util.spawn({cmd, args}, done)


fix reply_to

fix reply_to

--- index.coffee
+++ index.coffee
@@ -166,7 +166,7 @@
           to: to_address
           subject: t "email_title.#{file_name.replace('.', '-')}", view_data
           html: mail_body
-          reply_to: options.reply_to
+          replyTo: options.reply_to
         , (err, info) ->
           if err
             callback err


deploying...

deploying...

--- index.coffee
+++ index.coffee
@@ -12,8 +12,6 @@
   app.use require("stylus").middleware
     src: __dirname + '/stylesheets'
     dest: __dirname + '/public'
-if "production" is NODE_ENV
-  app.get '/fonts/cracked.woff', (req, res) -> res.send 404
 app.use express.static __dirname + '/public'

 # Routes


add api call for collocation

add api call for collocation

--- index.coffee
+++ index.coffee
@@ -13,8 +13,12 @@
 app.use require("cors")()

 app.get("/api/get-chain.json", (request, response) ->
+    poetryFunctions().poetryChain().then (data) ->
+        response.json(data)
+)
+
+app.get("/api/get-collocation.json", (request, response) ->
     poetryFunctions().collocationNet().then (data) ->
-        # console.log(data)
         response.json(data)
 )


Updated test

Updated test

--- index.coffee
+++ index.coffee
@@ -6,8 +6,15 @@
 frame = new Frame process
 stdin.resume();

+collect = ''
 frame.on 'input', (data, rawdata) ->
-  console.log data, rawdata
+  if (rawdata[0] isnt 13)
+    frame.put '[2J'
+    frame.write rawdata
+    collect += data
+  else
+    console.log collect
+    collect = ''

 frame.on 'exit', (data) ->
   process.exit()


refactor slide

refactor slide

--- src/puzzle.coffee
+++ src/puzzle.coffee
@@ -159,11 +159,15 @@
         [row, col] = toPos.call(@, posid)
         [erow, ecol] = @position[@emptyID]
         if row == erow
-            handler?.call(@, @grid[row][c], @emptyID)
-            @swap([row, c], @emptyID) for c in [ecol..col]
+            startCol = ecol + (if ecol > col then -1 else 1)
+            for c in [startCol .. col]
+                handler?.call(@, @grid[row][c], @emptyID)
+                @swap([row, c], @emptyID)
         else if col == ecol
-            handler?.call(@, @grid[r][col], @emptyID)
-            @swap([r, col], @emptyID) for r in [erow..row]
+            startRow = erow + (if erow > row then -1 else 1)
+            for r in [startRow .. row]
+                handler?.call(@, @grid[r][col], @emptyID)
+                @swap([r, col], @emptyID)
         return @

     slidable: (posid) ->


Fix bootstrap modification tag

Fix bootstrap modification tag

--- bootstrap/connection.coffee
+++ bootstrap/connection.coffee
@@ -30,7 +30,7 @@
   ctx.run.on 'error', close
   ctx.run.on 'end', close
   attempts = 0
-  modified = true
+  modified = false
   do_private_key = ->
     return do_ssh() unless private_key
     ctx.log "Place SSH private key inside \"~/.ssh\""


updated material list in group actions dropdown

--- client/vue/components/group_page/group_actions_dropdown/group_actions_dropdown.coffee
+++ client/vue/components/group_page/group_actions_dropdown/group_actions_dropdown.coffee
@@ -68,29 +68,33 @@

   template:
     """
-

-        {{ GroupActionsDropdown }}
-
-

+

+      <v-menu md-position-mode="target-right target" class="lmo-dropdown-menu">
+        <v-btn slot="activator" class="group-page-actions__button">
+
+
+        </v-btn>
+        <v-list class="group-actions-dropdown__menu-content">
+          <v-list-tile v-if="canEditGroup()" @click="editGroup()" class="group-page-actions__edit-group-link">
+            <v-list-tile-title v-t="'group_page.options.edit_group'"></v-list-tile-title>
+          </v-list-tile>
+          <v-list-tile v-if="canChangeVolume()" @click="openChangeVolumeForm()" class="group-page-actions__change-volume-link">
+            <v-list-tile-title v-t="'group_page.options.email_settings'"></v-list-tile-title>
+          </v-list-tile>
+
+
+
+          <v-list-tile v-if="canExportData()" @click="openGroupExportModal()" class="group-page-actions__export-json">
+            <v-list-tile-title v-t="'group_page.options.export_data'"></v-list-tile-title>
+          </v-list-tile>
+          <v-list-tile v-if="canLeaveGroup()" @click="leaveGroup()" class="group-page-actions__leave-group">
+            <v-list-tile-title v-t="'group_page.options.leave_group'"></v-list-tile-title>
+          </v-list-tile>
+          <v-list-tile v-if="canArchiveGroup()" @click="archiveGroup()" class="group-page-actions__archive-group">
+            <v-list-tile-title v-t="'group_page.options.deactivate_group'"></v-list-tile-title>
+          </v-list-tile>
+        </v-list>
+      </v-menu>
+

     """


DevTools: Preview App, Preview CSS and compile implementation, based on Kodepad’s functions

--- client/DevTools/AppView.coffee
+++ client/DevTools/AppView.coffee
@@ -1,4 +1,6 @@
 class DevToolsMainView extends KDView
+
+  COFFEE = "//cdnjs.cloudflare.com/ajax/libs/coffee-script/1.6.3/coffee-script.min.js"

   viewAppended:->

@@ -34,3 +36,53 @@
                     .splitViews.BaseSplit.resizePanel "258px", 0, cb
               }
             ]
+  previewApp:->
+
+    time 'Compile took:'
+
+    return  if @_inprogress
+    @_inprogress = yes
+
+    {JSEditor, PreviewPane} = @workspace.activePanel.panesByName
+
+    @compiler (coffee)=>
+
+      code = JSEditor.getValue()
+
+      PreviewPane.container.destroySubViews()
+      window.appView = new KDView
+
+      try
+
+        coffee.compile code
+        coffee.run code
+
+        PreviewPane.container.addSubView window.appView
+
+      catch e
+
+        try window.appView.destroy?()
+        warn "Compile failed:", e
+
+      finally
+
+        delete window.appView
+        @_inprogress = no
+
+        timeEnd 'Compile took:'
+
+  previewCss:->
+
+    {CSSEditor, PreviewPane} = @workspace.activePanel.panesByName
+
+    @_css?.remove()
+
+    @_css = $ "<style scoped></style>"
+    @_css.html CSSEditor.getValue()
+
+    PreviewPane.container.domElement.prepend @_css
+
+  compiler:(callback)->
+
+    return callback @coffee  if @coffee
+    require [COFFEE], (@coffee)=> callback @coffee


terminal: do not instantiate `VMSelection` modal if it is not destroyed yet

`addNewTab` method callers are invoked by two different events at the
moment. This patch prevents instantiating modal more than one if those
events fire twice or more.

--- client/Terminal/AppView.coffee
+++ client/Terminal/AppView.coffee
@@ -294,8 +294,9 @@

         vmc = KD.getSingleton 'vmController'
         if vmc.vms.length > 1
-          vmselection = new VMSelection
-          vmselection.once 'VMSelected', (vm)=> @createNewTab vmName: vm, mode: 'create'
+          return  unless @vmselection.isDestroyed
+          @vmselection = new VMSelection
+          @vmselection.once 'VMSelected', (vm)=> @createNewTab vmName: vm, mode: 'create'
         else
           @createNewTab vmName: vmc.vms.first, mode: 'create'


Terminal: AppView: remove restoreTabs code we will add it back in future.

--- client/Terminal/AppView.coffee
+++ client/Terminal/AppView.coffee
@@ -42,67 +42,6 @@

     # {vmController} = KD.singletons
     # {terminalKites} = vmController
-    # vmController.ready @bound 'restoreTabs'
-
-  restoreTabs: ->
-    @fetchStorage (storage) =>
-      sessions = storage.getValue 'savedSessions'
-      return  unless sessions?.length
-
-      @notify
-        title     : "Checking for previous sessions"
-        cssClass  : "success"
-
-      # group sessions by alias
-      aliases = []
-      sessions.forEach (session) ->
-        [alias, sessionId] = session.split ':'
-        aliases.push alias  unless alias in aliases
-
-      # fetch vms and store in an object with the key of alias
-      KD.singletons.vmController.fetchGroupVMs no, (err, vms) =>
-        return warn err  if err
-        vmList = {}
-        vms.map (vm) ->
-          vmList[vm.hostnameAlias] = vm
-
-        {dash} = Bongo
-
-        # fetch all active vm sessions via terminal kites
-        activeSessions = []
-        {vmController, kontrol} = KD.singletons
-        kites =
-          if KD.useNewKites
-          then kontrol.kites.terminal
-          else vmController.terminalKites
-        queue = aliases.map (alias)->->
-          # when we have sessions from another xontext in appStorage
-          # prevent restoring sessions of terminals in that context
-          kites[alias]?.webtermGetSessions().then (sessions) =>
-            activeSessions = activeSessions.concat sessions
-            queue.fin()
-          .catch (err) ->
-            warn err
-            queue.fin()
-
-        # after all active sessions are fetched, compare them with last open sessions
-        sessionRestored = no
-        dash queue, =>
-          sessions.forEach (session) =>
-            [alias, sessionId] = session.split ':'
-            if sessionId in activeSessions
-              sessionRestored = yes
-              @createNewTab
-                vm         : vmList[alias]
-                session    : sessionId
-                mode       : 'resume'
-                shouldShow : no
-
-          unless sessionRestored
-            @notify
-              title     : "Your previous sessions are no longer online since your VM is turned off due to inactivity. \
-                           If you want always on VMs, you can upgrade your plan"
-              cssClass  : "fail"

   initPane: (pane) ->


client: sidebar: fix team logo on solo product

--- client/app/lib/mainview.coffee
+++ client/app/lib/mainview.coffee
@@ -47,7 +47,7 @@
     @createMainTabView()

     kd.singletons.mainController.ready =>
-      @createTeamLogo()
+      @createTeamLogo()  unless isKoding()
       @createAccountArea()  if isKoding()
       @setStickyNotification()
       @emit 'ready'
@@ -128,13 +128,12 @@

     closeHandle.hide()

-    @logoWrapper.addSubView @teamLogoWrapper = new kd.CustomHTMLView
-      tagName : 'div'
-      cssClass : 'team-logo-wrapper'
-
     @aside.addSubView @logoWrapper

-    if isTeamReactSide()
+    unless isKoding()
+      @logoWrapper.addSubView @teamLogoWrapper = new kd.CustomHTMLView
+        tagName : 'div'
+        cssClass : 'team-logo-wrapper'
       SidebarView = require './components/sidebar/view'
       @aside.addSubView @sidebar = new SidebarView
       return


Allow format syntax in panic macros

Allow format syntax in panic macros

--- grammars/rust.cson
+++ grammars/rust.cson
@@ -435,7 +435,7 @@
       {
         'comment': 'Core macro'
         'name': 'support.function.macro.core.rust'
-        'match': '\\b(assert|assert_eq|debug_assert|debug_assert_eq|panic|try|unimplemented|unreachable)!'
+        'match': '\\b(assert|assert_eq|debug_assert|debug_assert_eq|try|unimplemented|unreachable)!'
       }
       {
         'comment': 'Standard library macro'
@@ -444,7 +444,7 @@
       }
       {
         'comment': 'Format macro'
-        'begin': '\\b(?:((?:write|writeln)!)|((?:format|format_args|print|println)!))'
+        'begin': '\\b(?:((?:write|writeln|panic)!)|((?:format|format_args|print|println)!))'
         'end': '[,\\)\\]\\}]'
         'beginCaptures': {
           '1': { 'name': 'support.function.macro.core.rust' }


include dataset creator names in homepage search

--- client/code/view/subnav.coffee
+++ client/code/view/subnav.coffee
@@ -198,7 +198,7 @@
       t = $input.val()
       if t != ''
         $('.dataset.tile').each ->
-          if $(this).children('h3').text().toUpperCase().indexOf(t.toUpperCase()) >= 0
+          if $(this).children('h3, h4').text().toUpperCase().indexOf(t.toUpperCase()) >= 0
             $(this).show()
           else
             $(this).hide()


Updated BaseView BarImage

Updated BaseView BarImage

--- Framework/Views/BaseView.coffee
+++ Framework/Views/BaseView.coffee
@@ -6,7 +6,6 @@
       backgroundColor: root.app.settings.viewBackgroundColor
       backgroundGradient: root.app.settings.viewBackgroundGradient
       barColor: root.app.settings.viewTitleBarColor
-      barImage: root.app.settings.viewTitleBarImage
       backgroundImage: root.app.settings.viewBackgroundImage
       barImage: root.app.settings.barImage
       #fullscreen: false


Update rabbot.coffee

Update rabbot.coffee

--- src/rabbot.coffee
+++ src/rabbot.coffee
@@ -20,6 +20,7 @@
   'dragonmantank': 'I am programmed to say he gets it.'
   'dcousineau': 'He is one with the brisket.'
   'MANCHUCK': 'As the The secretary of WurstCon, he gets it '
+  'GeeH': 'Are you freaking kidding me?'
 }

 maxims = [


Added comment and updated formatting.

Added comment and updated formatting.

--- src/chalkboard.coffee
+++ src/chalkboard.coffee
@@ -23,7 +23,9 @@
 ##
 ## @name Getting Started
 ## @description
-## Install the module with: `npm install -g chalkboard`
+## The easiest way to use chalkboard will probably be to install it globally.
+##
+## To do so, install the module with: `npm install -g chalkboard`
 ##

 ##
@@ -256,7 +258,7 @@
 # @param {Integer} headerLevel The header level of the section name
 # @returns {String} Formatted markdown string based on key and value
 #
-_formatKeyValue = (key, value, newLine = true, headerLevel = 4) ->
+_formatKeyValue = (key, value, newLine = true, headerLevel = 3) ->
   def         = definitions[key]
   displayName = if def?.displayName? then def.displayName else key

@@ -269,12 +271,16 @@
       if _(element).isObject()
         if element.name?
           output += "**#{element.name}**  \n"
+        if element.description? and element.description
+          output += "#{element.description}  \n"
         if element.type?
           output += "Type: `#{element.type}`  \n"
-        if element.description?
-          output += "#{element.description}  \n"
+
+      # Everything else with just string
       else
         output += "-   #{element}  \n"
+
+      output += "\n"

   else if _(value).isString()
     output += "#{value}"
@@ -315,7 +321,9 @@
           omitList.push "url"
         else
           output += "#{section.name}"
+
         output +="\n==="
+
       output += "\n"
       omitList.push "name"


FSItem: fix promise call in `exists` method

--- client/finder/fs/fsitem.coffee
+++ client/finder/fs/fsitem.coffee
@@ -231,9 +231,11 @@
   isHidden:-> FSItem.isHidden @name

   exists:(callback=noop)->
-    @getKite().vmOn()
-
-    .fsExists(path: @getPath())
+    kite = @getKite()
+
+    kite.vmOn().then =>
+
+      kite.fsExists(path: @getPath())

     .nodeify(callback)


Fix for Payments.

Fix for Payments.

[#52022417]

--- client/helpers/payments.coffee
+++ client/helpers/payments.coffee
@@ -19,10 +19,12 @@

 Template.payment.events {
   'click .edit-payment': (event) ->
+    event.preventDefault()
     paymentId = recordIdFromRow event
     Session.set 'editingPayment', paymentId

   'click .remove-payment': (event) ->
+    event.preventDefault()
     paymentId = recordIdFromRow event
     payment = Payments.findOne(paymentId)
     expense = Expenses.findOne(payment.expenseId)
@@ -40,6 +42,7 @@
             showNavError "I couldn't remove the payment for some reason. Try again, and contact us if the problems persist."
             console.log error
   'click .mark-paid': (event) ->
+    event.preventDefault()
     payment = Payments.findOne(recordIdFromRow event)
     Payments.update payment._id, {
       $set: {


Workspace: Added floatingpanelauncher class to includes files.

--- client/landing/includes.coffee
+++ client/landing/includes.coffee
@@ -580,6 +580,7 @@
   "app/CommonViews/workspace/panes/videopane.coffee",
   "app/CommonViews/workspace/panel/panel.coffee",
   "app/CommonViews/workspace/workspacelayout.coffee",
+  "app/CommonViews/workspace/views/workspacefloatingpanelauncher.coffee",
   "app/CommonViews/workspace/workspace.coffee",

   # COLLABORATIVE WORKSPACE


Add config for badge, sound, alert and vibrate for Push Notifications

--- client/lib/cordova/push.coffee
+++ client/lib/cordova/push.coffee
@@ -1,7 +1,11 @@
 if Meteor.isCordova
 	Tracker.autorun ->
 		if RocketChat.settings.get('Push_enable') is true
-			Push.Configure {}
+			Push.Configure
+				badge: true
+				sound: true
+				alert: true
+				vibrate: true

 			Push.addListener 'token', (token) ->
 				Meteor.call 'log', 'token', arguments


Remove logs

Remove logs

--- client/lib/readMessages.coffee
+++ client/lib/readMessages.coffee
@@ -89,8 +89,6 @@
 			room.unreadFirstId = data.firstUnreadId

 			self.enable()
-			console.log arguments
-			# firstUnreadId = ChatMessage.findOne({rid: subscription.rid, ts: {$gt: subscription.ls}, 'u._id': {$ne: Meteor.userId()}}, {sort: {ts: 1}})?._id
 			if data.firstUnreadId?
 				$roomDom.find('.message#'+data.firstUnreadId).addClass('first-unread')


Allow using of left arrow to go back.

Allow using of left arrow to go back.

--- index.coffee
+++ index.coffee
@@ -7,9 +7,9 @@

 program = blessed.program()
-
 screen = blessed.screen
   dump: true
+

 screen.key ['escape', 'C-c', 'q'], -> process.exit 0

@@ -172,11 +172,13 @@

       window.add "#{ nameText } = [#{ typeText }] #{ valueText }"

+    onSelected = @selected configurator, keys, model
+
     window.key 't', @backToTop configurator
     window.key ['h', 'left'], @back configurator
     window.key 'r', @reset

-    window.on 'select', @selected configurator, keys, model
+    window.on 'select', onSelected

     window.focus()
     screen.render()


Add stderr

Add stderr

--- index.coffee
+++ index.coffee
@@ -43,13 +43,13 @@
     payload = message.payload;
     command = @commands[payload.command]
     return unless command?
-    command (error, stdout) =>
+    command (error, stdout, stderr) =>
       if  error?
         @emit 'error', error
         @emit 'message', devices: '*', error: error
         return

-      @emit 'message', devices: '*', stdout: stdout
+      @emit 'message', devices: '*', stdout: stdout, stderr

   onConfig: (device) =>
     @setOptions device.options
@@ -92,7 +92,7 @@
         error.stdout = stdout
         error.stderr = stderr
         return callback error
-      callback null, stdout
+      callback null, stdout, stderr

 module.exports =


Load / run scripts synchronously

Load / run scripts synchronously

--- index.coffee
+++ index.coffee
@@ -3,10 +3,9 @@

 module.exports = (robot, scripts) ->
     scriptsPath = path.resolve(__dirname, 'src')
-    fs.exists scriptsPath, (exists) ->
-        if exists
-            for script in fs.readdirSync(scriptsPath)
-                if scripts? and '*' not in scripts
-                    robot.loadFile(scriptsPath, script) if script in scripts
-                else
-                    robot.loadFile(scriptsPath, script)+    if fs.existsSync scriptsPath
+        for script in fs.readdirSync(scriptsPath).sort()
+            if scripts? and '*' not in scripts
+                robot.loadFile(scriptsPath, script) if script in scripts
+            else
+                robot.loadFile(scriptsPath, script)


Only open GUIs on right-click if not crouching

Useful to shift-right-click to place blocks on workbenches (etc.),
as normally right-clicking opens the GUI.

--- index.coffee
+++ index.coffee
@@ -246,7 +246,7 @@
     # TODO: major refactor

     # 1. block interaction TODO: have blocks handle this
-    if target.voxel?
+    if target.voxel? and !game.buttons.crouch
       clickedBlockID = game.getBlock(target.voxel)
       clickedBlock = registry.getBlockName(clickedBlockID)
       if clickedBlock == 'workbench'


scaling_crop

--- app/assets/javascripts/ab_admin/components/croppable_image.js.coffee
+++ app/assets/javascripts/ab_admin/components/croppable_image.js.coffee
@@ -10,8 +10,14 @@
     _.defaults(@options, CroppableImage.crop_defaults)
     @options.onSelect = @setCropData
     @options.onChange = @setCropData
-
-    $('.fancybox-image:first').Jcrop @options
+    $img = $('.fancybox-image:first')
+    @natural_size =
+      w: $img[0].naturalWidth
+      h: $img[0].naturalHeight
+    @current_size =
+      w: $img.width()
+      h: $img.height()
+    $img.Jcrop @options
     $('.fancybox-nav').hide()

     $cont = $('.fancybox-outer:first')
@@ -25,8 +31,19 @@
   cropHandler: (e) =>
     e.preventDefault()
     asset_id = to_i($('.fancybox-image:first').attr('src').match(/\/[\d\/]{2,}\//)[0].replace(/\//g, ''))
-    $asset = $("#asset_#{asset_id}")
+    $asset = $(@options.asset_selector || "#asset_#{asset_id}")
+    @scalingCrop()
     geometry = [@cropData['w'], @cropData['h'], @cropData['x'], @cropData['y']].join(',')
-    $.post "/admin/assets/#{$asset.data('id')}/crop", {geometry: geometry}, (data) =>
+    $.post "/admin/assets/#{asset_id}/crop", {geometry: geometry}, (data) =>
       $asset.replaceWith @el.data('assets').template(data.asset)
-      $.fancybox.close()+      $.fancybox.close()
+
+  scalingCrop: ->
+    return unless @natural_size['w'] > @current_size['w'] && @natural_size['h'] > @current_size['h']
+    w_factor = @natural_size['w'] / @current_size['w']
+    h_factor = @natural_size['h'] / @current_size['h']
+    @cropData['x'] = Math.ceil(@cropData['x'] * h_factor) if @cropData['x'] > 0
+    @cropData['y'] = Math.ceil(@cropData['y'] * w_factor) if @cropData['y'] > 0
+
+    @cropData['w'] = Math.ceil(@current_size['w'] * w_factor )
+    @cropData['h'] = Math.ceil(this.cropData['h'] * h_factor )


server - added graceful shutdown

server - added graceful shutdown

--- index.coffee
+++ index.coffee
@@ -15,4 +15,25 @@
   return

 # start server
-server.start()+server.start()
+
+# ==========
+
+# graceful shutdown
+process.on 'exit', ->
+  cache.db.quit()
+  cache.db.shutdown() if process.env.NODE_ENV is 'development'
+  console.log '[INFO] Redis connection ended. Exiting stats.bower.io app.'
+  return
+
+# shutdown via Ctrl+C in dev
+process.on 'SIGINT', ->
+  console.log 'Gracefully shutting down from SIGINT (Crtl-C)'
+  process.exit()
+  return
+
+# usually called with kill
+process.on 'SIGTERM', ->
+  console.log 'Parent SIGTERM detected (kill)'
+  process.exit()
+  return


Adding record deletion option

Adding record deletion option

--- index.coffee
+++ index.coffee
@@ -25,14 +25,22 @@
     process.exit(1)

 cli.parse
-  'watch':    ['w', 'Monitor for changes after first check', 'boolean']
+  'delete':   ['d', 'Delete all records', 'boolean']
   'port':     ['p', 'TCP port to check', 'number', 80]
   'servers':  ['s', 'whitespace-delimited list of servers (which may use brace expansion)', 'string']
+  'watch':    ['w', 'Monitor for changes after first check', 'boolean']

 cli.main (args, options) ->
   recordName = (args[1] || process.exit(1)) + '.'
-  servers = _.flatten((options.servers || []).split(/\s+/).map(braces))
+  servers = _.flatten((options.servers ? '').split(/\s+/).map(braces))
   tcpPort = options.port
+
+  if options.watch and options['delete']
+    cli.fatal("Deletion is a once-only operation.")
+
+  if _.isEmpty(options.servers) and !options['delete']
+    cli.fatal("Must specify servers unless deleting all records.")
+

   designate = require('./designate')(recordName)

@@ -43,16 +51,24 @@

   updateDesignateRecords = do () ->
     executing = null
+
+    sitrepEmptyTmpl = Hogan.compile(
+      "{{name}} {{whenchecked}} has no records.")
     sitrepTmpl = Hogan.compile(
       "{{name}} {{type}} records {{whenchecked}}:\t{{#addrs}} {{.}}{{/addrs}}")
     sitrep = (whenChecked) -> (currentRecords) ->
-      grouped = _.groupBy(currentRecords, 'type')
-      Object.keys(grouped).forEach (type) ->
-        cli.debug sitrepTmpl.render
+      if _.isEmpty(currentRecords)
+        cli.debug sitrepEmptyTmpl.render
           name: _.trim(recordName, '.')
-          type: type
           whenchecked: whenChecked
-          addrs: _.pluck(grouped[type], "data")
+      else
+        grouped = _.groupBy(currentRecords, 'type')
+        Object.keys(grouped).forEach (type) ->
+          cli.debug sitrepTmpl.render
+            name: _.trim(recordName, '.')
+            whenchecked: whenChecked
+            type: type
+            addrs: _.pluck(grouped[type], "data")
       currentRecords
     fn = () ->
       designate.list()
@@ -115,6 +131,8 @@
       resolveAndUpdateMonitors()
         .then () ->
           Q.delay(60000)
+  else if options['delete']
+    updateDesignateRecords()
   else
     cli.debug("Resolving once only. Use -w to monitor indefinitely.")
     finished = () ->


[fix] Corrected the Prioritization View to save changes when tickets are moved around using the keyboard shortcuts

--- app/assets/javascripts/houston-scheduler/views/sequence2_view.coffee
+++ app/assets/javascripts/houston-scheduler/views/sequence2_view.coffee
@@ -123,11 +123,18 @@
         $ticket.remove().appendTo('#sequence2_unsorted').data('multiselectable', true).pseudoHover()
       else
         $ticket.remove().insertBefore($target).data('multiselectable', true).pseudoHover()
+
+      @delayedNotifier.trigger()
+      @adjustVelocityIndicatorHeight()

   moveUp: ->
     $ticket = $('.sequence2-ticket.selected')
     $prev = $ticket.prev()
-    $ticket.remove().insertBefore($prev).data('multiselectable', true).pseudoHover() if $prev.length > 0
+    if $prev.length > 0
+      $ticket.remove().insertBefore($prev).data('multiselectable', true).pseudoHover()
+
+      @delayedNotifier.trigger()
+      @adjustVelocityIndicatorHeight()

   moveRight: ->
     $ticket = $('#sequence2_unsorted .sequence2-ticket.selected')
@@ -138,12 +145,18 @@
         $ticket.remove().appendTo('#sequence2_sorted').data('multiselectable', true).pseudoHover()
       else
         $ticket.remove().insertBefore($target).data('multiselectable', true).pseudoHover()
+
+      @delayedNotifier.trigger()
+      @adjustVelocityIndicatorHeight()

   moveDown: ->
     $ticket = $('.sequence2-ticket.selected')
     $next = $ticket.next()
-    $ticket.remove().insertAfter($next).data('multiselectable', true).pseudoHover() if $next.length > 0
-
+    if $next.length > 0
+      $ticket.remove().insertAfter($next).data('multiselectable', true).pseudoHover()
+
+      @delayedNotifier.trigger()
+      @adjustVelocityIndicatorHeight()

   moveSelectionLeft: ->
     $ticket = $('#sequence2_sorted .sequence2-ticket.selected')


Move inventory window closer to center

Move inventory window closer to center

--- index.coffee
+++ index.coffee
@@ -187,8 +187,8 @@
         container = iw.createContainer()

         container.style.position = 'absolute'
-        container.style.top = '100px'
-        container.style.left = '100px'
+        container.style.top = '20%'
+        container.style.left = '30%'
         container.style.zIndex = 1
         document.body.appendChild(container)
       else


Revert for now "Test loading voxel-engine via voxel-cs"

Requires many more changes to client/server plugin loading/API

This reverts commit d6402135e0991908f83c57b060e373c917f08b72.

Ref GH-26

--- index.coffee
+++ index.coffee
@@ -52,7 +52,7 @@
   plugins = createPlugins null, {require: require}

   configuration =
-    'voxel-cs': {commonOpts:
+    'voxel-engine':
       appendDocument: true
       exposeGlobal: true  # for debugging

@@ -102,7 +102,8 @@
         'T': 'console'
         '/': 'console2'
         '.': 'console3'
-    }
+
+    #'voxel-cs': {} # TODO

     'voxel-registry': {}
     'craftingrecipes': {}