Remove focus of _dequeue

Remove focus of _dequeue

--- spec/request-queue-spec.coffee
+++ spec/request-queue-spec.coffee
@@ -29,7 +29,7 @@

       expect(callback).toHaveBeenCalledWith(job)

-  fdescribe "::_dequeue()", ->
+  describe "::_dequeue()", ->
     beforeEach ->
       spyOn queue, "_checkQueue"


:green_heart: Fix remaining broken focus tests

--- spec/table-element-spec.coffee
+++ spec/table-element-spec.coffee
@@ -780,7 +780,7 @@
           expect(editorElement.offsetHeight).toBeCloseTo(cell.offsetHeight, -2)

         it 'gives the focus to the editor', ->
-          expect(editorElement.matches('.is-focused')).toBeTruthy()
+          expect(document.activeElement).toBe(editorElement)

         it 'fills the editor with the cell value', ->
           expect(editor.getText()).toEqual('key')
@@ -1696,7 +1696,7 @@
       expect(editorElement.offsetHeight).toBeCloseTo(cell.offsetHeight, -2)

     it 'gives the focus to the editor', ->
-      expect(editorElement.matches('.is-focused')).toBeTruthy()
+      expect(document.activeElement).toBe(editorElement)

     it 'fills the editor with the cell value', ->
       expect(editor.getText()).toEqual('row0')


Revert change as it doesn't fix the duplication problem

--- lib/mixins/canvas-drawer.coffee
+++ lib/mixins/canvas-drawer.coffee
@@ -438,11 +438,11 @@
         else if change.end < range.start or change.start > range.end
           newIntactRanges.push(range)
         else
-          # if change.start > range.start
-          #   newIntactRanges.push(
-          #     start: range.start
-          #     end: change.start - 1
-          #     domStart: range.domStart)
+          if change.start > range.start
+            newIntactRanges.push(
+              start: range.start
+              end: change.start - 1
+              domStart: range.domStart)
           if change.end < range.end
             newIntactRanges.push(
               start: change.end + change.screenDelta + 1


Fix reseting for select2. Pass product data around as an object.

--- app/assets/javascripts/admin/suppliers_code.js.coffee
+++ app/assets/javascripts/admin/suppliers_code.js.coffee
@@ -34,20 +34,21 @@
     # Text displayed in the select menu
     formatSelection: (product) ->
       $(@element).parents("fieldset").data
-        sku: product.sku
-        name: product.name
+        product:
+          sku: product.sku
+          name: product.name
       product.name

   # Handle clicks on "Add button"
   # Add variant name, sku and qty to the table
   $('#suppliers_report [data-hook="add_button"]').on "click", ->
     $fieldset = $(this).parents("fieldset")
-    sku = $fieldset.data("sku")
-    name = $fieldset.data("name")
-    qty = $fieldset.find('[data-hook="add_quantity"] input').val()
+    product = $fieldset.data("product")

     # If no product was chosen from dropdown sku will not exist and we shouldn't add anything
-    return false unless sku
+    return false unless product
+
+    product.qty = $fieldset.find('[data-hook="add_quantity"] input').val()

     # Hide email content if visible
     textarea = $(this).parents('.supplier_products_table').find('[data-hook="email_content"]')
@@ -55,12 +56,12 @@
     textarea.slideUp() if textarea.is(':visible')

     $table = $(this).parents('.supplier_products_table').find('tbody')
-    $table.append(new_row_template({name: name, sku: sku, qty: qty}))
+    $table.append new_row_template(product)

     # Reset fields
-    $fieldset.data("sku", "").data("name", "").data("qty", 0)
-    # $fieldset.find('.variant_autocomplete').select2('data', null)
-    $fieldset.find('.variant_autocomplete').select2('data', {})
+    $fieldset.find('input[type="hidden"].variant_autocomplete')
+      .data('product', null)
+      .select2('data', null)

     return false


add toto comment

add toto comment

--- app/assets/javascripts/controllers/my_prefs.js.coffee
+++ app/assets/javascripts/controllers/my_prefs.js.coffee
@@ -26,6 +26,9 @@

   validateAndSaveForm: ->
+    # TODO This depends on the template element.
+    #      Can we pass it here from the view?
+    #
     errorCount = ($ '#my_prefs form div.error:visible').length
     if errorCount == 0
       @get('model').save()


Fix an issue with the Keydown/keyup and edition

--- app/assets/javascripts/rails_powergrid/grid.js.coffee
+++ app/assets/javascripts/rails_powergrid/grid.js.coffee
@@ -253,8 +253,13 @@

   handleKeyPress: (evt) ->

+    contentWrapper = @getDOMNode().querySelector(".powergrid-data-content-wrapper")
+
     switch evt.key
       when "ArrowDown"
+        #Blur the current focused event, in case of cell edition
+        contentWrapper.focus() if document.activeElement isnt contentWrapper
+
         evt.preventDefault()
         sel = Math.min(@lastRowPosition+1, @state.data.length-1)

@@ -263,6 +268,8 @@
         else
           @setSelection sel
       when "ArrowUp"
+        contentWrapper.focus() if document.activeElement isnt contentWrapper
+
         evt.preventDefault()
         sel = Math.max(@lastRowPosition-1, 0)
         if(evt.shiftKey)


Refactored key input handling. I hope it's an improvement...

--- app/assets/javascripts/roofpig/InputHandler.js.coffee
+++ app/assets/javascripts/roofpig/InputHandler.js.coffee
@@ -1,6 +1,8 @@
 #= require roofpig/utils

+#This is all global data and functions. Think of it as a "singleton" class.
 class @InputHandler
+

   @set_active_display: (new_active) ->
     @dom_handler.has_focus(false) if @active_display
@@ -12,43 +14,53 @@
     @dom_handler.has_focus(true)

   @key_down: (e) ->
-    if e.shiftKey
-      turns = 3
+    [key, shift, ctrl] = [e.keyCode, e.shiftKey, e.ctrlKey]
+
+    if key == key_tab
+      new_focus = if shift then @active_display.previous_display() else @active_display.next_display()
+      this.set_active_display(new_focus)
+
+    else if key == key_up_arrow
+      @active_display.to_end()
+
+    else if key in button_keys
+      this._fake_click_down(this._button_for(key, shift))
+
+    else if key in rotate_keys
+      axis = switch key
+        when key_C, key_Z then 'up'
+        when key_A, key_D then 'dr'
+        when key_S, key_X then 'dl'
+      turns = switch key
+        when key_C, key_A, key_S then 1
+        when key_Z, key_D, key_X then -1
+      this._rotate(axis, turns)
+
+    else if key in turn_keys
+      turns = if shift then 3 else if ctrl then 2 else 1
+      this._move("#{turn_for[key]}#{turns}")
+
     else
-      turns = if e.ctrlKey then 2 else 1
+      return false

-    switch e.keyCode
-      when key_tab
-        new_focus = if e.shiftKey then @active_display.previous_display() else @active_display.next_display()
-        this.set_active_display(new_focus)
-      when key_home, key_down_arrow then this._fake_click_down(@dom_handler.reset)
-      when key_left_arrow  then b = (if e.shiftKey then @dom_handler.reset else @dom_handler.prev); this._fake_click_down(b)
-      when key_right_arrow then b = (if e.shiftKey then @dom_handler.active_play_or_pause else @dom_handler.next); this._fake_click_down(b)
-      when key_space       then this._fake_click_down(@dom_handler.active_play_or_pause)
-      when key_C then this._rotate('up', 1)
-      when key_Z then this._rotate('up',-1)
-      when key_A then this._rotate('dr', 1)
-      when key_D then this._rotate('dr',-1)
-      when key_S then this._rotate('dl', 1)
-      when key_X then this._rotate('dl',-1)
-      when key_J then this._move("U#{turns}")
-      when key_K then this._move("F#{turns}")
-      when key_L then this._move("R#{turns}")
-      else
-        handled = false
-
-    !handled
+  @_button_for: (key, shift) ->
+    switch key
+      when key_home, key_down_arrow
+        @dom_handler.reset
+      when key_left_arrow
+        if shift then @dom_handler.reset else @dom_handler.prev
+      when key_right_arrow
+        if shift then @dom_handler.active_play_or_pause else @dom_handler.next
+      when key_space
+        @dom_handler.active_play_or_pause

   @key_up: (e) ->
-    switch e.keyCode
-      when key_home, key_left_arrow, key_right_arrow, key_space
-        if @down_button
-          this._fake_click_up(@down_button)
-          @down_button = null
-      else
-        handled = false
-
-    !handled
+    button_key = e.keyCode in button_keys
+    if button_key
+      if @down_button
+        this._fake_click_up(@down_button)
+        @down_button = null
+    return button_key

   @_fake_click_down: (button) ->
     unless button.attr("disabled")
@@ -106,3 +118,12 @@
   key_S = 83
   key_X = 88
   key_Z = 90
+
+  button_keys = [key_tab, key_space, key_home, key_left_arrow, key_right_arrow, key_down_arrow]
+  rotate_keys = [key_C, key_Z, key_A, key_D, key_S, key_X]
+  turn_keys   = [key_J, key_K, key_L]
+
+  turn_for = {}
+  turn_for[key_J] = "U"
+  turn_for[key_K] = "F"
+  turn_for[key_L] = "R"


More keyboard nav fancifulness. More work needed.

--- app/assets/javascripts/roofpig/InputHandler.js.coffee
+++ app/assets/javascripts/roofpig/InputHandler.js.coffee
@@ -23,9 +23,9 @@
       when key_tab
         new_focus = if e.shiftKey then @active_display.previous_display() else @active_display.next_display()
         this.set_active_display(new_focus)
-      when key_home        then this._fake_click_down(@dom_handler.reset)
-      when key_left_arrow  then this._fake_click_down(@dom_handler.prev)
-      when key_right_arrow then this._fake_click_down(@dom_handler.next)
+      when key_home, key_down_arrow then this._fake_click_down(@dom_handler.reset)
+      when key_left_arrow  then b = (if e.shiftKey then @dom_handler.reset else @dom_handler.prev); this._fake_click_down(b)
+      when key_right_arrow then b = (if e.shiftKey then @dom_handler.active_play_or_pause else @dom_handler.next); this._fake_click_down(b)
       when key_space       then this._fake_click_down(@dom_handler.active_play_or_pause)
       when key_C then this._rotate('up', 1)
       when key_Z then this._rotate('up',-1)
@@ -45,10 +45,10 @@
     unhandled = false

     switch e.keyCode
-      when key_home        then this._fake_click_up(@dom_handler.reset)
-      when key_left_arrow  then this._fake_click_up(@dom_handler.prev)
-      when key_right_arrow then this._fake_click_up(@dom_handler.next)
-      when key_space       then this._fake_click_up(@dom_handler.active_play_or_pause)
+      when key_home, key_left_arrow, key_right_arrow, key_space
+        if @down_button
+          this._fake_click_up(@down_button)
+          @down_button = null
       else
         unhandled = true

@@ -56,6 +56,7 @@

   @_fake_click_down: (button) ->
     unless button.attr("disabled")
+      @down_button = button
       button.addClass('roofpig-button-fake-active')

   @_fake_click_up: (button) ->
@@ -97,7 +98,9 @@
   key_space = 32
   key_home = 36
   key_left_arrow = 37
+  key_up_arrow = 38
   key_right_arrow = 39
+  key_down_arrow = 40
   key_A = 65
   key_C = 67
   key_D = 68


started work on pagination headers

started work on pagination headers

--- app/assets/javascripts/species/models/store.js.coffee
+++ app/assets/javascripts/species/models/store.js.coffee
@@ -1,7 +1,12 @@
 Species.Adapter = DS.RESTAdapter.reopen
-  namespace: 'api'
+  namespace: 'api/v1'
+  ajax: (url, type, hash) ->
+    hash.success = (json, e, xhr) ->
+      @pagination = xhr.getResponseHeader('X-Pagination')
+      console.log(xhr.getResponseHeader('X-Pagination'))
+    return this._super(url, type, hash)

 Species.Store = DS.Store.extend
   revision: 12
-  adapter: 'DS.RESTAdapter'+  adapter: 'DS.RESTAdapter'


empty out flash wrapper before appending again

--- app/assets/javascripts/spree/frontend/flash.js.coffee
+++ app/assets/javascripts/spree/frontend/flash.js.coffee
@@ -11,8 +11,10 @@
   ), showTime

 window.show_flash = (type, message) ->
-  $('.address_validator').before("
")
   $flashWrapper = $(".js-flash-wrapper")
+  if $flashWrapper.length == 0
+    $('.address_validator').before("
")
+  $flashWrapper.empty()
   flash_div = $("
")
   $flashWrapper.prepend(flash_div)
   flash_div.html(message).show().delay(showTime).fadeOut(fadeOutTime)


Optimization so we don't create a bunch of unnecessary arrays

--- lib/project/results-view.coffee
+++ lib/project/results-view.coffee
@@ -55,6 +55,8 @@
     resultView.renderMatches(null) if resultView

   renderResults: ({renderAll}={}) ->
+    return unless @shouldRenderMoreResults()
+
     paths = @model.getPaths()
     for filePath in paths[@lastRenderedResultIndex..]
       result = @model.getResult(filePath)


Print uncaught exceptions in the test runner.

--- tests/run.coffee
+++ tests/run.coffee
@@ -21,6 +21,10 @@
     console.error e.stack
     process.exit 1

+  process.on 'uncaughtException', (err) ->
+    console.log '\n\nUncaught Exception', err, '\n'
+    console.log err.stack, '\n'
+
   console.log "Running Batman test suite. #{tests.length} files required."
   qqunit.Runner.run tests, (stats) ->
     process.exit stats.failed


linebreak

linebreak

--- lib/rubocop-auto-correct.coffee
+++ lib/rubocop-auto-correct.coffee
@@ -14,10 +14,12 @@
         @handleEvents(editor)

     @subscriptions.add atom.commands.add 'atom-workspace',
-      'rubocop-auto-correct:current-file': => @run(atom.workspace.getActiveTextEditor())
+      'rubocop-auto-correct:current-file': =>
+        @run(atom.workspace.getActiveTextEditor())
       'rubocop-auto-correct:toggle-auto-run': => @toggleAutoRun()
       'rubocop-auto-correct:toggle-notification': => @toggleNotification()
-      'rubocop-auto-correct:toggle-only-fixes-notification': => @toggleOnlyFixesNotification()
+      'rubocop-auto-correct:toggle-only-fixes-notification': =>
+        @toggleOnlyFixesNotification()
       'rubocop-auto-correct:toggle-correct-file': => @toggleCorrectFile()
       'rubocop-auto-correct:toggle-debug-mode': => @toggleDebugMode()

@@ -55,7 +57,9 @@
   toggleOnlyFixesNotification: ->
     setting = atom.config.get('rubocop-auto-correct.onlyFixesNotification')
     atom.config.set('rubocop-auto-correct.onlyFixesNotification', !setting)
-    atom.notifications.addSuccess(@toggleMessage("Only fixes notification", !setting))
+    atom.notifications.addSuccess(
+      @toggleMessage("Only fixes notification", !setting)
+    )

   toggleCorrectFile: ->
     setting = atom.config.get('rubocop-auto-correct.correctFile')
@@ -147,7 +151,8 @@
       "Rubocop command is not found.",
       { detail: '''
       When you don't install rubocop yet, Run `gem install rubocop` first.\n
-      If you already installed rubocop, Please check package setting at `Rubocop Command Path`.
+      If you already installed rubocop,
+      Please check package setting at `Rubocop Command Path`.
       ''' }
     )

@@ -173,13 +178,15 @@
         for offense in file.offenses
           if offense.corrected
             atom.notifications.addSuccess(
-              "Line: #{offense.location.line}, Col:#{offense.location.column} (FIXED)",
+              "Line: #{offense.location.line},
+              Col:#{offense.location.column} (FIXED)",
               { detail: "#{offense.message}" }
             ) if notification
           else
             if !onlyFixesNotification
               atom.notifications.addWarning(
-                "Line: #{offense.location.line}, Col:#{offense.location.column}",
+                "Line: #{offense.location.line},
+                Col:#{offense.location.column}",
                 { detail: "#{offense.message}" }
               ) if notification


:lipstick:

:lipstick:

--- lib/space-pen-extensions.coffee
+++ lib/space-pen-extensions.coffee
@@ -52,7 +52,7 @@

     @subview '__', editorBlock

-    # TODO: maybe take this out. It might not add that much to the docs?
+  # TODO: maybe take this out. It might not add that much to the docs?
   exampleOverlaySelectList: (array) ->
     selectList = new OverlaySelectListView array, (item) ->
       $$ ->


repository.coffee no longer sets steward in to debug mode

--- lib/web/views/repository.coffee
+++ lib/web/views/repository.coffee
@@ -26,7 +26,7 @@
   router.fallbackRoute = (url) -> alert("Unknown matchedRoute: " + url);
   router.hashBaseUrl="/repository"
 #  router.pushStateSupport = false
-  router.debug = true
+#  router.debug = true
   router.initRouting()
   window.router = router


remove useless prototype activation

remove useless prototype activation

--- MediaAdminBundle/Resources/public/coffee/view/MediaFormView.coffee
+++ MediaAdminBundle/Resources/public/coffee/view/MediaFormView.coffee
@@ -25,8 +25,4 @@
     @options.domContainer.html @$el
     $('.js-widget-title', @options.domContainer).html @options.title
     $('.back-to-list', @options.domContainer).remove()
-    $("[data-prototype]", @options.domContainer).each ->
-      PO.formPrototypes.addPrototype $(this)
-      return
-    return
 )


Added Packet.bodySize; Ensure proper headerSize when no source is given

--- src/wrathnet/net/packet.coffee
+++ src/wrathnet/net/packet.coffee
@@ -13,8 +13,7 @@
 class WrathNet.net.Packet extends ByteBuffer

   # Creates a new packet with given opcode from given source or length
-  constructor: (opcode, source=@constructor.HEADER_SIZE, outgoing=true) ->
-    super source, ByteBuffer.LITTLE_ENDIAN
+  constructor: (opcode, source, outgoing=true) ->

     # Holds the opcode for this packet
     @opcode = opcode
@@ -22,12 +21,22 @@
     # Whether this packet is outgoing or incoming
     @outgoing = outgoing

+    # Default source to header size if not given
+    unless source?
+      source = @headerSize
+
+    super source, ByteBuffer.LITTLE_ENDIAN
+
     # Seek past opcode to reserve space for it when finalizing
     @index = @headerSize

-  # Header size in bytes for both incoming and outgoing packets
+  # Header size in bytes
   @getter 'headerSize', ->
     return @constructor.HEADER_SIZE
+
+  # Body size in bytes
+  @getter 'bodySize', ->
+    return @length - @headerSize

   # Retrieves the name of the opcode for this packet (if available)
   @getter 'opcodeName', ->
@@ -36,7 +45,7 @@
   # Short string representation of this packet
   toString: ->
     opcode = ('0000' + @opcode.toString(16).toUpperCase()).slice(-4)
-    return '[' + @constructor.name + '; Opcode: ' + (@opcodeName or 'UNKNOWN') + ' (0x' + opcode + '); Length: ' + @length + '; Index: ' + @_index + ']'
+    return "[#{@constructor.name}; Opcode: #{@opcodeName or 'UNKNOWN'} (0x#{opcode}); Length: #{@length}; Body: #{@bodySize}; Index: #{@_index}]"

   # Finalizes this packet
   finalize: ->


Kindly request buffers as a socket's binary type

--- src/wrathnet/net/socket.coffee
+++ src/wrathnet/net/socket.coffee
@@ -48,6 +48,7 @@
       @uri = 'ws://' + @host + ':' + @port

       @socket = new WebSocket(@uri, 'binary')
+      @socket.binaryType = 'arraybuffer'

       @socket.onopen = (e) =>
         @on.connect.dispatch(@, e)


advanced settings repos

advanced settings repos

--- client/app/Applications/Ace.kdapplication/AppController.coffee
+++ client/app/Applications/Ace.kdapplication/AppController.coffee
@@ -25,12 +25,12 @@
       { type      : "separator" }
       { title     : "Preview",             eventName : "preview" }
       { type      : "separator" }
+      { title     : "Advanced Settings",   viewName  : "advancedSettings" }
+      { type      : "separator" }
       { title     : "Recently Opened",     viewName  : "recents"}
       { title     : "Reopen Latest Files", eventName : "reopen" }
       { type      : "separator" }
       { title     : "Exit",                eventName : "exit" }
-      { type      : "separator" }
-      { title     : "Advanced Settings",   viewName  : "advancedSettings" }
     ]
     fileTypes     : [
       "php", "pl", "py", "jsp", "asp", "aspx", "htm", "html", "phtml","shtml",


Remove SplitRegionHandlerView

Remove SplitRegionHandlerView

--- client/ide/lib/views/tabview/region/splitregionpartview.coffee
+++ client/ide/lib/views/tabview/region/splitregionpartview.coffee
@@ -1,20 +0,0 @@
-kd                = require 'kd'
-KDCustomHTMLView  = kd.CustomHTMLView
-
-
-module.exports = class SplitRegionPartView extends KDCustomHTMLView
-
-  CSS_CLASS = 'show'
-
-  constructor: (options = {}, data) ->
-
-    options.cssClass  = kd.utils.curry 'region', options.direction
-
-    super options, data
-
-    @addSubView new KDCustomHTMLView
-      tagName   : 'span'
-      partial   : 'Drop to move source pane to this split'
-
-    @addSubView @holder = new KDCustomHTMLView
-


profile: tooltips for hitenterviews

profile: tooltips for hitenterviews

--- client/landing/app/MainApp/lazy/staticprofilecontroller.coffee
+++ client/landing/app/MainApp/lazy/staticprofilecontroller.coffee
@@ -218,6 +218,13 @@
         @handleLinks[type].addSubView new StaticHandleInput
           service     : type
           delegate    : @
+          tooltip     :
+            title     : "Enter your #{handleMap[type].text} handle and hit enter to save."
+            placement : 'right'
+            direction : 'center'
+            offset    :
+              left    : 5
+              top     : 2
           attributes  :
             spellcheck: no
           callback    :(value)->


Increase SavesDelayed debounce to 200ms.

We're trying to eliminate some recurring test failures.
This may change more in the future.

--- app/assets/javascripts/mixins/controllers/saves_delayed.js.coffee
+++ app/assets/javascripts/mixins/controllers/saves_delayed.js.coffee
@@ -2,7 +2,7 @@
   saveInFlight: false

   saveDelayed: ->
-    Ember.run.debounce(@, @saveModel, 100)
+    Ember.run.debounce(@, @saveModel, 200)

   saveModel: ->
     unless @get('saveInFlight')


fix exceeded lock timeout logging

fix exceeded lock timeout logging

we were logging this after failing to get the lock, this stops that

--- services/web/app/coffee/infrastructure/LockManager.coffee
+++ services/web/app/coffee/infrastructure/LockManager.coffee
@@ -11,27 +11,25 @@
 	SLOW_EXECUTION_THRESHOLD: 5000 # 5s, if execution takes longer than this then log

 	runWithLock: (namespace, id, runner = ( (releaseLock = (error) ->) -> ), callback = ( (error) -> )) ->
-
-		# The lock can expire in redis but the process carry on. This setTimout call
-		# is designed to log if this happens.
-		#
-		# error is defined here so we get a useful stacktrace
-		lockReleased = false
+		# This error is defined here so we get a useful stacktrace
 		slowExecutionError = new Error "slow execution during lock"
-		countIfExceededLockTimeout = () ->
-			if !lockReleased
-				metrics.inc "lock.#{namespace}.exceeded_lock_timeout"
-				logger.log "exceeded lock timeout", { namespace, id, slowExecutionError }
-
-		setTimeout countIfExceededLockTimeout, LockManager.REDIS_LOCK_EXPIRY * 1000

 		timer = new metrics.Timer("lock.#{namespace}")
 		key = "lock:web:#{namespace}:#{id}"
 		LockManager._getLock key, namespace, (error) ->
 			return callback(error) if error?
+
+			# The lock can expire in redis but the process carry on. This setTimout call
+			# is designed to log if this happens.
+			countIfExceededLockTimeout = () ->
+				metrics.inc "lock.#{namespace}.exceeded_lock_timeout"
+				logger.log "exceeded lock timeout", { namespace, id, slowExecutionError }
+			exceededLockTimeout = setTimeout countIfExceededLockTimeout, LockManager.REDIS_LOCK_EXPIRY * 1000
+
 			runner (error1, values...) ->
 				LockManager._releaseLock key, (error2) ->
-					lockReleased = true
+					clearTimeout exceededLockTimeout
+
 					timeTaken = new Date - timer.start
 					if timeTaken > LockManager.SLOW_EXECUTION_THRESHOLD
 						logger.log "slow execution during lock", { namespace, id, timeTaken, slowExecutionError }


removed env variables for CLIENT_ID and secret. Just use the MESHBLU_UUID/TOKEN!

--- app/templates/src/strategies/_octoblu-strategy.coffee
+++ app/templates/src/strategies/_octoblu-strategy.coffee
@@ -9,8 +9,8 @@
     throw new Error('Missing required environment variable: ENDO_<%= constantPrefix %>_OCTOBLU_OAUTH_URL')     if _.isEmpty process.env.ENDO_<%= constantPrefix %>_OCTOBLU_OAUTH_URL

     options = {
-      clientID:         process.env.ENDO_<%= constantPrefix %>_OCTOBLU_CLIENT_ID
-      clientSecret:     process.env.ENDO_<%= constantPrefix %>_OCTOBLU_CLIENT_SECRET
+      clientID:         process.env.MESHBLU_UUID
+      clientSecret:     process.env.MESHBLU_TOKEN
       authorizationURL: "#{process.env.ENDO_<%= constantPrefix %>_OCTOBLU_OAUTH_URL}/authorize"
       tokenURL:         "#{process.env.ENDO_<%= constantPrefix %>_OCTOBLU_OAUTH_URL}/access_token"
       meshbluConfig:    new MeshbluConfig().toJSON()


Remove unneeded initialization of variable from superclass

--- lib/command-palette-view.coffee
+++ lib/command-palette-view.coffee
@@ -13,7 +13,6 @@

   filterKey: 'eventDescription'

-  previouslyFocusedElement: null
   keyBindings: null

   initialize: ->


Fixed a bug that was constantly clearing

--- src/main/client/common/table-options-filter-dropdown.coffee
+++ src/main/client/common/table-options-filter-dropdown.coffee
@@ -32,7 +32,7 @@
       @updateFromElementVal()

     clear: () ->
-      @$widget.find('input').val('')
+      @$element.val('')

     elementKeydown: (e) ->
       @update()


fix memberships store

fix memberships store

--- src/node_modules/memberships-store/memberships-store.coffee
+++ src/node_modules/memberships-store/memberships-store.coffee
@@ -1,7 +1,13 @@
-module.exports = (Restangular) ->
+_ = require('lodash')
+
+module.exports = (Restangular, MembershipModel) ->

   all: (groupId) ->
-    Restangular.one('groups', groupId).all('memberships').getList()
+    Restangular.one('groups', groupId)
+    .all('memberships').getList()
+    .then (memberships) ->
+      _.map memberships, (membership) ->
+        new MembershipModel(membership.plain())

   create: (membership) ->
     Restangular.all('memberships').post(membership)


quick fix for firefox

quick fix for firefox

- I forgot to explicitly accept the event parameter to one of my event
  handlers. Chrome does it implicitly so I never noticed. Test in other
  browsers, yo.

--- scripts/_keybindings.coffee
+++ scripts/_keybindings.coffee
@@ -1,4 +1,4 @@
-keyboardKeydown = ->
+keyboardKeydown = (event) ->
     if not (event.altKey or event.ctrlKey or event.shiftKey or \
             event.metaKey)


Do not block mousedown events (just use es as listener).

--- app/assets/javascripts/app/controllers/widget/global_search.coffee
+++ app/assets/javascripts/app/controllers/widget/global_search.coffee
@@ -4,6 +4,7 @@
   constructor: ->
     $('body').on('mousedown', (e) =>
       @shiftHeldToogle(e)
+      true
     )
     App.Event.bind('global:search:set', (data) =>
       item = data[0]


fix timeout option

fix timeout option

--- lib/notification-element.coffee
+++ lib/notification-element.coffee
@@ -54,7 +54,7 @@
     @buttonListTemplate = TemplateHelper.create(ButtonListTemplate)
     @buttonTemplate = TemplateHelper.create(ButtonTemplate)

-    @visibilityDuration ?= @model.getOptions().timeout
+    @visibilityDuration = @model.getOptions().timeout ? @visibilityDuration

     @element = document.createElement('atom-notification')
     @issue = new NotificationIssue(@model) if @model.getType() is 'fatal'


be a bit more forgiving considering we concat for 100ms...

--- spec/console-spec.coffee
+++ spec/console-spec.coffee
@@ -141,7 +141,7 @@
     describe 'when outputs are seperated', ->
       beforeEach ->
         [1..10].forEach (i) ->
-          waits 100
+          waits 120
           runs ->
             model.stdout "#{i}\n"


white_check_mark: Add traverseTree test

white_check_mark: Add traverseTree test

--- spec/fs-plus-spec.coffee
+++ spec/fs-plus-spec.coffee
@@ -241,6 +241,86 @@
         onPath = (childPath) -> paths.push(childPath)
         fs.symlinkSync(path.join(directory, 'source'), path.join(directory, 'destination'))
         fs.traverseTreeSync(directory, onPath)
+        expect(paths.length).toBe 0
+
+  describe ".traverseTree(path, onFile, onDirectory, onDone)", ->
+    it "calls fn for every path in the tree at the given path", ->
+      paths = []
+      onPath = (childPath) ->
+        paths.push(childPath)
+        true
+      done = false
+      onDone = ->
+        done = true
+      fs.traverseTree fixturesDir, onPath, onPath, onDone
+
+      waitsFor ->
+        done
+
+      runs ->
+        expect(paths).toEqual fs.listTreeSync(fixturesDir)
+
+    it "does not recurse into a directory if it is pruned", ->
+      paths = []
+      onPath = (childPath) ->
+        if childPath.match(/\/dir$/)
+          false
+        else
+          paths.push(childPath)
+          true
+      done = false
+      onDone = ->
+        done = true
+
+      fs.traverseTree fixturesDir, onPath, onPath, onDone
+
+      waitsFor ->
+        done
+
+      runs ->
+        expect(paths.length).toBeGreaterThan 0
+        for filePath in paths
+          expect(filePath).not.toMatch /\/dir\//
+
+    it "returns entries if path is a symlink", ->
+      symlinkPath = path.join(fixturesDir, 'symlink-to-dir')
+      symlinkPaths = []
+
+      onSymlinkPath = (path) -> symlinkPaths.push(path.substring(symlinkPath.length + 1))
+
+      regularPath = path.join(fixturesDir, 'dir')
+      paths = []
+      onPath = (path) -> paths.push(path.substring(regularPath.length + 1))
+
+      symlinkDone = false
+      onSymlinkPathDone = ->
+        symlinkDone = true
+
+      regularDone = false
+      onRegularPathDone = ->
+        regularDone = true
+
+      fs.traverseTree symlinkPath, onSymlinkPath, onSymlinkPath, onSymlinkPathDone
+      fs.traverseTree regularPath, onPath, onPath, onRegularPathDone
+
+      waitsFor ->
+        symlinkDone && regularDone
+
+      runs ->
+        expect(symlinkPaths).toEqual(paths)
+
+    it "ignores missing symlinks", ->
+      directory = temp.mkdirSync('symlink-in-here')
+      paths = []
+      onPath = (childPath) -> paths.push(childPath)
+      fs.symlinkSync(path.join(directory, 'source'), path.join(directory, 'destination'))
+      done = false
+      onDone = ->
+        done = true
+      fs.traverseTree directory, onPath, onPath, onDone
+      waitsFor ->
+        done
+      runs ->
         expect(paths.length).toBe 0

   describe ".md5ForPath(path)", ->


:white_check_mark: Added regexp tests

:white_check_mark: Added regexp tests

--- spec/grammar-spec.coffee
+++ spec/grammar-spec.coffee
@@ -11,3 +11,29 @@
   it "parses the grammar", ->
     expect(grammar).toBeDefined()
     expect(grammar.scopeName).toBe "source.perl"
+
+  it "tokenizes regexp replace", ->
+    {tokens} = grammar.tokenizeLine('s/text/test/')
+    expect(tokens[0]).toEqual value: "s", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl", "punctuation.definition.string.perl", "support.function.perl"]
+    expect(tokens[1]).toEqual value: "/", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl", "punctuation.definition.string.perl"]
+    expect(tokens[2]).toEqual value: "text", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl"]
+    expect(tokens[3]).toEqual value: "/", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl", "punctuation.definition.string.perl"]
+    expect(tokens[4]).toEqual value: "test", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl"]
+    expect(tokens[5]).toEqual value: "/", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl", "punctuation.definition.string.perl"]
+
+    {tokens} = grammar.tokenizeLine('s_text_test_')
+    expect(tokens[0]).toEqual value: "s", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl", "punctuation.definition.string.perl", "support.function.perl"]
+    expect(tokens[1]).toEqual value: "_", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl", "punctuation.definition.string.perl"]
+    expect(tokens[2]).toEqual value: "text", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl"]
+    expect(tokens[3]).toEqual value: "_", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl", "punctuation.definition.string.perl"]
+    expect(tokens[4]).toEqual value: "test", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl"]
+    expect(tokens[5]).toEqual value: "_", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl", "punctuation.definition.string.perl"]
+
+    {tokens} = grammar.tokenizeLine('s/text/test/gxr')
+    expect(tokens[0]).toEqual value: "s", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl", "punctuation.definition.string.perl", "support.function.perl"]
+    expect(tokens[1]).toEqual value: "/", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl", "punctuation.definition.string.perl"]
+    expect(tokens[2]).toEqual value: "text", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl"]
+    expect(tokens[3]).toEqual value: "/", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl", "punctuation.definition.string.perl"]
+    expect(tokens[4]).toEqual value: "test", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl"]
+    expect(tokens[5]).toEqual value: "/", scopes: ["source.perl", "string.regexp.replaceXXX.simple_delimiter.perl", "punctuation.definition.string.perl"]
+    expect(tokens[6]).toEqual value: "gxr", scopes: ["source.perl", "string.regexp.replace.perl", "punctuation.definition.string.perl", "keyword.control.regexp-option.perl"]


WIP remove noise

WIP remove noise

--- spec/motions-spec.coffee
+++ spec/motions-spec.coffee
@@ -1,6 +1,7 @@
 helpers = require './spec-helper'
-
-describe "Motions", ->
+_ = require 'underscore-plus'
+
+fdescribe "Motions", ->
   [editor, editorElement, vimState] = []

   beforeEach ->
@@ -18,6 +19,13 @@
     options.element ?= editorElement
     helpers.keydown(key, options)

+  keystroke = (keys) ->
+    for key in keys.split('')
+      if key.match(/[A-Z]/)
+        keydown(key, shift: true)
+      else
+        keydown(key)
+
   normalModeInputKeydown = (key, opts = {}) ->
     theEditor = opts.editor or editor
     theEditor.normalModeInputView.editorElement.getModel().setText(key)
@@ -27,455 +35,395 @@
     inputEditor.getModel().setText(text)
     atom.commands.dispatch(inputEditor, "core:confirm")

+  set = (options={}) ->
+    if options.keystroke?
+      keystroke(options.keystroke)
+    if options.text?
+      editor.setText(options.text)
+    if options.cursor?
+      editor.setCursorScreenPosition options.cursor
+    if options.addCursor?
+      editor.addCursorAtBufferPosition options.addCursor
+    if options.register?
+      vimState.register.set '"', text: options.register
+
+
+  selectedScreenRange = ->
+    expect editor.getSelectedScreenRange()
+  selectedScreenRanges = ->
+    expect editor.getSelectedScreenRanges()
+  selectedBufferRange = ->
+    expect editor.getSelectedBufferRange()
+  selectedBufferRanges = ->
+    expect editor.getSelectedBufferRanges()
+
+  ensure = (_keystroke, options={}) ->
+    unless _.isEmpty(_keystroke)
+      keystroke(_keystroke)
+    if options.text?
+      expect(editor.getText()).toBe options.text
+    if options.cursor?
+      expect(editor.getCursorScreenPosition()).toEqual options.cursor
+    if options.register?
+      expect(vimState.register.get('"').text).toBe options.register
+    if options.selectedText?
+      expect(editor.getSelectedText()).toBe options.selectedText
+
+    if options.selectedBufferRange?
+      selectedBufferRange().toEqual options.selectedBufferRange
+    if options.selectedBufferRanges?
+      selectedBufferRanges().toEqual options.selectedBufferRanges
+
+    if options.selectedScreenRange?
+      selectedScreenRange().toEqual options.selectedScreenRange
+    if options.selectedScreenRanges?
+      selectedScreenRanges().toEqual options.selectedScreenRanges
+
   describe "simple motions", ->
     beforeEach ->
-      editor.setText("12345\nabcd\nABCDE")
-      editor.setCursorScreenPosition([1, 1])
+      set
+        text: "12345\nabcd\nABCDE"
+        cursor: [1, 1]

     describe "the h keybinding", ->
       describe "as a motion", ->
         it "moves the cursor left, but not to the previous line", ->
-          keydown('h')
-          expect(editor.getCursorScreenPosition()).toEqual [1, 0]
-
-          keydown('h')
-          expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+          ensure 'h', cursor: [1, 0]
+          ensure 'h', cursor: [1, 0]

         it "moves the cursor to the previous line if wrapLeftRightMotion is true", ->
           atom.config.set('vim-mode.wrapLeftRightMotion', true)
-          keydown('h')
-          keydown('h')
-          expect(editor.getCursorScreenPosition()).toEqual [0, 4]
+          ensure 'hh', cursor: [0, 4]

       describe "as a selection", ->
         it "selects the character to the left", ->
-          keydown('y')
-          keydown('h')
-
-          expect(vimState.register.get('"').text).toBe 'a'
-          expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+          ensure 'yh',
+            register: 'a'
+            cursor: [1, 0]

     describe "the j keybinding", ->
       it "moves the cursor down, but not to the end of the last line", ->
-        keydown('j')
-        expect(editor.getCursorScreenPosition()).toEqual [2, 1]
-
-        keydown('j')
-        expect(editor.getCursorScreenPosition()).toEqual [2, 1]
+        ensure 'j', cursor: [2, 1]
+        ensure 'j', cursor: [2, 1]

       it "moves the cursor to the end of the line, not past it", ->
-        editor.setCursorScreenPosition([0, 4])
-
-        keydown('j')
-        expect(editor.getCursorScreenPosition()).toEqual [1, 3]
+        set
+          cursor: [0, 4]
+        ensure 'j',
+          cursor: [1, 3]

       it "remembers the position it column it was in after moving to shorter line", ->
-        editor.setCursorScreenPosition([0, 4])
-
-        keydown('j')
-        expect(editor.getCursorScreenPosition()).toEqual [1, 3]
-
-        keydown('j')
-        expect(editor.getCursorScreenPosition()).toEqual [2, 4]
+        set cursor: [0, 4]
+        ensure 'j', cursor: [1, 3]
+        ensure 'j', cursor: [2, 4]

       describe "when visual mode", ->
         beforeEach ->
-          keydown('v')
-          expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+          ensure 'v', cursor: [1, 2]

         it "moves the cursor down", ->
-          keydown('j')
-          expect(editor.getCursorScreenPosition()).toEqual [2, 2]
+          ensure 'j', cursor: [2, 2]

         it "doesn't go over after the last line", ->
-          keydown('j')
-          expect(editor.getCursorScreenPosition()).toEqual [2, 2]
+          ensure 'j', cursor: [2, 2]

         it "selects the text while moving", ->
-          keydown('j')
-          expect(editor.getSelectedText()).toBe "bcd\nAB"
+          ensure 'j',
+            selectedText: "bcd\nAB"

     describe "the k keybinding", ->
       it "moves the cursor up, but not to the beginning of the first line", ->
-        keydown('k')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 1]
-
-        keydown('k')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+        ensure 'k', cursor: [0, 1]
+        ensure 'k', cursor: [0, 1]

     describe "the l keybinding", ->
-      beforeEach -> editor.setCursorScreenPosition([1, 2])
+      beforeEach ->
+        set cursor: [1, 2]

       it "moves the cursor right, but not to the next line", ->
-        keydown('l')
-        expect(editor.getCursorScreenPosition()).toEqual [1, 3]
-
-        keydown('l')
-        expect(editor.getCursorScreenPosition()).toEqual [1, 3]
+        ensure 'l', cursor: [1, 3]
+        ensure 'l', cursor: [1, 3]

       it "moves the cursor to the next line if wrapLeftRightMotion is true", ->
         atom.config.set('vim-mode.wrapLeftRightMotion', true)
-        keydown('l')
-        keydown('l')
-        expect(editor.getCursorScreenPosition()).toEqual [2, 0]
+        ensure 'll', cursor: [2, 0]

       describe "on a blank line", ->
         it "doesn't move the cursor", ->
-          editor.setText("\n\n\n")
-          editor.setCursorBufferPosition([1, 0])
-          keydown('l')
-          expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+          set
+            text: "\n\n\n"
+            cursor: [1, 0]
+          ensure 'l',
+            cursor: [1, 0]

   describe "the w keybinding", ->
-    beforeEach -> editor.setText("ab cde1+- \n xyz\n\nzip")
+    beforeEach ->
+      set text: "ab cde1+- \n xyz\n\nzip"

     describe "as a motion", ->
-      beforeEach -> editor.setCursorScreenPosition([0, 0])
+      beforeEach ->
+        set cursor: [0, 0]

       it "moves the cursor to the beginning of the next word", ->
-        keydown('w')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 3]
-
-        keydown('w')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 7]
-
-        keydown('w')
-        expect(editor.getCursorScreenPosition()).toEqual [1, 1]
-
-        keydown('w')
-        expect(editor.getCursorScreenPosition()).toEqual [2, 0]
-
-        keydown('w')
-        expect(editor.getCursorScreenPosition()).toEqual [3, 0]
-
-        keydown('w')
-        expect(editor.getCursorScreenPosition()).toEqual [3, 2]
-
+        ensure 'w', cursor: [0, 3]
+        ensure 'w', cursor: [0, 7]
+        ensure 'w', cursor: [1, 1]
+        ensure 'w', cursor: [2, 0]
+        ensure 'w', cursor: [3, 0]
+        ensure 'w', cursor: [3, 2]
         # When the cursor gets to the EOF, it should stay there.
-        keydown('w')
-        expect(editor.getCursorScreenPosition()).toEqual [3, 2]
+        ensure 'w', cursor: [3, 2]

       it "moves the cursor to the end of the word if last word in file", ->
-        editor.setText("abc")
-        editor.setCursorScreenPosition([0, 0])
-        keydown('w')
-        expect(editor.getCursorScreenPosition()).toEqual([0, 2])
+        set
+          text: 'abc'
+          cursor: [0, 0]
+        ensure 'w',
+          cursor: [0, 2]

     describe "as a selection", ->
       describe "within a word", ->
-        beforeEach ->
-          editor.setCursorScreenPosition([0, 0])
-          keydown('y')
-          keydown('w')
-
         it "selects to the end of the word", ->
-          expect(vimState.register.get('"').text).toBe 'ab '
+          set
+            cursor: [0, 0]
+          ensure 'yw',
+            register: 'ab '

       describe "between words", ->
-        beforeEach ->
-          editor.setCursorScreenPosition([0, 2])
-          keydown('y')
-          keydown('w')
-
         it "selects the whitespace", ->
-          expect(vimState.register.get('"').text).toBe ' '
+          set cursor: [0, 2]
+          ensure 'yw', register: ' '

   describe "the W keybinding", ->
-    beforeEach -> editor.setText("cde1+- ab \n xyz\n\nzip")
+    beforeEach ->
+      set text: "cde1+- ab \n xyz\n\nzip"

     describe "as a motion", ->
-      beforeEach -> editor.setCursorScreenPosition([0, 0])
+      beforeEach ->
+        set cursor: [0, 0]

       it "moves the cursor to the beginning of the next word", ->
-        keydown('W', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [0, 7]
-
-        keydown('W', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [1, 1]
-
-        keydown('W', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [2, 0]
-
-        keydown('W', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [3, 0]
+        ensure 'W', cursor: [0, 7]
+        ensure 'W', cursor: [1, 1]
+        ensure 'W', cursor: [2, 0]
+        ensure 'W', cursor: [3, 0]

     describe "as a selection", ->
       describe "within a word", ->
         it "selects to the end of the whole word", ->
-          editor.setCursorScreenPosition([0, 0])
-          keydown('y')
-          keydown('W', shift: true)
-          expect(vimState.register.get('"').text).toBe 'cde1+- '
+          set cursor: [0, 0]
+          ensure 'yW', register: 'cde1+- '

       it "continues past blank lines", ->
-        editor.setCursorScreenPosition([2, 0])
-
-        keydown('d')
-        keydown('W', shift: true)
-        expect(editor.getText()).toBe "cde1+- ab \n xyz\nzip"
-        expect(vimState.register.get('"').text).toBe '\n'
+        set
+          cursor: [2, 0]
+        ensure 'dW',
+          text: "cde1+- ab \n xyz\nzip"
+          register: "\n"

       it "doesn't go past the end of the file", ->
-        editor.setCursorScreenPosition([3, 0])
-
-        keydown('d')
-        keydown('W', shift: true)
-        expect(editor.getText()).toBe "cde1+- ab \n xyz\n\n"
-        expect(vimState.register.get('"').text).toBe 'zip'
+        set
+          cursor: [3, 0]
+        ensure 'dW',
+          text: "cde1+- ab \n xyz\n\n"
+          register: 'zip'

   describe "the e keybinding", ->
-    beforeEach -> editor.setText("ab cde1+- \n xyz\n\nzip")
+    beforeEach ->
+      set text: "ab cde1+- \n xyz\n\nzip"

     describe "as a motion", ->
-      beforeEach -> editor.setCursorScreenPosition([0, 0])
+      beforeEach ->
+        set cursor: [0, 0]

       it "moves the cursor to the end of the current word", ->
-        keydown('e')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 1]
-
-        keydown('e')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 6]
-
-        keydown('e')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 8]
-
-        keydown('e')
-        expect(editor.getCursorScreenPosition()).toEqual [1, 3]
-
-        keydown('e')
-        expect(editor.getCursorScreenPosition()).toEqual [3, 2]
+        ensure 'e', cursor: [0, 1]
+        ensure 'e', cursor: [0, 6]
+        ensure 'e', cursor: [0, 8]
+        ensure 'e', cursor: [1, 3]
+        ensure 'e', cursor: [3, 2]

     describe "as selection", ->
       describe "within a word", ->
-        beforeEach ->
-          editor.setCursorScreenPosition([0, 0])
-          keydown('y')
-          keydown('e')
-
         it "selects to the end of the current word", ->
-          expect(vimState.register.get('"').text).toBe 'ab'
+          set cursor: [0, 0]
+          ensure 'ye', register: 'ab'

       describe "between words", ->
-        beforeEach ->
-          editor.setCursorScreenPosition([0, 2])
-          keydown('y')
-          keydown('e')
-
         it "selects to the end of the next word", ->
-          expect(vimState.register.get('"').text).toBe ' cde1'
+          set cursor: [0, 2]
+          ensure 'ye', register: ' cde1'

   describe "the E keybinding", ->
-    beforeEach -> editor.setText("ab  cde1+- \n xyz \n\nzip\n")
+    beforeEach ->
+      set text: "ab  cde1+- \n xyz \n\nzip\n"

     describe "as a motion", ->
-      beforeEach -> editor.setCursorScreenPosition([0, 0])
+      beforeEach ->
+        set cursor: [0, 0]

       it "moves the cursor to the end of the current word", ->
-        keydown('E', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [0, 1]
-
-        keydown('E', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [0, 9]
-
-        keydown('E', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [1, 3]
-
-        keydown('E', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [3, 2]
-
-        keydown('E', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [4, 0]
+        ensure 'E', cursor: [0, 1]
+        ensure 'E', cursor: [0, 9]
+        ensure 'E', cursor: [1, 3]
+        ensure 'E', cursor: [3, 2]
+        ensure 'E', cursor: [4, 0]

     describe "as selection", ->
       describe "within a word", ->
-        beforeEach ->
-          editor.setCursorScreenPosition([0, 0])
-          keydown('y')
-          keydown('E', shift: true)
-
         it "selects to the end of the current word", ->
-          expect(vimState.register.get('"').text).toBe 'ab'
+          set cursor: [0, 0]
+          ensure 'yE', register: 'ab'

       describe "between words", ->
-        beforeEach ->
-          editor.setCursorScreenPosition([0, 2])
-          keydown('y')
-          keydown('E', shift: true)
-
         it "selects to the end of the next word", ->
-          expect(vimState.register.get('"').text).toBe '  cde1+-'
+          set cursor: [0, 2]
+          ensure 'yE', register: '  cde1+-'

       describe "press more than once", ->
-        beforeEach ->
-          editor.setCursorScreenPosition([0, 0])
-          keydown('v')
-          keydown('E', shift: true)
-          keydown('E', shift: true)
-          keydown('y')
-
         it "selects to the end of the current word", ->
-          expect(vimState.register.get('"').text).toBe 'ab  cde1+-'
+          set cursor: [0, 0]
+          ensure 'vEEy', register: 'ab  cde1+-'

   describe "the } keybinding", ->
     beforeEach ->
-      editor.setText("abcde\n\nfghij\nhijk\n  xyz  \n\nzip\n\n  \nthe end")
-      editor.setCursorScreenPosition([0, 0])
+      set
+        text: "abcde\n\nfghij\nhijk\n  xyz  \n\nzip\n\n  \nthe end"
+        cursor: [0, 0]

     describe "as a motion", ->
       it "moves the cursor to the end of the paragraph", ->
-        keydown('}')
-        expect(editor.getCursorScreenPosition()).toEqual [1, 0]
-
-        keydown('}')
-        expect(editor.getCursorScreenPosition()).toEqual [5, 0]
-
-        keydown('}')
-        expect(editor.getCursorScreenPosition()).toEqual [7, 0]
-
-        keydown('}')
-        expect(editor.getCursorScreenPosition()).toEqual [9, 6]
+        ensure '}', cursor: [1, 0]
+        ensure '}', cursor: [5, 0]
+        ensure '}', cursor: [7, 0]
+        ensure '}', cursor: [9, 6]

     describe "as a selection", ->
-      beforeEach ->
-        keydown('y')
-        keydown('}')
-
       it 'selects to the end of the current paragraph', ->
-        expect(vimState.register.get('"').text).toBe "abcde\n"
+        ensure 'y}', register: "abcde\n"

   describe "the { keybinding", ->
     beforeEach ->
-      editor.setText("abcde\n\nfghij\nhijk\n  xyz  \n\nzip\n\n  \nthe end")
-      editor.setCursorScreenPosition([9, 0])
+      set
+        text: "abcde\n\nfghij\nhijk\n  xyz  \n\nzip\n\n  \nthe end"
+        cursor: [9, 0]

     describe "as a motion", ->
       it "moves the cursor to the beginning of the paragraph", ->
-        keydown('{')
-        expect(editor.getCursorScreenPosition()).toEqual [7, 0]
-
-        keydown('{')
-        expect(editor.getCursorScreenPosition()).toEqual [5, 0]
-
-        keydown('{')
-        expect(editor.getCursorScreenPosition()).toEqual [1, 0]
-
-        keydown('{')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+        ensure '{', cursor: [7, 0]
+        ensure '{', cursor: [5, 0]
+        ensure '{', cursor: [1, 0]
+        ensure '{', cursor: [0, 0]

     describe "as a selection", ->
-      beforeEach ->
-        editor.setCursorScreenPosition([7, 0])
-        keydown('y')
-        keydown('{')
-
       it 'selects to the beginning of the current paragraph', ->
-        expect(vimState.register.get('"').text).toBe "\nzip\n"
+        set cursor: [7, 0]
+        ensure 'y{', register: "\nzip\n"

   describe "the b keybinding", ->
-    beforeEach -> editor.setText(" ab cde1+- \n xyz\n\nzip }\n last")
+    beforeEach ->
+      set text: " ab cde1+- \n xyz\n\nzip }\n last"

     describe "as a motion", ->
-      beforeEach -> editor.setCursorScreenPosition([4, 1])
+      beforeEach ->
+        set cursor: [4, 1]

       it "moves the cursor to the beginning of the previous word", ->
-        keydown('b')
-        expect(editor.getCursorScreenPosition()).toEqual [3, 4]
-
-        keydown('b')
-        expect(editor.getCursorScreenPosition()).toEqual [3, 0]
-
-        keydown('b')
-        expect(editor.getCursorScreenPosition()).toEqual [2, 0]
-
-        keydown('b')
-        expect(editor.getCursorScreenPosition()).toEqual [1, 1]
-
-        keydown('b')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 8]
-
-        keydown('b')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 4]
-
-        keydown('b')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+        ensure 'b', cursor: [3, 4]
+        ensure 'b', cursor: [3, 0]
+        ensure 'b', cursor: [2, 0]
+        ensure 'b', cursor: [1, 1]
+        ensure 'b', cursor: [0, 8]
+        ensure 'b', cursor: [0, 4]
+        ensure 'b', cursor: [0, 1]

         # Go to start of the file, after moving past the first word
-        keydown('b')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 0]
-
+        ensure 'b', cursor: [0, 0]
         # Stay at the start of the file
-        keydown('b')
-        expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+        ensure 'b', cursor: [0, 0]

     describe "as a selection", ->
       describe "within a word", ->
-        beforeEach ->
-          editor.setCursorScreenPosition([0, 2])
-          keydown('y')
-          keydown('b')
-
         it "selects to the beginning of the current word", ->
-          expect(vimState.register.get('"').text).toBe 'a'
-          expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+          set
+            cursor: [0, 2]
+          ensure 'yb',
+            register: 'a'
+            cursor: [0, 1]

       describe "between words", ->
-        beforeEach ->
-          editor.setCursorScreenPosition([0, 4])
-          keydown('y')
-          keydown('b')
-
         it "selects to the beginning of the last word", ->
-          expect(vimState.register.get('"').text).toBe 'ab '
-          expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+          set cursor: [0, 4]
+          ensure 'yb',
+            register: 'ab '
+            cursor: [0, 1]

   describe "the B keybinding", ->
-    beforeEach -> editor.setText("cde1+- ab \n\t xyz-123\n\n zip")
+    beforeEach ->
+      set text: "cde1+- ab \n\t xyz-123\n\n zip"

     describe "as a motion", ->
-      beforeEach -> editor.setCursorScreenPosition([4, 1])
+      beforeEach ->
+        set cursor: [4, 1]

       it "moves the cursor to the beginning of the previous word", ->
-        keydown('B', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [3, 1]
-
-        keydown('B', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [2, 0]
-
-        keydown('B', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [1, 3]
-
-        keydown('B', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [0, 7]
-
-        keydown('B', shift: true)
-        expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+        ensure 'B', cursor: [3, 1]
+        ensure 'B', cursor: [2, 0]
+        ensure 'B', cursor: [1, 3]
+        ensure 'B', cursor: [0, 7]
+        ensure 'B', cursor: [0, 0]

     describe "as a selection", ->
       it "selects to the beginning of the whole word", ->
-        editor.setCursorScreenPosition([1, 10])
-        keydown('y')
-        keydown('B', shift: true)
-        expect(vimState.register.get('"').text).toBe 'xyz-12' # because cursor is on the `3`
+        set cursor: [1, 10]
+        ensure 'yB', register: 'xyz-12' # because cursor is on the `3`

       it "doesn't go past the beginning of the file", ->
-        editor.setCursorScreenPosition([0, 0])
-        vimState.register.set('"', text: 'abc')
-        keydown('y')
-        keydown('B', shift: true)
-        expect(vimState.register.get('"').text).toBe 'abc'
+        set
+          cursor: [0, 0]
+          register: 'abc'
+        ensure 'yB',
+          register: 'abc'

   describe "the ^ keybinding", ->
     beforeEach ->
-      editor.setText("  abcde")
+      set text: "  abcde"

     describe "from the beginning of the line", ->
-      beforeEach -> editor.setCursorScreenPosition([0, 0])
+      beforeEach ->
+        set cursor: [0, 0]

       describe "as a motion", ->
-        beforeEach -> keydown('^')
-
         it "moves the cursor to the first character of the line", ->
-          expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+          ensure '^', cursor: [0, 2]
+
+      describe "as a selection", ->
+        it 'selects to the first character of the line', ->
+          ensure 'd^',
+            text: 'abcde'
+            cursor: [0, 0]
+
+    describe "from the first character of the line", ->
+      beforeEach ->
+        set cursor: [0, 2]
+
+      describe "as a motion", ->
+        it "stays put", ->
+          ensure '^', cursor: [0, 2]
+
+      describe "as a selection", ->
+        it "does nothing", ->
+          ensure 'd^',
+            text: '  abcde'
+            cursor: [0, 2]
+
+    describe "from the middle of a word", ->
+      beforeEach ->
+        set cursor: [0, 4]
+
+      describe "as a motion", ->
+        it "moves the cursor to the first character of the line", ->
+          ensure '^', cursor: [0, 2]

       describe "as a selection", ->
         beforeEach ->
@@ -483,321 +431,218 @@
           keydown('^')

         it 'selects to the first character of the line', ->
-          expect(editor.getText()).toBe 'abcde'
-          expect(editor.getCursorScreenPosition()).toEqual [0, 0]
-
-    describe "from the first character of the line", ->
-      beforeEach -> editor.setCursorScreenPosition([0, 2])
-
-      describe "as a motion", ->
-        beforeEach -> keydown('^')
-
-        it "stays put", ->
-          expect(editor.getCursorScreenPosition()).toEqual [0, 2]
-
-      describe "as a selection", ->
-        beforeEach ->
-          keydown('d')
-          keydown('^')
-
-        it "does nothing", ->
-          expect(editor.getText()).toBe '  abcde'
-          expect(editor.getCursorScreenPosition()).toEqual [0, 2]
-
-    describe "from the middle of a word", ->
-      beforeEach -> editor.setCursorScreenPosition([0, 4])
-
-      describe "as a motion", ->
-        beforeEach -> keydown('^')
-
-        it "moves the cursor to the first character of the line", ->
-          expect(editor.getCursorScreenPosition()).toEqual [0, 2]
-
-      describe "as a selection", ->
-        beforeEach ->
-          keydown('d')
-          keydown('^')
-
-        it 'selects to the first character of the line', ->
-          expect(editor.getText()).toBe '  cde'
-          expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+          ensure 'd^',
+            text: '  cde'
+            cursor: [0, 2]

   describe "the 0 keybinding", ->
     beforeEach ->
-      editor.setText("  abcde")
-      editor.setCursorScreenPosition([0, 4])
+      set
+        text: "  abcde"
+        cursor: [0, 4]

     describe "as a motion", ->
-      beforeEach -> keydown('0')
-
       it "moves the cursor to the first column", ->
-        expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+        ensure '0', cursor: [0, 0]

     describe "as a selection", ->
-      beforeEach ->
-        keydown('d')
-        keydown('0')
-
       it 'selects to the first column of the line', ->
-        expect(editor.getText()).toBe 'cde'
-        expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+        ensure 'd0',
+          text: 'cde'
+          cursor: [0, 0]

   describe "the $ keybinding", ->
     beforeEach ->
-      editor.setText("  abcde\n\n1234567890")
-      editor.setCursorScreenPosition([0, 4])
+      set
+        text: "  abcde\n\n1234567890"
+        cursor: [0, 4]

     describe "as a motion from empty line", ->
-      beforeEach -> editor.setCursorScreenPosition([1, 0])
-
       it "moves the cursor to the end of the line", ->
-        expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+        set cursor: [1, 0]
+        ensure '$', cursor: [1, 0]

     describe "as a motion", ->
       beforeEach -> keydown('$')

       # FIXME: See atom/vim-mode#2
       it "moves the cursor to the end of the line", ->
-        expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+        ensure '$', cursor: [0, 6]

       it "should remain in the last column when moving down", ->
-        keydown('j')
-        expect(editor.getCursorScreenPosition()).toEqual [1, 0]
-
-        keydown('j')
-        expect(editor.getCursorScreenPosition()).toEqual [2, 9]
+        ensure '$j', cursor: [1, 0]
+        ensure 'j', cursor: [2, 9]

     describe "as a selection", ->
-      beforeEach ->
-        keydown('d')
-        keydown('$')
-
       it "selects to the beginning of the lines", ->
-        expect(editor.getText()).toBe "  ab\n\n1234567890"
-        expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+        ensure 'd$',
+          text: "  ab\n\n1234567890"
+          cursor: [0, 3]

   describe "the 0 keybinding", ->
     beforeEach ->
-      editor.setText("  a\n")
-      editor.setCursorScreenPosition([0, 2])
+      set
+        text: "  a\n"
+        cursor: [0, 2]

     describe "as a motion", ->
-      beforeEach -> keydown('0')
-
       it "moves the cursor to the beginning of the line", ->
-        expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+        ensure '0', cursor: [0, 0]

   describe "the - keybinding", ->
     beforeEach ->
-      editor.setText("abcdefg\n  abc\n  abc\n")
+      set text: "abcdefg\n  abc\n  abc\n"

     describe "from the middle of a line", ->
-      beforeEach -> editor.setCursorScreenPosition([1, 3])
+      beforeEach ->
+        set cursor: [1, 3]

       describe "as a motion", ->
-        beforeEach -> keydown('-')
-
         it "moves the cursor to the last character of the previous line", ->
-          expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+          ensure '-', cursor: [0, 0]

       describe "as a selection", ->
-        beforeEach ->
-          keydown('d')
-          keydown('-')
-
         it "deletes the current and previous line", ->
-          expect(editor.getText()).toBe "  abc\n"
+          ensure 'd-', text: "  abc\n"
           # commented out because the column is wrong due to a bug in `k`; re-enable when `k` is fixed
           #expect(editor.getCursorScreenPosition()).toEqual [0, 3]

     describe "from the first character of a line indented the same as the previous one", ->
-      beforeEach -> editor.setCursorScreenPosition([2, 2])
+      beforeEach ->
+        set cursor: [2, 2]

       describe "as a motion", ->
-        beforeEach -> keydown('-')
-
         it "moves to the first character of the previous line (directly above)", ->
-          expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+          ensure '-', cursor: [1, 2]

       describe "as a selection", ->
-        beforeEach ->
-          keydown('d')
-          keydown('-')
-
         it "selects to the first character of the previous line (directly above)", ->
-          expect(editor.getText()).toBe "abcdefg\n"
+          ensure 'd-', text: "abcdefg\n"
           # commented out because the column is wrong due to a bug in `k`; re-enable when `k` is fixed
           #expect(editor.getCursorScreenPosition()).toEqual [0, 2]

     describe "from the beginning of a line preceded by an indented line", ->
-      beforeEach -> editor.setCursorScreenPosition([2, 0])
+      beforeEach ->
+        set cursor: [2, 0]

       describe "as a motion", ->
-        beforeEach -> keydown('-')
-
         it "moves the cursor to the first character of the previous line", ->
-          expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+          ensure '-', cursor: [1, 2]

       describe "as a selection", ->
-        beforeEach ->
-          keydown('d')
-          keydown('-')
-
         it "selects to the first character of the previous line", ->
-          expect(editor.getText()).toBe "abcdefg\n"
+          ensure 'd-', text: "abcdefg\n"
           # commented out because the column is wrong due to a bug in `k`; re-enable when `k` is fixed
           #expect(editor.getCursorScreenPosition()).toEqual [0, 0]

     describe "with a count", ->
       beforeEach ->
-        editor.setText("1\n2\n3\n4\n5\n6\n")
-        editor.setCursorScreenPosition([4, 0])
+        set
+          text: "1\n2\n3\n4\n5\n6\n"
+          cursor: [4, 0]

       describe "as a motion", ->
-        beforeEach ->
-          keydown('3')
-          keydown('-')
-
         it "moves the cursor to the first character of that many lines previous", ->
-          expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+          ensure '3-', cursor: [1, 0]

       describe "as a selection", ->
-        beforeEach ->
-          keydown('d')
-          keydown('3')
-          keydown('-')
-
         it "deletes the current line plus that many previous lines", ->
-          expect(editor.getText()).toBe "1\n6\n"
-          expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+          ensure 'd3-',
+            text: "1\n6\n"
+            cursor: [1, 0]

   describe "the + keybinding", ->
     beforeEach ->
-      editor.setText("  abc\n  abc\nabcdefg\n")
+      set text: "  abc\n  abc\nabcdefg\n"

     describe "from the middle of a line", ->
-      beforeEach -> editor.setCursorScreenPosition([1, 3])
+      beforeEach ->
+        set cursor: [1, 3]

       describe "as a motion", ->
-        beforeEach -> keydown('+')
-
         it "moves the cursor to the first character of the next line", ->
-          expect(editor.getCursorScreenPosition()).toEqual [2, 0]
+          ensure '+', cursor: [2, 0]

       describe "as a selection", ->
-        beforeEach ->
-          keydown('d')
-          keydown('+')
-
         it "deletes the current and next line", ->
-          expect(editor.getText()).toBe "  abc\n"
+          ensure 'd+', text: "  abc\n"
           # commented out because the column is wrong due to a bug in `j`; re-enable when `j` is fixed
           #expect(editor.getCursorScreenPosition()).toEqual [0, 3]

     describe "from the first character of a line indented the same as the next one", ->
-      beforeEach -> editor.setCursorScreenPosition([0, 2])
+      beforeEach -> set cursor: [0, 2]

       describe "as a motion", ->
-        beforeEach -> keydown('+')
-
         it "moves to the first character of the next line (directly below)", ->
-          expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+          ensure '+', cursor: [1, 2]

       describe "as a selection", ->
-        beforeEach ->
-          keydown('d')
-          keydown('+')
-
         it "selects to the first character of the next line (directly below)", ->
-          expect(editor.getText()).toBe "abcdefg\n"
+          ensure 'd+', text: "abcdefg\n"
           # commented out because the column is wrong due to a bug in `j`; re-enable when `j` is fixed
           #expect(editor.getCursorScreenPosition()).toEqual [0, 2]

     describe "from the beginning of a line followed by an indented line", ->
-      beforeEach -> editor.setCursorScreenPosition([0, 0])
+      beforeEach -> set cursor: [0, 0]

       describe "as a motion", ->
-        beforeEach -> keydown('+')
-
         it "moves the cursor to the first character of the next line", ->
-          expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+          ensure '+', cursor: [1, 2]

       describe "as a selection", ->
-        beforeEach ->
-          keydown('d')
-          keydown('+')
-
         it "selects to the first character of the next line", ->
-          expect(editor.getText()).toBe "abcdefg\n"
-          expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+          ensure 'd+',
+            text: "abcdefg\n"
+            cursor: [0, 0]

     describe "with a count", ->
       beforeEach ->
-        editor.setText("1\n2\n3\n4\n5\n6\n")
-        editor.setCursorScreenPosition([1, 0])
+        set
+          text: "1\n2\n3\n4\n5\n6\n"
+          cursor: [1, 0]

       describe "as a motion", ->
-        beforeEach ->
-          keydown('3')
-          keydown('+')
-
         it "moves the cursor to the first character of that many lines following", ->
-          expect(editor.getCursorScreenPosition()).toEqual [4, 0]
+          ensure '3+', cursor: [4, 0]

       describe "as a selection", ->
-        beforeEach ->
-          keydown('d')
-          keydown('3')
-          keydown('+')
-
         it "deletes the current line plus that many following lines", ->
-          expect(editor.getText()).toBe "1\n6\n"
-          expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+          ensure 'd3+',
+            text: "1\n6\n"
+            cursor: [1, 0]

   describe "the _ keybinding", ->
     beforeEach ->
-      editor.setText("  abc\n  abc\nabcdefg\n")
+      set text: "  abc\n  abc\nabcdefg\n"

     describe "from the middle of a line", ->
-      beforeEach -> editor.setCursorScreenPosition([1, 3])
+      beforeEach -> set cursor: [1, 3]

       describe "as a motion", ->
-        beforeEach -> keydown('_')
-
         it "moves the cursor to the first character of the current line", ->
-          expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+          ensure '_', cursor: [1, 2]

       describe "as a selection", ->
-        beforeEach ->
-          keydown('d')
-          keydown('_')
-
         it "deletes the current line", ->
-          expect(editor.getText()).toBe "  abc\nabcdefg\n"
-          expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+          ensure 'd_',
+            text: "  abc\nabcdefg\n"
+            cursor: [1, 0]

     describe "with a count", ->
       beforeEach ->
-        editor.setText("1\n2\n3\n4\n5\n6\n")
-        editor.setCursorScreenPosition([1, 0])
+        set
+          text: "1\n2\n3\n4\n5\n6\n"
+          cursor: [1, 0]

       describe "as a motion", ->
-        beforeEach ->
-          keydown('3')
-          keydown('_')
-
         it "moves the cursor to the first character of that many lines following", ->
-          expect(editor.getCursorScreenPosition()).toEqual [3, 0]
+          ensure '3_', cursor: [3, 0]

       describe "as a selection", ->
-        beforeEach ->
-          keydown('d')
-          keydown('3')
-          keydown('_')
-
         it "deletes the current line plus that many following lines", ->
-          expect(editor.getText()).toBe "1\n5\n6\n"
-          expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+          ensure 'd3_',
+            text: "1\n5\n6\n"
+            cursor: [1, 0]

   describe "the enter keybinding", ->
     keydownCodeForEnter = '\r' # 'enter' does not work


Destroy deserialized project in an afterEach

--- spec/project-spec.coffee
+++ spec/project-spec.coffee
@@ -9,10 +9,16 @@
     project.setPath(project.resolve('dir'))

   describe "serialization", ->
+    deserializedProject = null
+
+    afterEach ->
+      deserializedProject?.destroy()
+
     it "destroys unretained buffers and does not include them in the serialized state", ->
       project.bufferForPath('a')
       expect(project.getBuffers().length).toBe 1
-      expect(deserialize(project.serialize()).getBuffers().length).toBe 0
+      deserializedProject = deserialize(project.serialize())
+      expect(deserializedProject.getBuffers().length).toBe 0
       expect(project.getBuffers().length).toBe 0

   describe "when an edit session is destroyed", ->


ApplicationTabView: wait for mainController.ready before starting to listen

--- client/Main/CommonViews/applicationview/applicationtabview.coffee
+++ client/Main/CommonViews/applicationview/applicationtabview.coffee
@@ -38,8 +38,10 @@
         if this is tabView
           @getActivePane()?.getHandle()?.$().click()

-    mainView = KD.getSingleton("mainViewController").getView()
-    mainView.mainTabView.on "PaneDidShow", focusActivePane
+    {mainController, mainViewController} = KD.singletons
+    mainController.ready =>
+      mainView = mainViewController.getView()
+      mainView.mainTabView.on "PaneDidShow", focusActivePane

     @on "KDObjectWillBeDestroyed", ->
       mainView.mainTabView.off "PaneDidShow", focusActivePane


teams: creation: stacks tab to congrats tab transition

--- client/landing/site.landing/coffee/team/tabs/teamstackstab.coffee
+++ client/landing/site.landing/coffee/team/tabs/teamstackstab.coffee
@@ -20,7 +20,7 @@
     @next = new KDButtonView
       title      : 'Next'
       style      : 'TeamsModal-button TeamsModal-button--green'
-      callback   : ->
+      callback   : -> KD.singletons.router.handleRoute '/Team/Congrats'

   pistachio: ->


lets do it damons way

lets do it damons way

--- apps/home_2/components/followed_artists/search_artists_view.coffee
+++ apps/home_2/components/followed_artists/search_artists_view.coffee
@@ -58,12 +58,8 @@
         size: 1

   findReplacementAndWait: (id) ->
-    replacementDeferred = Q.defer()
-    waitDeferred = Q.defer()
-
-    @findReplacement id, (artist) -> replacementDeferred.resolve(artist)
-    setTimeout ( -> waitDeferred.resolve() ), 500
-    Q.all [replacementDeferred.promise, waitDeferred.promise]
+    replacement = new Promise (resolve) => @findReplacement id, resolve
+    Q.all [replacement, Q.delay(500)]

   replaceRow: ($el, id, artist) ->
     html = itemTemplate suggestion: artist


do not over-execute range slider render (#6379)

--- bokehjs/src/coffee/models/widgets/range_slider.coffee
+++ bokehjs/src/coffee/models/widgets/range_slider.coffee
@@ -14,7 +14,10 @@

   initialize: (options) ->
     super(options)
-    @connect(@model.change, () -> @render())
+    @connect(@model.properties.start.change, () -> @_render())
+    @connect(@model.properties.end.change, () -> @_render())
+    @connect(@model.properties.step.change, () -> @_render())
+    @connect(@model.properties.orientation.change, () -> @_render())
     @$el.empty()
     html = @template(@model.attributes)
     @$el.html(html)
@@ -26,10 +29,10 @@
       @callbackWrapper = throttle(() ->
         @model.callback?.execute(@model)
       , @model.callback_throttle)
+    @_render()
+
+  _render: () ->
     @render()
-
-  render: () ->
-    super()
     max = @model.end
     min = @model.start
     step = @model.step or ((max - min)/50)


Fix auto run subscriptions

Fix auto run subscriptions

--- lib/rubocop-auto-correct.coffee
+++ lib/rubocop-auto-correct.coffee
@@ -6,7 +6,7 @@
   constructor: ->
     @subscriptions = new CompositeDisposable
     @subscriptions.add atom.workspace.observeTextEditors (editor) =>
-      if editor.getGrammar().scopeName == "source.ruby"
+      if editor.getGrammar().scopeName.match("ruby")
         @handleEvents(editor)

     @subscriptions.add atom.commands.add 'atom-workspace',


Added search on Home folder for .rubocop.yml and refactored code

--- lib/rubocop-auto-correct.coffee
+++ lib/rubocop-auto-correct.coffee
@@ -14,9 +14,7 @@
         @handleEvents(editor)

     @subscriptions.add atom.commands.add 'atom-workspace',
-      'rubocop-auto-correct:current-file': =>
-        if editor = atom.workspace.getActiveTextEditor()
-          @run(editor)
+      'rubocop-auto-correct:current-file': => @run(atom.workspace.getActiveTextEditor())
       'rubocop-auto-correct:toggle-auto-run': => @toggleAutoRun()
       'rubocop-auto-correct:toggle-notification': => @toggleNotification()
       'rubocop-auto-correct:toggle-correct-file': => @toggleCorrectFile()
@@ -39,53 +37,49 @@
     @subscriptions.add(bufferSavedSubscription)
     @subscriptions.add(editorDestroyedSubscription)

+  toggleMessage: (messagePrepend, enabled) ->
+    "Rubocop Auto Correct: "+ messagePrepend + " " +
+      (if enabled then "ON" else "OFF")
+
   toggleAutoRun: ->
-    if atom.config.get('rubocop-auto-correct.autoRun')
-      atom.config.set('rubocop-auto-correct.autoRun', false)
-      atom.notifications.addSuccess("Turn OFF, Auto Run")
-    else
-      atom.config.set('rubocop-auto-correct.autoRun', true)
-      atom.notifications.addSuccess("Turn ON, Auto Run")
+    setting = atom.config.get('rubocop-auto-correct.autoRun')
+    atom.config.set('rubocop-auto-correct.autoRun', !setting)
+    atom.notifications.addSuccess(@toggleMessage("Auto Run", !setting))

   toggleNotification: ->
-    if atom.config.get('rubocop-auto-correct.notification')
-      atom.config.set('rubocop-auto-correct.notification', false)
-      atom.notifications.addSuccess("Turn OFF, Notification")
-    else
-      atom.config.set('rubocop-auto-correct.notification', true)
-      atom.notifications.addSuccess("Turn ON, Notification")
+    setting = atom.config.get('rubocop-auto-correct.notification')
+    atom.config.set('rubocop-auto-correct.notification', !setting)
+    atom.notifications.addSuccess(@toggleMessage("Notifications", !setting))

   toggleCorrectFile: ->
-    if atom.config.get('rubocop-auto-correct.correctFile')
-      atom.config.set('rubocop-auto-correct.correctFile', false)
-      atom.notifications.addSuccess("Correct the buffer")
-    else
-      atom.config.set('rubocop-auto-correct.correctFile', true)
-      atom.notifications.addSuccess("Correct the file")
+    setting = atom.config.get('rubocop-auto-correct.correctFile')
+    atom.config.set('rubocop-auto-correct.correctFile', !setting)
+    atom.notifications.addSuccess(@toggleMessage("Correct File", !setting))

   toggleDebugMode: ->
-    if atom.config.get('rubocop-auto-correct.debugMode')
-      atom.config.set('rubocop-auto-correct.debugMode', false)
-      atom.notifications.addSuccess("Turn OFF, Debug Mode")
-    else
-      atom.config.set('rubocop-auto-correct.debugMode', true)
-      atom.notifications.addSuccess("Turn ON, Debug Mode")
+    setting = atom.config.get('rubocop-auto-correct.debugMode')
+    atom.config.set('rubocop-auto-correct.debugMode', !setting)
+    atom.notifications.addSuccess(@toggleMessage("Debug Mode", !setting))

   run: (editor) ->
-    unless editor.getGrammar().scopeName.match("ruby")
-      return atom.notifications.addError("Only use source.ruby")
-    if atom.config.get('rubocop-auto-correct.correctFile')
-      if editor.isModified()
-        editor.save()
-      @autoCorrectFile(editor.getPath())
-    else
-      @autoCorrectBuffer(editor.getBuffer())
+    if editor
+      unless editor.getGrammar().scopeName.match("ruby")
+        return atom.notifications.addError("Only use source.ruby")
+      if atom.config.get('rubocop-auto-correct.correctFile')
+        if editor.isModified()
+          editor.save()
+        @autoCorrectFile(editor.getPath())
+      else
+        @autoCorrectBuffer(editor.getBuffer())

   projectRootRubocopConfig: (filePath) ->
     [projectPath, relativePath] = atom.project.relativizePath(filePath)
-    rubocopConfigPath = projectPath+'/.rubocop.yml'
-    if (fs.existsSync(rubocopConfigPath))
-      ['--config', rubocopConfigPath]
+    projectConfigPath = projectPath + '/.rubocop.yml'
+    homeConfigPath = fs.getHomeDirectory() + '/.rubocop.yml'
+    if (fs.existsSync(projectConfigPath))
+      ['--config', projectConfigPath]
+    else if (fs.existsSync(homeConfigPath))
+      ['--config', homeConfigPath]
     else
       []

@@ -98,9 +92,8 @@
                                 .concat(@projectRootRubocopConfig(buffer.getPath()))
     command = commandWithArgs[0]
     args = commandWithArgs[1..]
-    options = { encoding: 'utf-8', timeout: 5000 }
+    debug = atom.config.get('rubocop-auto-correct.debugMode')
     notification = atom.config.get('rubocop-auto-correct.notification')
-    debug = atom.config.get('rubocop-auto-correct.debugMode')

     which command, (err) ->
       if (err)
@@ -112,21 +105,13 @@
           ''' }
         )

-      rubocop = spawnSync(command, args, options)
+    rubocop = spawnSync(command, args, { encoding: 'utf-8', timeout: 5000 })

-      if rubocop.stderr != ""
-        console.error(rubocop.stderr) if debug
-        atom.notifications.addError(rubocop.stderr) if notification
-
-      if rubocop.stdout.match("corrected")
-        buffer.setTextViaDiff(fs.readFileSync(tempFilePath, 'utf-8'))
-        if notification || debug
-          re = /^.+?(:[0-9]+:[0-9]+:.*$)/mg
-          offenses = rubocop.stdout.match(re)
-          offenses.map (offense) ->
-            message = offense.replace(re, buffer.getBaseName() + "$1")
-            console.log(message) if debug
-            atom.notifications.addSuccess(message) if notification
+    if (rubocop.status != 0)
+      @rubocopOutput(buffer.getBaseName(), rubocop.stderr)
+    else
+      buffer.setTextViaDiff(fs.readFileSync(tempFilePath, 'utf-8'))
+      @rubocopOutput(buffer.getBaseName(), rubocop.stdout)

   autoCorrectFile: (filePath)  ->
     commandWithArgs = atom.config.get('rubocop-auto-correct.rubocopCommandPath')
@@ -135,15 +120,6 @@
                                 .concat(@projectRootRubocopConfig(filePath))
     command = commandWithArgs[0]
     args = commandWithArgs[1..]
-    debug = atom.config.get('rubocop-auto-correct.debugMode')
-    notification = atom.config.get('rubocop-auto-correct.notification')
-    stdout = (output) ->
-      if output.match("corrected")
-        console.log(output) if debug
-        atom.notifications.addSuccess(output) if notification
-    stderr = (output) ->
-      console.error(output) if debug
-      atom.notifications.addError(output) if notification

     which command, (err) ->
       if (err)
@@ -155,8 +131,27 @@
           ''' }
         )

-      rubocop = new BufferedProcess({command, args, stdout, stderr})
+    stdout = (output) =>
+      @rubocopOutput(filePath.replace(/.+\//, ""), output)
+    stderr = (output) =>
+      @rubocopOutput(filePath.replace(/.+\//, ""), output)

+    rubocop = new BufferedProcess({command, args, stdout, stderr})
+
+  rubocopOutput: (fileName, output) ->
+    debug = atom.config.get('rubocop-auto-correct.debugMode')
+    notification = atom.config.get('rubocop-auto-correct.notification')
+    console.log(output) if debug
+
+    if output.match("corrected")
+      re = /^.+?(:[0-9]+:[0-9]+:.*$)/mg
+      offenses = output.match(re)
+      offenses.map (offense) ->
+        message = offense.replace(re, fileName + "$1")
+        console.log(message) if debug
+        atom.notifications.addSuccess(message) if notification
+    else
+      atom.notifications.addError(output) if notification

   makeTempFile: (filename) ->
     directory = temp.mkdirSync()


部屋の目的が通知されていなかったバグを修正

部屋の目的が通知されていなかったバグを修正

--- scripts/notification.coffee
+++ scripts/notification.coffee
@@ -9,9 +9,11 @@
     message = JSON.parse msg
     switch message.type
       when 'channel_created'
-        creator = robot.adapter.client.rtm.dataStore.getUserById(message.channel.creator)
-        channel = robot.adapter.client.rtm.dataStore.getChannelById(message.channel.id)
-        robot.send {room: "C0P4MNTT8"}, "新しいチャンネルができたよ！ ( ##{message.channel.name} ) By #{creator.real_name}\nどんなところ? -> #{channel.purpose.value}"
+        setTimeout ->
+          creator = robot.adapter.client.rtm.dataStore.getUserById(message.channel.creator)
+          channel = robot.adapter.client.rtm.dataStore.getChannelById(message.channel.id)
+          robot.send {room: "C0P4MNTT8"}, "新しいチャンネルができたよ！ ( ##{message.channel.name} ) By #{creator.real_name}\nどんなところ? -> #{channel.purpose.value}"
+        ,5000
       when 'emoji_changed'
         break unless message.subtype is 'add'
         robot.send {room: "C0P4MNTT8"}, "新しい絵文字か追加されたよ!\n どんなの? -> :#{message.name}: [#{message.name}]\nちなみに追加は<https://c-a-c.slack.com/customize/emoji|ここ>からできるよ"


remove unused functions

remove unused functions

--- lib/slickgrid/table-view.coffee
+++ lib/slickgrid/table-view.coffee
@@ -1,6 +1,6 @@
 {View, $}                           = require 'space-pen'
 window.jQuery                       = $
-SlickGrid                           = require 'bd-slickgrid/grid'
+SlickGrid                           = require '../../extlib/bd-slickgrid/grid'
 WinningSelectionModel               = require './selection-models/winning-selectionmodel'
 {Emitter, Disposable}               = require 'atom'

@@ -23,22 +23,6 @@
         @grid.resizeCanvas()
         @grid.autosizeColumns()
         @grid.resizeCanvas()
-
-    addRows: (newData) ->
-        return unless @grid
-        @data = @data.concat newData
-        @sortData()
-        @grid.setData @data
-        @grid.invalidateAllRows()
-        @grid.autosizeColumns()
-        @grid.render()
-
-    deleteAllRows: ->
-        return unless @grid
-        @data = []
-        @grid.setData @data
-        @grid.invalidateAllRows()
-        @grid.render()

     sortData: () =>
         cols = @grid.getSortColumns()


clean up tabs' z-indices after dragging

clean up tabs' z-indices after dragging

--- client/ide.coffee
+++ client/ide.coffee
@@ -29,7 +29,7 @@
           $(@).closest('.ui-tabs').append $ '#win' + ui.item.attr('id').replace /\D+/, ''
           $tabs.tabs('destroy').tabs tabOpts
           return
-        stop: refreshTabs
+        stop: -> refreshTabs(); $('[role=tab]', @).attr 'style', '' # clean up z-indices after dragging

     wins = # mapping between window ids and widget instances (Dyalog.Session or Dyalog.Editor)
       0: session = Dyalog.Session $('.ui-layout-center'),


Activity: sidebar notification count listeners has been added

--- client/Social/Activity/sidebar/activitysidebar.coffee
+++ client/Social/Activity/sidebar/activitysidebar.coffee
@@ -66,19 +66,28 @@
       item           = listController.itemsIndexed[revived.id]
       listController.removeItem item

-    notificationController.on 'ChannelUpdateHappened', (update) =>
-
-      {unreadCount, channel} = update
-      {typeConstant, id}     = channel
-
-      listController = @getListController typeConstant
-
-      item = listController.itemForId id
-
-      log item, update, '>>>>>>>>>>>>>>'
+
+    notificationController
+      .on 'ChannelUpdateHappened',  @bound 'notificationHasArrived'
+      .on 'NotificationHasArrived', @bound 'notificationHasArrived'
+

     # windowController.addFocusListener (focused) ->
     #   log 'browser focus:', focused
+
+
+
+  notificationHasArrived: (update) ->
+
+    {unreadCount, channel} = update
+    {typeConstant, id}     = channel
+
+    listController = @getListController typeConstant
+
+    item = listController.itemForId id
+
+    item.setUnreadCount unreadCount  if item.unreadCount
+


Sidebar: Fetch machines and update machine tree after page load.

--- client/Social/Activity/sidebar/activitysidebar.coffee
+++ client/Social/Activity/sidebar/activitysidebar.coffee
@@ -409,9 +409,10 @@
       machineItem.on 'click', @lazyBound 'handleMachineItemClick', machineItem

     if KD.userMachines.length
-    then @listMachines KD.userMachines
-    else @fetchMachines @bound 'listMachines'
-
+      @listMachines KD.userMachines
+      @updateMachineTree()
+    else
+      @fetchMachines @bound 'listMachines'

   handleMachineItemClick: (machineItem, event) ->


kite controller: use the new kite abstraction in tellKite

--- client/landing/app/MainApp/kite/kitecontroller.coffee
+++ client/landing/app/MainApp/kite/kitecontroller.coffee
@@ -83,8 +83,16 @@
       command = options
       options = {}

+    currentGroupName = (KD.getSingleton 'groupsController').getGroupSlug()
+
     options.kiteName or= "os"
     options.method   or= "exec"
+    # options.correlationName or= currentGroupName
+
+    kite = @getKite options.kiteName,
+      if not currentGroupName or currentGroupName is 'koding'
+      then KD.whoami().profile.nickname
+      else currentGroupName

     if command
       options.withArgs = command
@@ -94,7 +102,7 @@
     notify "Calling #{options.method} method, from #{options.kiteName} kite"
     log "Kite Request:", options

-    KD.whoami().tellKite? options, (err, response)=>
+    kite.tell options, (err, response)=>
       @parseKiteResponse {err, response}, options, callback

   setListeners:->


Comment cleanup

Comment cleanup

--- client/landing/app/MainApp/sidebar/sidebarview.coffee
+++ client/landing/app/MainApp/sidebar/sidebarview.coffee
@@ -45,9 +45,6 @@
       tagName   : "h2"
       pistachio : "{{#(profile.nickname)}}.#{location.hostname}"
     , account
-
-    # @finderResizeHandle = new SidebarResizeHandle
-    #   cssClass  : "finder-resize-handle"

     @finderController = new NFinderController
       useStorage        : yes
@@ -84,11 +81,8 @@
     KD.registerSingleton "finderController", @finderController
     @listenWindowResize()

-    # @statusLEDs = new StatusLEDView
     @statusLEDs = new KDView
       cssClass : 'status-leds'
-
-    # @virtualizationButtons = new VirtualizationControls

     @finderController.on 'ManageResources', @bound 'toggleResources'

@@ -114,48 +108,6 @@
     mainController.on "AvatarPopupIsActive",   => @_popupIsActive = yes
     mainController.on "AvatarPopupIsInactive", => @_popupIsActive = no

-    # @finderResizeHandle.on "ClickedButNotDragged", =>
-    #   unless fpLastWidth
-    #     fpLastWidth = parseInt $fp.css("width"), 10
-    #     cp.$().css left : 65, width : @wc.winWidth - 65
-    #     @utils.wait 300, -> $fp.css "width", 13
-    #   else
-    #     fpLastWidth = 208 if fpLastWidth < 100
-    #     $fp.css "width", fpLastWidth
-    #     cpWidth = @wc.winWidth - 52 - fpLastWidth
-    #     cp.$().css left : 52 + fpLastWidth, width : cpWidth
-    #     cp.emit "ViewResized", {newWidth : cpWidth, unit: "px"}
-    #     fpLastWidth = null
-    #   @finderResizeHandle.$().css left: ''
-
-    # @finderResizeHandle.on "DragStarted", (e, dragState)=>
-    #   cp._left  = parseInt cp.$().css("left"), 10
-    #   cp._left  = parseInt cp.$().css("left"), 10
-    #   @_fpWidth = parseInt $fp.css("width"), 10
-    #   cp._width = parseInt @wc.winWidth - 52 - @_fpWidth, 10
-    #   cp.unsetClass "transition"
-
-    # @finderResizeHandle.on "DragFinished", (e, dragState)=>
-    #   delete cp._left
-    #   delete cp._width
-    #   delete @_fpWidth
-    #   unless @finderResizeHandle._dragged
-    #     @finderResizeHandle.emit "ClickedButNotDragged"
-    #   else
-    #     fpLastWidth = null
-    #   delete @finderResizeHandle._dragged
-    #   cp.setClass "transition"
-
-    # @finderResizeHandle.on "DragInAction", (x, y)=>
-    #   @finderResizeHandle._dragged = yes
-    #   newFpWidth = @_fpWidth + x
-    #   return @finderResizeHandle.$().css left: '' if newFpWidth < 13
-    #   cpWidth = cp._width - x
-    #   cp.$().css left : cp._left + x, width : cpWidth
-    #   @finderResizeHandle.$().css left: ''
-    #   $fp.css "width", newFpWidth
-    #   cp.emit "ViewResized", {newWidth : cpWidth, unit: "px"}
-
     # exception - Sinan, Jan 2013
     # we bind this with jquery directly bc #main-nav is no KDView but just HTML
     @$('#main-nav').on "mouseenter", @bound "animateLeftNavIn"
@@ -187,7 +139,6 @@
     @setListeners()

   pistachio:->
-    # {{> @finderResizeHandle}} removed until fixed
     """

@@ -254,7 +205,6 @@

   showBottomControls:->
     @$('#finder-bottom-controls').removeClass 'go-down'
-    # @$("#finder-holder").height @getHeight() - @$("#finder-header-holder").height() - 27

   toggleResources:->
     @$('#finder-bottom-controls').toggleClass 'show-resources'
@@ -262,13 +212,6 @@
   _windowDidResize:->

     {winWidth} = @getSingleton('windowController')
-    # if KD.isLoggedIn()
-    #   if @contentPanel.$().hasClass "with-finder"
-    #     @contentPanel.setWidth winWidth - parseInt(@$('#finder-panel').css("width"), 10) - 52
-    #   else
-    #     @contentPanel.setWidth winWidth - 160
-    # else
-    #   @contentPanel.setWidth winWidth

     bottomListHeight = @$("#finder-bottom-controls").height() or 109
     @$("#finder-holder").height @getHeight() - @$("#finder-header-holder").height() - bottomListHeight
@@ -317,14 +260,6 @@
         title   : "Launch Terminal", icon : "terminal",
         appPath : "WebTerm", isWebTerm : yes
       }
-      # {
-      #   title   : "Manage Remotes", icon : "remotes",
-      #   action  : "manageRemotes"
-      # }
-      # {
-      #   title   : "Manage Databases", icon : "databases",
-      #   action  : "manageDatabases"
-      # }
       { title   : "Settings",           icon : "cog" }
       {
         title   : "Keyboard Shortcuts", icon : "shortcuts",
@@ -340,7 +275,6 @@
     id    : "admin-navigation"
     title : "admin-navigation"
     items : [
-      # { title : "Kite selector", loggedIn : yes, callback : -> new KiteSelectorModal }
       {
         title    : "Admin Panel",
         loggedIn : yes,


Let the cog reinitialize your VM

Let the cog reinitialize your VM

--- client/landing/app/MainApp/sidebar/sidebarview.coffee
+++ client/landing/app/MainApp/sidebar/sidebarview.coffee
@@ -67,12 +67,9 @@
       cssClass     : "server-pin-button"
       iconOnly     : yes
       iconClass    : "cog"
-      # callback     : =>
-      #   $('body').addClass 'server-stack'
-      #   @putOverlay
-      #     animated    : yes
-      #     isRemovable : no
-      #     color       : 'rgba(0,0,0,.3)'
+      tooltip      :
+        title      : "Re-initialize your VM"
+      callback     : => KD.singletons.vmController.reinitialize()

     @finderBottomControlPin = new KDToggleButton
       cssClass     : "finder-bottom-pin"


Stacks: Remove "Stacks" title from breadcrumb

--- client/stacks/lib/views/stacks/definestackview.coffee
+++ client/stacks/lib/views/stacks/definestackview.coffee
@@ -52,7 +52,7 @@
     @addSubView new kd.CustomHTMLView
       tagName  : 'header'
       cssClass : 'breadcrumb'
-      partial  : "Stacks > #{breadcrumbTitle}"
+      partial  : "#{breadcrumbTitle}"

     @createStackNameInput()
     @addSubView @tabView = new KDTabView hideHandleCloseIcons: yes


AutoCompleteController: use addItemView for adding View instances

--- src/components/autocomplete/autocompletecontroller.coffee
+++ src/components/autocomplete/autocompletecontroller.coffee
@@ -178,7 +178,7 @@
           inexactMatches.push datum

     if (@dropdownPrefix.length >= minSuggestionLength) and allowNewSuggestions and not exactMatches.length
-      @dropdown.getListView().addItem @getNoItemFoundView()
+      @dropdown.getListView().addItemView @getNoItemFoundView()

     data = exactMatches.concat inexactMatches
     @dropdown.instantiateListItems data
@@ -385,7 +385,7 @@
     list = @dropdown.getListView()

     @dropdown.removeAllItems()
-    list.addItem new fetchingItemClass {}, {}
+    list.addItemView new fetchingItemClass {}, {}
     @showDropdown()

   getNoItemFoundView: (suggestion) ->
@@ -403,7 +403,7 @@

     noItemFoundView = @getNoItemFoundView()
     @dropdown.removeAllItems()
-    @dropdown.getListView().addItem noItemFoundView
+    @dropdown.getListView().addItemView noItemFoundView
     @showDropdown()

   destroy:->


ランダムに結果を表示するすように変更。

ランダムに結果を表示するすように変更。

--- scripts/recommend_lunch.coffee
+++ scripts/recommend_lunch.coffee
@@ -1,7 +1,7 @@
 Yelp = require 'yelp'

 module.exports = (robot) ->
-    robot.hear /(おすすめ)/i, (msg) ->
+    robot.respond /(腹|お腹)(減った|空いた)/i, (msg) ->
         yelp = new Yelp({
           consumer_key: process.env.YELP_CONSUMER_KEY,
           consumer_secret: process.env.YELP_CONSUMER_SECRET,
@@ -9,9 +9,18 @@
           token_secret: process.env.YELP_TOKEN_SECRET
         })

-        yelp.search({ term: 'food', location: '港区南青山6-10-12', radius_filter: 1000, limit: 1, cc: 'JP', lang: 'ja' })
+        yelp.search({ term: 'food', location: '港区南青山6-10-12', radius_filter: 2000, cc: 'JP', lang: 'ja' })
         .then (data) ->
-            msg.send data.businesses[0].name
+            total = data.businesses.length
+            console.log total
+            random = Math.floor(Math.random() * total)
+            console.log random
+
+            answer = "こんな所はどうでしょう？¥n¥n"
+            answer += data.businesses[random].name + "¥n"
+            answer += data.businesses[random].url
+
+            msg.send answer
         .catch (err) ->
             console.log(err)
             msg.send err


Mathjax preprocessor is course-specific

Mathjax preprocessor is course-specific

--- common/lib/xmodule/xmodule/js/src/capa/display.coffee
+++ common/lib/xmodule/xmodule/js/src/capa/display.coffee
@@ -6,6 +6,11 @@
     @element_id = @el.attr('id')
     @url = @el.data('url')
     @render()
+
+    # TODO: Each course should be able to customize the MathJax preprocessor
+    #       through a generic plug-in
+    if (@id).search('6.002x') >= 0
+      @mathjax_preprocessor = @mathjax_preprocessor_for_6002x

   $: (selector) ->
     $(selector, @el)
@@ -299,12 +304,15 @@
     target = "display_#{element.id.replace(/^input_/, '')}"

     if jax = MathJax.Hub.getAllJax(target)[0]
-      eqn = @mathjax_preprocessor($(element).val())
-      #eqn = $(element).val()
+      eqn = $(element).val()
+      if @mathjax_preprocessor
+        eqn = @mathjax_preprocessor(eqn)
+
       MathJax.Hub.Queue ['Text', jax, eqn],
         [@updateMathML, jax, element]

-  mathjax_preprocessor: (eqn) ->
+  # TODO: The 6.002x preprocessor should not be baked into capa/display.coffee, but should be a plug-in
+  mathjax_preprocessor_for_6002x: (eqn) ->
     ###
     Translate 6.002x conventions for subscripts to standard Latex, e.g.
       'R3'  --> 'R_{3}'


Calculate the total score from the rubric.

--- common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee
+++ common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee
@@ -16,6 +16,10 @@

   @get_total_score: () ->
     score_lst = @get_score_list()
+    tot = 0
+    for score in score_lst
+      tot += parseInt(score)
+    return tot

   @check_complete: () ->
      # check to see whether or not any categories have not been scored


Usability fixes for auto complete controller

--- components/autocomplete/autocompletecontroller.coffee
+++ components/autocomplete/autocompletecontroller.coffee
@@ -31,6 +31,7 @@
     @selectedItemData    = []
     @hiddenInputs        = {}
     @selectedItemCounter = 0
+    @readyToShowDropDown = yes

   reset:->
     subViews    = @itemWrapper.getSubViews().slice()
@@ -61,6 +62,7 @@
           @submitAutoComplete autoCompleteView.getValue()
           event.stopPropagation()
           event.preventDefault()
+          @readyToShowDropDown = no
           return no
         else
           return yes
@@ -82,6 +84,8 @@
           event.preventDefault()
           return no
         # @getView().$input().blur()
+      else
+        @readyToShowDropDown = yes
     no

   getPrefix:()->
@@ -129,6 +133,9 @@
     dropdownWrapper.$().fadeOut 75

   showDropdown:->
+
+    return unless @readyToShowDropDown
+
     windowController = @getSingleton('windowController')
     dropdownWrapper = @dropdown.getView()
     dropdownWrapper.unsetClass "hidden"
@@ -283,7 +290,8 @@
     @emit 'AutocompleteSuggestionWasAdded', title

   addItemToSubmitQueue:(item,data)->
-    data or= item.getData()
+    data or= item?.getData()
+    return unless data

     {itemDataPath,form,submitValuesAsText} = @getOptions()


renamed opts to options

renamed opts to options

extracted expressions because of long line

--- core/app/backbone/collections/interactors_page.coffee
+++ core/app/backbone/collections/interactors_page.coffee
@@ -17,11 +17,13 @@
     @totalPages = Math.floor(response.total / @perPage)
     response.users

-  initialize: (opts) ->
+  initialize: (options) ->
+    fact_id = options.fact_id
+    group = group_for_type(options.type)
     @paginator_core =
       dataType: "json"
-      url: "/facts/#{opts.fact_id}/#{group_for_type(opts.type)}"
+      url: "/facts/#{fact_id}/#{group}"
     @paginator_ui =
-      perPage: opts.perPage || 6
+      perPage: options.perPage || 6
       firstPage: 1
       currentPage: 1