fix for embeds that the user does not want to be shown in the activity stream

--- client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemStatusUpdate.coffee
+++ client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemStatusUpdate.coffee
@@ -25,7 +25,13 @@

     # If there is embed data in the model, use that!
     if @getData()?.link
-      @embedBox.embedExistingData @getData()?.link?.link_embed, {}
+      if not ("embed" in @getData().link.link_embed_hidden_items)
+        @embedBox.show()
+        @embedBox.embedExistingData @getData()?.link?.link_embed, {}
+      else
+        # no need to show stuff if it should not be shown. not even in the code
+        @embedBox.hide()
+        @embedBox.destroy()

     # This will involve heavy load on the embedly servers - every client
     # will need to make a request.
@@ -36,6 +42,7 @@
           firstUrl = $(url).attr "href"

       if firstUrl then @embedBox.embedUrl firstUrl, {}
+      else @embed

   click:(event)->


Fixed reference error.

Fixed reference error.

--- app/assets/javascripts/views/clouds/chat.js.coffee
+++ app/assets/javascripts/views/clouds/chat.js.coffee
@@ -226,7 +226,7 @@
       window.setTimeout =>
         @resizeElements()
       , 305
-      $('.chat-inspect').append(view)
+      @.$('.chat-inspect').append(view)

     false


prevents defualt movement for updownleftright and adds collapseCells

--- js/main.coffee
+++ js/main.coffee
@@ -34,14 +34,15 @@
     if direction is 'right'
       row = getRow(i, board)
       mergeCells(row, direction)
-      collapseCells()
+      collapseCells(row, direction)
+

 getRow = (r, board) ->
   [board[r][0], board[r][1], board[r][2], board[r][3]]
-  #console.log 'get row'

 mergeCells = (row, direction) ->
-  #console.log 'merge cells'
+  #to merge the cells we need to know the rows and the direction
+  #this is a double for loop which iterates over all the possible comparisons within the array
   if direction is 'right'
     for a in [3...0]
       for b in [a-1..0]
@@ -50,16 +51,27 @@
         else if row[a] is row[b]
           row[a] *= 2
           row[b] = 0
-        else if row[a] isnt 0
+        else if row[b] isnt 0
           break
   row

-console.log mergeCells([4,4,2,0],'right')
-console.log mergeCells([4,0,0,4],'right')
-console.log mergeCells([4,4,2,0],'right')
+collapseCells = (row, direction) ->
+  row = row.filter (x) -> x isnt 0
+  zeroesToAdd = 4 - row.length
+  for i in [0...zeroesToAdd]
+    switch direction
+      when 'right','down' then row.unshift 0
+      when 'left','up' then row.push 0
+  console.log row
+  row

-collapseCells = ->
-  console.log 'collapse cells'
+  # if direction is 'right'
+  #   while row.length < 4
+  #     row.unshift 0
+  # console.log row
+  # row
+
+

 printArray = (array) ->
   console.log "--start--"
@@ -82,6 +94,7 @@
   @board = buildBoard()
   generateTile(@board)
   generateTile(@board)
+  printArray(@board)
   showBoard(@board)

   $('body').keydown (e) => #where keydown is the event and everything after (e) is the event handler
@@ -89,7 +102,7 @@
     key = e.which #event.which is a function in jquery which returns which key you pressed
     keys = [37..40]
     if key in keys
-      #e.preventDefault()
+      e.preventDefault()
       direction = switch key #the switch function switches the value based upon conditions
         when 37 then 'left'
         when 38 then 'up'


Kernel: Fix bug on ZMQ monitoring disabled

Fixes #248

--- lib/kernel.coffee
+++ lib/kernel.coffee
@@ -111,9 +111,12 @@
         @controlSocket.on 'connect', () -> console.log "controlSocket connected"
         @ioSocket.on 'connect', () -> console.log "ioSocket connected"

-        @shellSocket.monitor()
-        @controlSocket.monitor()
-        @ioSocket.monitor()
+        try
+            @shellSocket.monitor()
+            @controlSocket.monitor()
+            @ioSocket.monitor()
+        catch err
+            console.log "Kernel:", err

     interrupt: ->
         console.log "sending SIGINT"


:new: Show a notification when no linters are installed

--- lib/linter.coffee
+++ lib/linter.coffee
@@ -13,6 +13,7 @@
   # State is an object by default; never null or undefined
   constructor: (@state)  ->
     @state.scope ?= 'File'
+    @warningShown = false

     # Public Stuff
     @lintOnFly = true # A default art value, to be immediately replaced by the observe config below
@@ -95,7 +96,11 @@
     editorLinter.onShouldUpdateBubble =>
       @views.renderBubble(editorLinter)
     editorLinter.onShouldLint (onChange) =>
-      @linters.lint({onChange, editorLinter})
+      if @linters.linters.size
+        @linters.lint({onChange, editorLinter})
+      else if not @indieLinters.indieLinters.size and not @warningShown
+        @warningShown = true
+        atom.notifications.addWarning('No Linter Providers Found', {detail: 'Goto atomlinter.github.io to get a list of linter providers for your favorite language', dismissable: true})
     editorLinter.onDidDestroy =>
       @messages.deleteEditorMessages(editorLinter)
     editorLinter.onDidCalculateLineMessages =>


memory: commented

memory: commented

--- lib/memory.coffee
+++ lib/memory.coffee
@@ -1,116 +1,116 @@

-{merge} = require 'mecano/lib/misc'
+# {merge} = require 'mecano/lib/misc'

-# https://github.com/hortonworks/hdp-configuration-utils/blob/master/2.1/hdp-configuration-utils.py
-# https://support.pivotal.io/hc/en-us/articles/201462036-Mapreduce-YARN-Memory-Parameters
+# # https://github.com/hortonworks/hdp-configuration-utils/blob/master/2.1/hdp-configuration-utils.py
+# # https://support.pivotal.io/hc/en-us/articles/201462036-Mapreduce-YARN-Memory-Parameters

-memory = (ctx) ->
-  {yarn, hadoop_conf_dir} = ctx.config.ryba
-  # yarn.nodemanager.log.retain-seconds (cherif mettre la valeur à 10800 au lie de 604800)
-  # yarn.log-aggregation.retain-seconds (cherif)
+# memory = (ctx) ->
+#   {yarn, hadoop_conf_dir} = ctx.config.ryba
+#   # yarn.nodemanager.log.retain-seconds (cherif mettre la valeur à 10800 au lie de 604800)
+#   # yarn.log-aggregation.retain-seconds (cherif)

-  # Follow [Hortonworks example](http://hortonworks.com/blog/how-to-plan-and-configure-yarn-in-hdp-2-0/)
-  # As a general recommendation, Hortonworks found that allowing for 1-2
-  # Containers per disk and per core gives the best balance for cluster utilization.
-  # Each machine in our cluster has 96 GB of RAM. Some of this RAM should be
-  # reserved for Operating System usage. On each node, we’ll reserve 10%
-  # with a maximum of 8 GB for the Operating System.
-  coreNumber = ctx.cpuinfo.length
-  diskNumber = yarn.site['yarn.nodemanager.local-dirs'].length
-  memoryTotalMb = Math.floor ctx.meminfo.MemTotal / 1000 / 1000
-  memoryAvailableMb = memoryTotalMb - memory.getReservedMemory(memoryTotalMb, false)
-  # minimum container size (in RAM)
-  mininumContainerSize = memory.getMininumContainerSize memoryAvailableMb
-  # Maximum number of containers allowed per node:
-  # min (2*CORES, 1.8*DISKS, (Total available RAM / MIN_CONTAINER_SIZE) )
-  maxNumberOfcontainers = Math.floor Math.min coreNumber*2, diskNumber * 1.8, (memoryAvailableMb / mininumContainerSize)
-  # Amount of RAM per container
-  # max(MIN_CONTAINER_SIZE, (Total Available RAM) / containers))
-  memoryPerContainer = Math.floor Math.max mininumContainerSize, memoryAvailableMb / maxNumberOfcontainers
-  # Get default
-  yarnNodeManagerResourceMemoryMb = yarn.site['yarn.nodemanager.resource.memory-mb']
-  YarnNodemanagerVirtualMemoryRatio = yarn.site['yarn.nodemanager.vmem-pmem-ratio']
-  yarnSchedulerMinimumAllocationMb = yarn.site['yarn.scheduler.minimum-allocation-mb']
-  yarnSchedulerMaximumAllocationMb = yarn.site['yarn.scheduler.maximum-allocation-mb']
-  yarnAppMapreduceAmResourceMb = yarn.site['yarn.app.mapreduce.am.resource.mb']
-  yarnAppMapreduceAmCommandOpts = /-Xmx(.*)m/.exec(yarn.site['yarn.app.mapreduce.am.command-opts'])?[1]
-  # Compute
-  yarnNodeManagerResourceMemoryMb ?= maxNumberOfcontainers * memoryPerContainer
-  yarnSchedulerMinimumAllocationMb ?= memoryPerContainer
-  yarnSchedulerMaximumAllocationMb ?= maxNumberOfcontainers * memoryPerContainer # containers * RAM-per-container
-  yarnAppMapreduceAmResourceMb ?= 2 * memoryPerContainer # 2 * RAM-per-container
-  yarnAppMapreduceAmCommandOpts ?= Math.floor(.8 * 2 * memoryPerContainer) # 0.8 * 2 * RAM-per-container
-  YarnNodemanagerVirtualMemoryRatio ?= 2.1 # Virtual memory (physical + paged memory) upper limit for each Map and Reduce task
-  mapreduceMapMemoryMb = memoryPerContainer
-  mapreduceReduceMemoryMb = 2 * memoryPerContainer # 2 * RAM-per-container
-  # Constrain
-  yarnAppMapreduceAmResourceMb = Math.min yarnAppMapreduceAmResourceMb, yarnSchedulerMaximumAllocationMb
-  yarnAppMapreduceAmCommandOpts = Math.min yarnAppMapreduceAmCommandOpts, yarnSchedulerMaximumAllocationMb
-  mapreduceMapMemoryMb = Math.min mapreduceMapMemoryMb, yarnSchedulerMaximumAllocationMb # RAM-per-container cannot exceed YARN maximum allocation, example: "Invalid resource request, requested memory < 0, or requested memory > max configured, requestedMemory=1922, maxMemory=1800"
-  mapreduceReduceMemoryMb = Math.min mapreduceReduceMemoryMb, yarnSchedulerMaximumAllocationMb # RAM per reduce task cannot exceed YARN minimum allocation, example: "REDUCE capability required is more than the supported max container capability in the cluster. Killing the Job. reduceResourceReqt: 3844 maxContainerCapability:1922"
-  result =
-    info:
-      'coreNumber': coreNumber
-      'diskNumber': diskNumber
-      'memoryTotalMb': memoryTotalMb
-      'memoryAvailableMb': memoryAvailableMb
-      'mininumContainerSize': mininumContainerSize
-      'maxNumberOfcontainers': maxNumberOfcontainers
-      'memoryPerContainer': memoryPerContainer
-    yarn:
-      site:
-        'yarn.nodemanager.resource.memory-mb': "#{yarnNodeManagerResourceMemoryMb}" # containers * RAM-per-container
-        'yarn.nodemanager.vmem-pmem-ratio': "#{YarnNodemanagerVirtualMemoryRatio}"
-        'yarn.scheduler.minimum-allocation-mb': "#{yarnSchedulerMinimumAllocationMb}" # RAM-per-container
-        'yarn.scheduler.maximum-allocation-mb': "#{yarnSchedulerMaximumAllocationMb}"
-        'yarn.app.mapreduce.am.resource.mb': "#{yarnAppMapreduceAmResourceMb}" # Default to "682"
-        'yarn.app.mapreduce.am.command-opts': "-Xmx#{yarnAppMapreduceAmCommandOpts}m" # Default to "-Xmx546m"
-    mapred:
-      site:
-        'mapreduce.map.memory.mb': "#{mapreduceMapMemoryMb}"
-        'mapreduce.reduce.memory.mb': "#{mapreduceReduceMemoryMb}"
-        'mapreduce.map.java.opts': "-Xmx#{Math.floor .8 * memoryPerContainer}m" # 0.8 * RAM-per-container
-        'mapreduce.reduce.java.opts': "-Xmx#{Math.floor .8 * 2 * memoryPerContainer}m" # 0.8 * 2 * RAM-per-container
-        'mapreduce.task.io.sort.mb': "#{Math.floor .4 * memoryPerContainer}"
-  # merge result.yarn.site, ctx.config.ryba.yarn.site
-  for k, v of result.yarn.site
-    result.yarn.site[k] = ctx.config.ryba.yarn.site[k] if ctx.config.ryba.yarn.site[k]?
-  # merge result.mapred.site, ctx.config.ryba.mapred.site
-  for k, v of result.mapred.site
-    result.mapred.site[k] = ctx.config.ryba.mapred.site[k] if ctx.config.ryba.mapred.site[k]?
-  result
+#   # Follow [Hortonworks example](http://hortonworks.com/blog/how-to-plan-and-configure-yarn-in-hdp-2-0/)
+#   # As a general recommendation, Hortonworks found that allowing for 1-2
+#   # Containers per disk and per core gives the best balance for cluster utilization.
+#   # Each machine in our cluster has 96 GB of RAM. Some of this RAM should be
+#   # reserved for Operating System usage. On each node, we’ll reserve 10%
+#   # with a maximum of 8 GB for the Operating System.
+#   coreNumber = ctx.cpuinfo.length
+#   diskNumber = yarn.site['yarn.nodemanager.local-dirs'].length
+#   memoryTotalMb = Math.floor ctx.meminfo.MemTotal / 1000 / 1000
+#   memoryAvailableMb = memoryTotalMb - memory.getReservedMemory(memoryTotalMb, false)
+#   # minimum container size (in RAM)
+#   mininumContainerSize = memory.getMininumContainerSize memoryAvailableMb
+#   # Maximum number of containers allowed per node:
+#   # min (2*CORES, 1.8*DISKS, (Total available RAM / MIN_CONTAINER_SIZE) )
+#   maxNumberOfcontainers = Math.floor Math.min coreNumber*2, diskNumber * 1.8, (memoryAvailableMb / mininumContainerSize)
+#   # Amount of RAM per container
+#   # max(MIN_CONTAINER_SIZE, (Total Available RAM) / containers))
+#   memoryPerContainer = Math.floor Math.max mininumContainerSize, memoryAvailableMb / maxNumberOfcontainers
+#   # Get default
+#   yarnNodeManagerResourceMemoryMb = yarn.site['yarn.nodemanager.resource.memory-mb']
+#   YarnNodemanagerVirtualMemoryRatio = yarn.site['yarn.nodemanager.vmem-pmem-ratio']
+#   yarnSchedulerMinimumAllocationMb = yarn.site['yarn.scheduler.minimum-allocation-mb']
+#   yarnSchedulerMaximumAllocationMb = yarn.site['yarn.scheduler.maximum-allocation-mb']
+#   yarnAppMapreduceAmResourceMb = yarn.site['yarn.app.mapreduce.am.resource.mb']
+#   yarnAppMapreduceAmCommandOpts = /-Xmx(.*)m/.exec(yarn.site['yarn.app.mapreduce.am.command-opts'])?[1]
+#   # Compute
+#   yarnNodeManagerResourceMemoryMb ?= maxNumberOfcontainers * memoryPerContainer
+#   yarnSchedulerMinimumAllocationMb ?= memoryPerContainer
+#   yarnSchedulerMaximumAllocationMb ?= maxNumberOfcontainers * memoryPerContainer # containers * RAM-per-container
+#   yarnAppMapreduceAmResourceMb ?= 2 * memoryPerContainer # 2 * RAM-per-container
+#   yarnAppMapreduceAmCommandOpts ?= Math.floor(.8 * 2 * memoryPerContainer) # 0.8 * 2 * RAM-per-container
+#   YarnNodemanagerVirtualMemoryRatio ?= 2.1 # Virtual memory (physical + paged memory) upper limit for each Map and Reduce task
+#   # mapreduceMapMemoryMb = memoryPerContainer
+#   # mapreduceReduceMemoryMb = 2 * memoryPerContainer # 2 * RAM-per-container
+#   # Constrain
+#   yarnAppMapreduceAmResourceMb = Math.min yarnAppMapreduceAmResourceMb, yarnSchedulerMaximumAllocationMb
+#   yarnAppMapreduceAmCommandOpts = Math.min yarnAppMapreduceAmCommandOpts, yarnSchedulerMaximumAllocationMb
+#   # mapreduceMapMemoryMb = Math.min mapreduceMapMemoryMb, yarnSchedulerMaximumAllocationMb # RAM-per-container cannot exceed YARN maximum allocation, example: "Invalid resource request, requested memory < 0, or requested memory > max configured, requestedMemory=1922, maxMemory=1800"
+#   # mapreduceReduceMemoryMb = Math.min mapreduceReduceMemoryMb, yarnSchedulerMaximumAllocationMb # RAM per reduce task cannot exceed YARN minimum allocation, example: "REDUCE capability required is more than the supported max container capability in the cluster. Killing the Job. reduceResourceReqt: 3844 maxContainerCapability:1922"
+#   result =
+#     info:
+#       'coreNumber': coreNumber
+#       'diskNumber': diskNumber
+#       'memoryTotalMb': memoryTotalMb
+#       'memoryAvailableMb': memoryAvailableMb
+#       'mininumContainerSize': mininumContainerSize
+#       'maxNumberOfcontainers': maxNumberOfcontainers
+#       'memoryPerContainer': memoryPerContainer
+#     yarn:
+#       site:
+#         'yarn.nodemanager.resource.memory-mb': "#{yarnNodeManagerResourceMemoryMb}" # containers * RAM-per-container
+#         # 'yarn.nodemanager.vmem-pmem-ratio': "#{YarnNodemanagerVirtualMemoryRatio}"
+#         'yarn.scheduler.minimum-allocation-mb': "#{yarnSchedulerMinimumAllocationMb}" # RAM-per-container
+#         'yarn.scheduler.maximum-allocation-mb': "#{yarnSchedulerMaximumAllocationMb}"
+#         # 'yarn.app.mapreduce.am.resource.mb': "#{yarnAppMapreduceAmResourceMb}" # Default to "682"
+#         'yarn.app.mapreduce.am.command-opts': "-Xmx#{yarnAppMapreduceAmCommandOpts}m" # Default to "-Xmx546m"
+#     # mapred:
+#     #   site:
+#     #     'mapreduce.map.memory.mb': "#{mapreduceMapMemoryMb}"
+#     #     'mapreduce.reduce.memory.mb': "#{mapreduceReduceMemoryMb}"
+#     #     'mapreduce.map.java.opts': "-Xmx#{Math.floor .8 * memoryPerContainer}m" # 0.8 * RAM-per-container
+#     #     'mapreduce.reduce.java.opts': "-Xmx#{Math.floor .8 * 2 * memoryPerContainer}m" # 0.8 * 2 * RAM-per-container
+#     #     'mapreduce.task.io.sort.mb': "#{Math.floor .4 * memoryPerContainer}"
+#   # merge result.yarn.site, ctx.config.ryba.yarn.site
+#   for k, v of result.yarn.site
+#     result.yarn.site[k] = ctx.config.ryba.yarn.site[k] if ctx.config.ryba.yarn.site[k]?
+#   # merge result.mapred.site, ctx.config.ryba.mapred.site
+#   # for k, v of result.mapred.site
+#   #   result.mapred.site[k] = ctx.config.ryba.mapred.site[k] if ctx.config.ryba.mapred.site[k]?
+#   result

-memory.reservedStack = 4:1, 8:2, 16:2, 24:4, 48:6, 64:8, 72:8, 96:12, 128:24, 256:32, 512:64
+# memory.reservedStack = 4:1, 8:2, 16:2, 24:4, 48:6, 64:8, 72:8, 96:12, 128:24, 256:32, 512:64

-memory.reservedHBase = 4:1, 8:1, 16:2, 24:4, 48:8, 64:8, 72:8, 96:16, 128:24, 256:32, 512:64
+# memory.reservedHBase = 4:1, 8:1, 16:2, 24:4, 48:8, 64:8, 72:8, 96:16, 128:24, 256:32, 512:64

-memory.getReservedMemory = (memory_mb, withHBase=false) ->
-  reservedMemory = 0
-  if memory_mb < memory.reservedStack[0]
-    reservedMemory += memory.reservedStack[0]
-  else if memory_mb >= memory.reservedStack[memory.reservedStack.length-1]
-    reservedMemory += memory.reservedStack[memory.reservedStack.length-1]
-  else
-    for total, reserved of memory.reservedStack
-      if memory_mb < total
-        reservedMemory += Math.ceil memory_mb * reserved / total
-        break
-  if withHBase
-    if memory_mb < memory.reservedHBase[0]
-      reservedMemory += memory.reservedHBase[0]
-    else if memory_mb >= memory.reservedHBase[memory.reservedHBase.length-1]
-      reservedMemory += memory.reservedHBase[memory.reservedHBase.length-1]
-    else
-      for total, reserved of memory.reservedHBase
-        if memory_mb < total
-          reservedMemory += Math.ceil memory_mb * reserved / total
-          break
-  reservedMemory
+# memory.getReservedMemory = (memory_mb, withHBase=false) ->
+#   reservedMemory = 0
+#   if memory_mb < memory.reservedStack[0]
+#     reservedMemory += memory.reservedStack[0]
+#   else if memory_mb >= memory.reservedStack[memory.reservedStack.length-1]
+#     reservedMemory += memory.reservedStack[memory.reservedStack.length-1]
+#   else
+#     for total, reserved of memory.reservedStack
+#       if memory_mb < total
+#         reservedMemory += Math.ceil memory_mb * reserved / total
+#         break
+#   if withHBase
+#     if memory_mb < memory.reservedHBase[0]
+#       reservedMemory += memory.reservedHBase[0]
+#     else if memory_mb >= memory.reservedHBase[memory.reservedHBase.length-1]
+#       reservedMemory += memory.reservedHBase[memory.reservedHBase.length-1]
+#     else
+#       for total, reserved of memory.reservedHBase
+#         if memory_mb < total
+#           reservedMemory += Math.ceil memory_mb * reserved / total
+#           break
+#   reservedMemory

-memory.getMininumContainerSize = (memory_mb) ->
-  if memory_mb <= 4*1024 then 256
-  else if memory_mb <= 8*1024 then 512
-  else if memory_mb <= 24*1024 then 1024
-  else 2048
+# memory.getMininumContainerSize = (memory_mb) ->
+#   if memory_mb <= 4*1024 then 256
+#   else if memory_mb <= 8*1024 then 512
+#   else if memory_mb <= 24*1024 then 1024
+#   else 2048

-module.exports = memory
+# module.exports = memory


:art: cleanup Find, improve SearchCurrentWord.

--- lib/motion.coffee
+++ lib/motion.coffee
@@ -479,19 +479,12 @@
   isBackwards: ->
     @backwards

-  getOffset: ->
-    if @isBackwards() then @offset else -@offset
-
-  getUnOffset: ->
-    -@getOffset() * @isRepeatFind()
-
   find: (cursor) ->
     cursorPoint = cursor.getBufferPosition()
     {start, end} = @editor.bufferRangeForBufferRow(cursorPoint.row)

-    points   = []
-    offset   = @getOffset()
-    unOffset = @getUnOffset()
+    offset   = if @isBackwards() then @offset else -@offset
+    unOffset = -offset * @isRepeatFind()
     if @isBackwards()
       scanRange = [start, cursorPoint.translate([0, unOffset])]
       method    = 'backwardsScanInBufferRange'
@@ -499,9 +492,9 @@
       scanRange = [cursorPoint.translate([0, 1 + unOffset]), end]
       method    = 'scanInBufferRange'

+    points   = []
     @editor[method] ///#{_.escapeRegExp(@input)}///g, scanRange, ({range}) ->
       points.push range.start
-
     points[@getCount(1) - 1]?.translate([0, offset])

   moveCursor: (cursor) ->
@@ -612,7 +605,8 @@

     cursorPosition = cursor.getBufferPosition()
     ranges = []
-    @editor.scan @getSearchTerm(@input), ({range}) ->
+    pattern = @getPattern(@input)
+    @editor.scan pattern, ({range}) ->
       ranges.push range

     [rangesBefore, rangesAfter] = _.partition ranges, ({start}) =>
@@ -625,9 +619,13 @@
     ranges.reverse() if @isBackwards()
     ranges

-  getSearchTerm: (term) ->
+  # getPattern: (text) ->
+  #   flags = 'g'
+  #   flags += 'i' if settings.get('useSmartcaseForSearch') and text.match('[A-Z]')
+  #   new RegExp(_.escapeRegExp(text), flags)
+
+  getPattern: (term) ->
     modifiers = {'g': true}
-
     if not term.match('[A-Z]') and settings.get('useSmartcaseForSearch')
       modifiers['i'] = true

@@ -667,15 +665,19 @@

   constructor: ->
     super
-
     # FIXME: This must depend on the current language
     defaultIsKeyword = "[@a-zA-Z0-9_\-]+"
     userIsKeyword = atom.config.get('vim-mode.iskeyword')
     @wordRegex = new RegExp(userIsKeyword or defaultIsKeyword)
-    @abort() unless word = @getCurrentWord()
-    @input = if /\W/.test(word) then "#{word}\\b" else "\\b#{word}\\b"
+    unless @input = @getCurrentWord()
+      @abort()
     unless @input is @vimState.getSearchHistoryItem()
       @vimState.pushSearchHistory(@input)
+
+  getPattern: (text) ->
+    pattern = _.escapeRegExp(text)
+    pattern = if /\W/.test(text) then "#{pattern}\\b" else "\\b#{pattern}\\b"
+    new RegExp(pattern, 'gi') # always case insensitive.

   # FIXME: Should not move cursor.
   getCurrentWord: ->


:bug: `n`, `N` in different editor cause `flashScreen` is not function

fix degradation caused by #200 refactoring Search feature.

--- lib/motion.coffee
+++ lib/motion.coffee
@@ -760,6 +760,13 @@
     @matches?.destroy()
     @matches = null

+  flashScreen: ->
+    if settings.get('flashScreenOnSearchHasNoMatch')
+      highlightRanges @editor, getVisibleBufferRange(@editor),
+        class: 'vim-mode-plus-flash'
+        timeout: 100
+    atom.beep()
+
   moveCursor: (cursor) ->
     # console.log "moving!"
     @matches ?= @scan(cursor)
@@ -865,13 +872,6 @@
     if @isIncrementalSearch() and settings.get('showHoverSearchCounter')
       @vimState.hoverSearchCounter.reset()
     super
-
-  flashScreen: ->
-    if settings.get('flashScreenOnSearchHasNoMatch')
-      highlightRanges @editor, getVisibleBufferRange(@editor),
-        class: 'vim-mode-plus-flash'
-        timeout: 100
-    atom.beep()

   visitCursors: ->
     @matches?.destroy()


one too many callbacks .

one too many callbacks .

--- lib/server.coffee
+++ lib/server.coffee
@@ -462,7 +462,6 @@
 							setImmediate ->
 								getDocsCargo.push couch_toprocess
 								return
-							callback()
 						else
 							for item in bulkbody.rows
 								if item?.doc?.exec?
@@ -485,7 +484,6 @@
 										console.log "invalid doc",item.id
 										index = findplace(item.id)
 										workque[index].status = "dropped"
-
 						callback()
 			), config.readBatchsize)
 			syncJobs = (host, jobs) ->


Issue #860. Nested classes.

Issue #860. Nested classes.

--- nodes.coffee
+++ nodes.coffee
@@ -786,6 +786,7 @@
   # Walk the body of the class, looking for prototype properties to be converted.
   walkBody: (name) ->
     @traverseChildren false, (child) =>
+      return false if child instanceof Class
       if child instanceof Expressions
         for node, i in exps = child.expressions
           if node instanceof Value and node.isObject(true)


fixes #1973: redefining Array/Object constructors shouldn't break helpers

--- nodes.coffee
+++ nodes.coffee
@@ -1876,12 +1876,12 @@

   # Discover if an item is in an array.
   indexOf: -> """
-    Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }
+    [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }
   """

   # Shortcuts to speed up the lookup time for native functions.
-  hasProp: -> 'Object.prototype.hasOwnProperty'
-  slice  : -> 'Array.prototype.slice'
+  hasProp: -> '{}.hasOwnProperty'
+  slice  : -> '[].slice'

 # Levels indicate a node's position in the AST. Useful for knowing if
 # parens are necessary or superfluous.


Fix #2953. Method calls on splice endpoints

--- nodes.coffee
+++ nodes.coffee
@@ -1261,7 +1261,8 @@
     else
       fromDecl = fromRef = '0'
     if to
-      if from?.isSimpleNumber() and to.isSimpleNumber()
+      if from and from instanceof Value and from?.isSimpleNumber() and
+                    to instanceof Value and to.isSimpleNumber()
         to = +to.compile(o) - +fromRef
         to += 1 unless exclusive
       else


Added function call's flexibility with splats to array literals, factoring out splat compiling, and adjusted tests

--- nodes.coffee
+++ nodes.coffee
@@ -329,6 +329,7 @@

   constructor: (variable, args) ->
     @children:  flatten [@variable: variable, @args: (args or [])]
+    @compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args
     @prefix:    ''

   # Tag this invocation as creating a new instance.
@@ -365,27 +366,6 @@
       meth: "($temp = ${ @variable.source })${ @variable.last }"
     "$@prefix${meth}.apply($obj, ${ @compile_splat_arguments(o) })"

-  # Converts arbitrary number of arguments, mixed with splats, to
-  # a proper array to pass to an `.apply()` call
-  compile_splat_arguments: (o) ->
-    args: []
-    i: 0
-    for arg in @args
-      code: arg.compile o
-      if not (arg instanceof SplatNode)
-        prev: args[i - 1]
-        if i is 1 and prev.substr(0, 1) is '[' and prev.substr(prev.length - 1, 1) is ']'
-          args[i - 1]: "${prev.substr(0, prev.length - 1)}, $code]"
-          continue
-        else if i > 1 and prev.substr(0, 9) is '.concat([' and prev.substr(prev.length - 2, 2) is '])'
-          args[i - 1]: "${prev.substr(0, prev.length - 2)}, $code])"
-          continue
-        else
-          code: "[$code]"
-      args.push(if i is 0 then code else ".concat($code)")
-      i += 1
-    args.join('')
-

 #### CurryNode

@@ -398,6 +378,7 @@

   constructor: (meth, args) ->
     @children:  flatten [@meth: meth, @context: args[0], @args: (args.slice(1) or [])]
+    @compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args

   arguments: (o) ->
     for arg in @args
@@ -567,17 +548,21 @@

   constructor: (objects) ->
     @children: @objects: objects or []
-
+    @compile_splat_literal: SplatNode.compile_mixed_array <- @, @objects
+
   compile_node: (o) ->
     o.indent: @idt(1)
-    objects: for obj, i in @objects
+    objects: []
+    for obj, i in @objects
       code: obj.compile(o)
-      if obj instanceof CommentNode
-        "\n$code\n$o.indent"
+      if obj instanceof SplatNode
+        return @compile_splat_literal(@objects, o)
+      else if obj instanceof CommentNode
+        objects.push "\n$code\n$o.indent"
       else if i is @objects.length - 1
-        code
+        objects.push code
       else
-        "$code, "
+        objects.push "$code, "
     objects: objects.join('')
     ending: if objects.indexOf('\n') >= 0 then "\n$@tab]" else ']'
     "[$objects$ending"
@@ -814,6 +799,27 @@
   # from the right-hand-side's corresponding array.
   compile_value: (o, name, index) ->
     "Array.prototype.slice.call($name, $index)"
+
+# Utility function that converts arbitrary number of elements, mixed with
+# splats, to a proper array
+SplatNode.compile_mixed_array: (list, o) ->
+  args: []
+  i: 0
+  for arg in list
+    code: arg.compile o
+    if not (arg instanceof SplatNode)
+      prev: args[i - 1]
+      if i is 1 and prev.substr(0, 1) is '[' and prev.substr(prev.length - 1, 1) is ']'
+        args[i - 1]: "${prev.substr(0, prev.length - 1)}, $code]"
+        continue
+      else if i > 1 and prev.substr(0, 9) is '.concat([' and prev.substr(prev.length - 2, 2) is '])'
+        args[i - 1]: "${prev.substr(0, prev.length - 2)}, $code])"
+        continue
+      else
+        code: "[$code]"
+    args.push(if i is 0 then code else ".concat($code)")
+    i += 1
+  args.join('')

 #### WhileNode


coco 7222551: crushed __bind

coco 7222551: crushed __bind

--- nodes.coffee
+++ nodes.coffee
@@ -1598,9 +1598,7 @@

   # Create a function bound to the current value of "this".
   bind: '''
-    function(func, context) {
-      return function() { return func.apply(context, arguments); };
-    }
+    function(fn, me){ return function(){ return fn.apply(me, arguments); }; }
   '''

   # Discover if an item is in an array.


renamed

renamed

--- assets/js/collection/stub-collection.coffee
+++ assets/js/collection/stub-collection.coffee
@@ -2,8 +2,8 @@
 define [
   'lodash'
   'vo/stub-vo'
-], (_, stub) ->
+], (_, vo) ->
   (dfd, data) ->
-    collection = _.map data, stub
+    collection = _.map data, vo

     dfd.resolve collection


Search for %!TEX root if no bibfile found

also using  addbibresource addglobabib besides bibliography tag

--- lib/cite-view.coffee
+++ lib/cite-view.coffee
@@ -2,6 +2,7 @@
 Citation = require './citation'
 FindLabels = require './find-labels'
 fs = require 'fs-plus'
+pathModule = require 'path'

 module.exports =
 class CiteView extends SelectListView
@@ -44,13 +45,41 @@

   getCitations: ->
     cites = []
-    bibRex = /\\bibliography{([^}]+)}/g
-    while (match = bibRex.exec(@editor.getText()))
+    bibFiles = @getBibFiles()
+    for bibFile in bibFiles
+      cites = cites.concat(@getCitationsFromPath(bibFile))
+    cites
+
+  getBibFiles: ->
+    basePath = @editor.getPath()
+    bibFiles = @getBibFileFromText(@editor.getText())
+    if bibFiles == null or bibFiles.length == 0
+      texRootRex = /%!TEX root = (.+)/g
+      while(match = texRootRex.exec(@editor.getText()))
+        absolutFilePath = FindLabels.getAbsolutePath(@editor.getPath(), match[1])
+        basePath = pathModule.dirname(absolutFilePath)
+        try
+          text = fs.readFileSync(absolutFilePath).toString()
+          bibFiles = @getBibFileFromText(text) #todo append basePath to each BibFiles in
+          if bibFiles != null and bibFiles.length != 0
+            break
+        catch error
+          atom.notifications.addError('could not load content '+ match[1], { dismissable: true })
+          console.log(error)
+    result = []
+    basePath = basePath + pathModule.sep
+    for bfpath in bibFiles
+      result = result.concat(FindLabels.getAbsolutePath(basePath, bfpath) )
+    result
+
+  getBibFileFromText: (text) ->
+    bibFiles = []
+    bibRex = /\\(?:bibliography|addbibresource|addglobalbib){([^}]+)}/g
+    while( match = bibRex.exec(text) ) #try editor text for bibfile
       if not /\.bib$/.test(match[1])
         match[1] += ".bib"
-      path = FindLabels.getAbsolutePath(@editor.getPath(), match[1])
-      cites = cites.concat(@getCitationsFromPath(path))
-    cites
+      bibFiles = bibFiles.concat(match[1])
+    bibFiles

   getCitationsFromPath: (path) ->
     cites = []


check for object, not string

check for object, not string

otherwise we fail when a number is passed.

--- ccss.coffee
+++ ccss.coffee
@@ -25,10 +25,10 @@
     css += selector + ' {\n'

     for property, value of declarations
-      if typeof value is 'string'
+      if typeof value is 'object'
+        children["#{selector} #{property}"] = value
+      else
         css += "  #{property}: #{value};\n"
-      else
-        children["#{selector} #{property}"] = value

     css += '}\n'


fix addLanguage bug

fix addLanguage bug

--- both/methods/store/language.coffee
+++ both/methods/store/language.coffee
@@ -9,7 +9,7 @@

 		existing = false
 		project = Projects.findOne projectId, fields: 'store.items': 1
-		for item in project.store.items when item? && item.short == short
+		for item in project.store.items when item? && item.short == short && item.languages?
 			for lang in item.languages when lang? && lang.short == language
 				existing = true


Code annotations and such.

Code annotations and such.

--- lib/js2coffee.coffee
+++ lib/js2coffee.coffee
@@ -46,6 +46,7 @@
 #
 # For instance, for a `function` node, it calls `Builders.function(node)`.
 # It defaults to `Builders.other` if it can't find a function for it.
+
 build = (node, opts={}) ->
   transform node

@@ -59,12 +60,14 @@
 # `re()`
 # Works like `build()`, except it explicitly states which function should
 # handle it. (essentially, *re*routing it to another builder)
+
 re = (type, str, args...) ->
   Builders[type].apply str, args

 # `body()`
 # Works like `build()`, and is used for code blocks. It cleans up the returned
 # code block by removing any extraneous spaces and such.
+
 body = (item, opts={}) ->
   str = build(item, opts)
   str = blockTrim(str)
@@ -72,6 +75,16 @@

   if str.length > 0 then str else ""

+# `transform()`
+# Perform a transformation on the node, if a transformation function is
+# available.
+
+transform = (node, args...) ->
+  type = node.typeName()
+  fn   = Transformers[type]
+
+  fn.apply(node, args)  if fn
+
 # ## The builders
 #
 # Each of these functions are apply'd to a Node, and is expected to return
@@ -82,6 +95,7 @@
 Builders =
   # `script`
   # This is the main entry point.
+
   'script': (opts={}) ->
     c = new Code

@@ -120,6 +134,7 @@

   # `id_param`
   # Function parameters. Belongs to `list`.
+
   'id_param': ->
     if @toString() in ['undefined']
       "#{@}_"
@@ -143,16 +158,16 @@
     # **Caveat:**
     # Some statements can be blank as some people are silly enough to use `;;`
     # sometimes. They should be ignored.
+
     unless @expression?
       ""

-    else if @expression.typeName() == 'object_init'  # TODO: remove this
+    else if @expression.typeName() == 'object_init'
       src = re('object_init', @expression)
       if @parenthesized
         src
       else
-        src = unshift(blockTrim(src))
-        "#{src}\n"
+        "#{unshift(blockTrim(src))}\n"

     else
       build(@expression) + "\n"
@@ -255,7 +270,7 @@

   # `regexp`
   # Regular expressions.
-  #
+
   'regexp': ->
     m     = @value.toString().match(/^\/(.*)\/([a-z]?)/)
     value = m[1]
@@ -370,6 +385,7 @@
   # `?` (ternary operator)
   # For `a ? b : c`. Note that these will always be parenthesized, as (I
   # believe) the order of operations in JS is different in CS.
+
   '?': ->
     "(if #{build @left()} then #{build @children[1]} else #{build @children[2]})"

@@ -534,12 +550,6 @@

 Builders.block = Builders.script

-transform = (node, args...) ->
-  type = node.typeName()
-  fn   = Transformers[type]
-
-  fn.apply(node, args)  if fn
-
 # ## AST manipulation
 # Manipulation of the abstract syntax tree happens here. All these are done on
 # the `build()` step, done just before a node is passed onto `Builders`.


Update config validation to use remote and local

Should fix #64

--- lib/php-debug.coffee
+++ lib/php-debug.coffee
@@ -43,9 +43,9 @@
       items:
         type: 'object'
         properties:
-          from:
+          remote:
             type: 'string'
-          to:
+          local:
             type: 'string'
     ServerPort:
       type: 'integer'


syntax colorize the word 'Function' in the callstack

--- lib/rendering.coffee
+++ lib/rendering.coffee
@@ -101,7 +101,7 @@

         line = """

-            a Function #{dfn}#{frame.address}
+            a Function #{dfn}#{frame.address}

         """
         if frame.context


Fixed spec

Fixed spec

--- lib/spark-ide.coffee
+++ lib/spark-ide.coffee
@@ -292,6 +292,7 @@

   # Show cloud variables and functions panel
   showCloudVariablesAndFunctions: -> @coreRequired =>
+    @cloudVariablesAndFunctionsView = null
     @openPane 'cloud-variables-and-functions'

   # Flash core via the cloud
@@ -337,4 +338,5 @@

   # Show serial monitor panel
   showSerialMonitor: ->
+    @serialMonitorView = null
     @openPane 'serial-monitor'


Focus tree-view if name of active file is clicked

Fixes https://github.com/atom/tree-view/issues/740

--- lib/tree-view.coffee
+++ lib/tree-view.coffee
@@ -205,13 +205,17 @@
       when 1
         @selectEntry(entry)
         if entry instanceof FileView
-          @openedItem = atom.workspace.open(entry.getPath(), pending: true)
+          if entry.getPath() is atom.workspace.getActivePaneItem()?.getPath?()
+            @focus()
+          else
+            @openedItem = atom.workspace.open(entry.getPath(), pending: true)
         else if entry instanceof DirectoryView
           entry.toggleExpansion(isRecursive)
       when 2
         if entry instanceof FileView
           @openedItem.then((item) -> item.terminatePendingState?())
-          @unfocus()
+          unless entry.getPath() is atom.workspace.getActivePaneItem()?.getPath?()
+            @unfocus()
         else if entry instanceof DirectoryView
           entry.toggleExpansion(isRecursive)


Fix typo in callback for file:// resource error

--- lib/zombie/resources.coffee
+++ lib/zombie/resources.coffee
@@ -234,7 +234,7 @@
         FS.readFile Path.normalize(url.pathname), (error, data)=>
           # Fallback with error -> callback
           if error
-            callback err
+            callback error
           else
             # Turn body from string into a String, so we can add property getters.
             resource.response = new HTTPResponse(url, 200, {}, String(data))


simplyfied colorize

simplyfied colorize

--- src/coffee/choropleth.coffee
+++ src/coffee/choropleth.coffee
@@ -41,7 +41,7 @@
         # Set the coloring function.
         colorize = d3.scale.quantize()
             .domain([min, max])
-            .range(d3.range(geomap.properties.colors.length).map((i)-> geomap.properties.colors[i]))
+            .range(geomap.properties.colors)

         iso_val = (iso3)->
             if data_by_iso[iso3] then geomap.properties.format(data_by_iso[iso3]) else 'No data'


Remove collection generator from scaffold.

--- src/commands/scaffold.coffee
+++ src/commands/scaffold.coffee
@@ -81,7 +81,6 @@

     scaffold: (name, pluralName) ->
       generator('model', name, pluralName).concat(
-        generator('collection', name, pluralName),
         generator('view', name, pluralName),
       )

@@ -141,7 +140,6 @@
     scaffold: (name, pluralName) ->
       generator('controller', name, pluralName).concat(
         generator('model', name, pluralName),
-        generator('collection', name, pluralName),
         generator('view', name, pluralName),
         generator('collectionView', name, pluralName)
       )


Implement replaceSKU method

Implement replaceSKU method

--- src/checkout.coffee
+++ src/checkout.coffee
@@ -436,6 +436,18 @@

   getLogoutURL: @::getChangeToAnonymousUserURL

+  # Replace current SKU for new SKU
+  replaceSKU: (items, noSplitItem = true, expectedOrderFormSections = @_allOrderFormSections) =>
+    @_updateOrderForm({
+      url: @_getAddToCartURL()
+      type: 'PATCH'
+      data: JSON.stringify({
+        "orderItems": items,
+        "expectedOrderFormSections": expectedOrderFormSections,
+        "noSplitItem": noSplitItem,
+      })
+    })
+
   # URL BUILDERS

   _getOrderFormId: =>


ヘルプメッセージの誤爆するので修正

ヘルプメッセージの誤爆するので修正

--- scripts/help-message.coffee
+++ scripts/help-message.coffee
@@ -5,7 +5,7 @@

 module.exports = (robot) ->
-  robot.respond /(-help|h|-h|ヘルプ|詳細)/i, (msg) ->
+  robot.respond /(-help|-h|ヘルプ|詳細)/i, (msg) ->
     text = """
      バスの混み具合を確認する
      　chocobot bus or バス


Replace atom.syntax with atom.grammars in spec

--- spec/operators-spec.coffee
+++ spec/operators-spec.coffee
@@ -1061,7 +1061,7 @@

     describe "when used in a scope that supports auto-indent", ->
       beforeEach ->
-        jsGrammar = atom.syntax.grammarForScopeName('source.js')
+        jsGrammar = atom.grammars.grammarForScopeName('source.js')
         editor.setGrammar(jsGrammar)

       afterEach ->


janitoring more

janitoring more

--- scripts/pagerv2_hook.coffee
+++ scripts/pagerv2_hook.coffee
@@ -36,8 +36,6 @@
           .then (messages) ->
             for message in messages
               robot.messageRoom pagerAnnounceRoom, message
-          .catch (e) ->
-            robot.logger.warning e
           res.status(200).end()
         else
           robot.logger.warning '[pagerv2] Invalid hook payload ' +


Fixing a typo

Fixing a typo

--- scripts/xcode-server.coffee
+++ scripts/xcode-server.coffee
@@ -28,7 +28,7 @@
     if success
       robot.messageRoom '#publishmobileautomati', 'Built ' + app + ' ' + version + '-' + number + ' successfully. Currently available on Crashlytics for download.'
     else
-      robot.messageRoom '#publishmobileautomati', 'FAILED while building' + app + ' with error ' + error
+      robot.messageRoom '#publishmobileautomati', 'FAILED while building ' + app + ' with error ' + error

     res.writeHead 204, { 'Content-Length': 0}


cooldown finilazation

cooldown finilazation

--- src/cooldown.coffee
+++ src/cooldown.coffee
@@ -17,8 +17,7 @@
 # Shoot Timeout
 player = GameObject()

-player.cooldown "shootTimer",
-  target: 100
+player.cooldown "shootTimer"
 </pre></code>

 @name Cooldown


cooldown finilazation

cooldown finilazation

--- src/cooldown.coffee
+++ src/cooldown.coffee
@@ -10,6 +10,7 @@

   cooldown: (name, options={target: 0, approachBy: 1, value: null}) ->
     options.target ||= 0
+    u

     unless I.cooldowns[name]
       I.cooldowns[name] = options


Remove caching stuff

Remove caching stuff

--- src/flowdock.coffee
+++ src/flowdock.coffee
@@ -14,17 +14,7 @@
 class Session extends process.EventEmitter
   constructor: (@email, @password) ->
     @auth = 'Basic ' + new Buffer(@email + ':' + @password).toString('base64')
-    @_flows = []
-    @_users = []
-
   flows: (callback) ->
-    @fetchFlows (flows) =>
-      for flow in flows
-        @_users.push user for user in flow.users when !@_users.some((u) -> u.id == user.id)
-        @_flows.push flow if !@_flows.some((f) -> f.id == flow.id)
-      callback(@_flows)
-
-  fetchFlows: (callback) ->
     options =
       host: FLOWDOCK_API_URL.hostname
       port: FLOWDOCK_API_URL.port


Verify user roles before greeting-changing.

--- src/greeting.coffee
+++ src/greeting.coffee
@@ -5,7 +5,7 @@
 #   None
 #
 # Configuration:
-#   None
+#   HUBOT_GREETING_FFA - If set, any user can set any other user's greeting.
 #
 # Commands:
 #   hubot greet <name> - Test out <name>'s current greeting; can be "me" or "yourself".
@@ -16,6 +16,10 @@
 #
 # Author:
 #   smashwilson
+
+freeForAll = process.env.HUBOT_GREETING_FFA?
+
+GREETING_ROLE = 'greeting czar'

 module.exports = (robot) ->

@@ -48,8 +52,19 @@
     # Set as some user, whether in the room or not
     return match

+  verifyPermission = (msg, target) ->
+    return true if freeForAll or msg.message.user.name is target
+    user = robot.brain.userForName target
+    if user? and user.roles? and GREETING_ROLE in user.roles
+      true
+    else
+      msg.reply "I can't do that, you're not a #{GREETING_ROLE}!"
+      false
+
   robot.respond /greet (\S+) with (.+)/i, (msg) ->
     target = chooseTarget msg, msg.match[1]
+    return unless verifyPermission msg, target
+
     greeting = msg.match[2]
     withGreetings target, (greetings) ->
       greetings.push greeting
@@ -69,6 +84,8 @@

   robot.respond /don\'t greet (\S+) with (.+)/i, (msg) ->
     target = chooseTarget msg, msg.match[1]
+    return unless verifyPermission msg, target
+
     greeting = msg.match[2]
     found = false
     withGreetings target, (greetings) ->
@@ -88,6 +105,8 @@

   robot.respond /forget (\S+)('s)? greetings$/i, (msg) ->
     target = chooseTarget msg, msg.match[1]
+    return unless verifyPermission msg, target
+
     withGreetings target, (greetings) ->
       msg.reply "Forgetting #{greetings.length} greetings."
       []


Stepped first date for okSubmits

Stepped first date for okSubmits

--- server/api/dashboard.coffee
+++ server/api/dashboard.coffee
@@ -56,7 +56,7 @@
 export default dashboard = () ->
     queries =
         # remember that months start from 0
-        ok: {ok: 1, lastSubmitTime: {$gt: new Date(2017, 8, 6)}},
+        ok: {ok: 1, lastSubmitTime: {$gt: new Date(2017, 8, 10)}},
         wa: {solved: 0, ok: 0, ignored: 0, attempts: {$gt: 0}},
         ig: {ignored: 1},
         ac: {solved: 1}


default to current view context

default to current view context

--- manager/app/assets/javascripts/stark/view.js.coffee
+++ manager/app/assets/javascripts/stark/view.js.coffee
@@ -186,6 +186,8 @@
   partial_html: (tpl, data) ->
     if _.isString(tpl)
       tpl = new Template(@jst(tpl))
+
+    data ||= @
     tpl.render(data)

   create_partial: (clazz, data) ->


Defer request and glob requires

Defer request and glob requires

These were occurring at Atom startup when they aren't needed until
the settings view is opened.

--- lib/atom-io-client.coffee
+++ lib/atom-io-client.coffee
@@ -1,8 +1,8 @@
 fs = require 'fs-plus'
 path = require 'path'

-glob = require 'glob'
-request = require 'request'
+glob = null    # defer until used
+request = null # defer until used

 module.exports =
 class AtomIoClient
@@ -65,6 +65,7 @@
         callback(error, null)

   request: (path, callback) ->
+    request ?= require 'request'
     request "#{@baseURL}#{path}", (err, res, body) =>
       try
         data = JSON.parse(body)
@@ -115,6 +116,7 @@
     path.join @getCachePath(), "#{login}-#{Date.now()}"

   cachedAvatar: (login, callback) ->
+    glob ?= require 'glob'
     glob @avatarGlob(login), (err, files) =>
       files.sort().reverse()
       for imagePath in files
@@ -134,6 +136,7 @@
       writeStream.on 'finish', -> callback(null, imagePath)
       writeStream.on 'error', (error) -> callback(error)

+      request ?= require 'request'
       readStream = request("https://github.com/#{login}.png")
       readStream.on 'error', (error) -> callback(error)
       readStream.pipe(writeStream)


Use @editor.command to bind to commands

Use @editor.command to bind to commands

--- lib/bookmarks-view.coffee
+++ lib/bookmarks-view.coffee
@@ -13,9 +13,9 @@
     @gutter = @editor.gutter
     @editor.on 'editor:display-updated', @renderBookmarkMarkers

-    rootView.command 'bookmarks:toggle-bookmark', '.editor', @toggleBookmark
-    rootView.command 'bookmarks:jump-to-next-bookmark', '.editor', @jumpToNextBookmark
-    rootView.command 'bookmarks:jump-to-previous-bookmark', '.editor', @jumpToPreviousBookmark
+    @editor.command 'bookmarks:toggle-bookmark', @toggleBookmark
+    @editor.command 'bookmarks:jump-to-next-bookmark', @jumpToNextBookmark
+    @editor.command 'bookmarks:jump-to-previous-bookmark', @jumpToPreviousBookmark

   toggleBookmark: =>
     cursors = @editor.getCursors()


pause the stream of ops, not the download

the download is buffered in the lineStream so a lot comes out even
after pausing the S3 download.

--- app/coffee/MongoAWS.coffee
+++ app/coffee/MongoAWS.coffee
@@ -64,20 +64,21 @@
 		ops = []
 		sz = 0

-		download
+		inputStream = download
 			.on 'open', (obj) ->
 				return 1
 			.on 'error', (err) ->
 				callback(err)
 			.pipe lineStream
-			.on 'data', (line) ->
+
+		inputStream.on 'data', (line) ->
 				if line.length > 2
 					ops.push(JSON.parse(line))
 					sz += line.length
 				if ops.length >= MongoAWS.MAX_COUNT || sz >= MongoAWS.MAX_SIZE
-					download.pause()
+					inputStream.pause()
 					MongoAWS.handleBulk ops.slice(0), sz, () ->
-						download.resume()
+						inputStream.resume()
 					ops.splice(0,ops.length)
 					sz = 0
 			.on 'end', () ->


Added autofoldGrammars and autofoldIgnoreGrammars

Two new configuration options have been added that allow you to configure the autofold functionality further:

1. `autofoldGrammars` allows you to specify grammar names you *want* to autofold.
2. `autofoldIgnoreGrammars` allows you to specify grammar names you *do not want* to autofold.

--- lib/fold-functions.coffee
+++ lib/fold-functions.coffee
@@ -12,6 +12,12 @@
     shortfileCutoff:
       type: 'integer'
       default: 42
+    autofoldGrammars:
+      type: 'array'
+      default: []
+    autofoldIgnoreGrammars:
+      type: 'array'
+      default: ['SQL', 'CSV', 'JSON', 'CSON', 'Plain Text']

   activate: (state) ->
     # Events subscribed to in atom's system can be easily cleaned up with a
@@ -31,10 +37,20 @@
     if atom.config.get('fold-functions.autofold')
       atom.workspace.observeTextEditors (editor) =>
         editor.displayBuffer.tokenizedBuffer.onDidTokenize =>
+          autofoldGrammars = atom.config.get('fold-functions.autofoldGrammars')
+          grammar = editor.getGrammar()
+          if autofoldGrammars.length > 0 and grammar.name not in autofoldGrammars
+            console.log('autofold grammar not whitelisted', grammar.name)
+            return
+
+          autofoldIgnoreGrammars = atom.config.get('fold-functions.autofoldIgnoreGrammars')
+          if autofoldIgnoreGrammars.length > 0 and grammar.name in autofoldIgnoreGrammars
+            console.log('autofold ignored grammar', grammar.name)
+            return
+
           if shortfileCutoff = atom.config.get('fold-functions.shortfileCutoff')
             # make sure the file is longer than the cutoff before folding
             if shortfileCutoff > 0 and editor.getLineCount() >= shortfileCutoff
-              console.log('autofold')
               @fold('autofold', editor)

   deactivate: ->


bongo: exit the process on error

bongo: exit the process on error

--- node_modules_koding/bongo/lib/bongo.coffee
+++ node_modules_koding/bongo/lib/bongo.coffee
@@ -66,7 +66,7 @@

   @throwIt = (it) ->
     console.error it  if it?
-    # process.kill process.pid, 'SIGTERM'
+    process.exit 1

   constructor:(options)->
     {@mq, @mongo, @resourceName, @root, @fetchClient, @verbose, models, @precompiledApi} = options


Expires attribute are now only set from the cookie.expires

--- lib/mongoose-store.coffee
+++ lib/mongoose-store.coffee
@@ -14,7 +14,8 @@

       @SessionModel.findOne query, (err, data) =>
         if err or not data then return callback err
-        if new Date().getTime() > data.session.cookie.maxAge
+        cookie = data.session.cookie
+        if cookie.expires? and new Date() > cookie.expires
           return @destroy data.sid, callback
         callback null, data.session

@@ -23,14 +24,11 @@
       unless session
         @destroy sid, callback

+      data = sid: sid, session: session
+
       if cookie = session.cookie
-        expires = cookie.expires if cookie.expires
-        expires = new Date(cookie.maxAge) if cookie.maxAge
-
-      data =
-        sid: sid
-        session: session
-        expires: expires
+        data.expires = cookie._expires if cookie._expires
+        data.expires = cookie.expires if cookie.expires

       if @options.ttl then data.createdAt = new Date()


Copy allowedHosts and destroy browser on every render.

--- lib/otter/renderer.coffee
+++ lib/otter/renderer.coffee
@@ -8,14 +8,17 @@
     headers:
       "X-Otter-No-Render": "true"
   browser.resources.addHandler (request, next) ->
-    if not options.allowedHosts
-      options.allowedHosts = []
+    allowedHosts = []
+    if options.allowedHosts
+      allowedHosts = allowedHosts.concat(options.allowedHosts)
     # Always allow local requests
-    options.allowedHosts.push(URL.parse(options.baseUrl).host)
+    allowedHosts.push(URL.parse(options.baseUrl).host)

     parsedUrl = URL.parse(request.url)
-    if parsedUrl.host not in options.allowedHosts
-      next(new Error("Not loading #{parsedUrl.href}: #{parsedUrl.host} not in allowedHosts"))
+    if parsedUrl.host not in allowedHosts
+      err = new Error("Not loading #{parsedUrl.href}: #{parsedUrl.host} not in allowedHosts")
+      console.error(err)
+      next(err)
     else
       next()

@@ -30,5 +33,6 @@
       if browser.error
         console.log browser.errors
       res.send browser.document.outerHTML
+      browser.destroy()


config wording

config wording

--- lib/package/config.coffee
+++ lib/package/config.coffee
@@ -19,7 +19,8 @@
   errorsToConsole:
     type: 'boolean'
     default: false
-    description: 'Show errors in console. If false use atom\'s nofitication UI'
+    description: 'When evaluating a script, show errors in the console instead
+                  of using a notification.'
     order: 4
   enableMenu:
     type: 'boolean'


markdown now proxies images and target_blanks links that arent usernames

--- client/Framework/core/utils.coffee
+++ client/Framework/core/utils.coffee
@@ -109,9 +109,25 @@
         else
           text

-    text = Encoder.htmlDecode text
-
-    text = marked text
+    text = marked Encoder.htmlDecode text
+
+    sanitizeText = $(text)
+
+    # Proxify images
+
+    proxify = (str, p1, offset, s)=>
+      @proxifyUrl str
+
+    sanitizeText.find("img").each (i,element) =>
+      $(element).attr("src", $(element).attr("src")?.replace(/.*/, proxify))
+
+    # Give all outbound links a target blank
+    sanitizeText.find("a").each (i,element) =>
+      unless /^(#!)/.test $(element).attr("href")
+        $(element).attr("target", "_blank")
+
+    text = $("<div />").append(sanitizeText.clone()).remove().html() # workaround for .html()
+

   applyLineBreaks: (text)->
     return null unless text


terminal: scroll down terminal if shown pane is IDE [#77684044]

--- client/Terminal/webtermview.coffee
+++ client/Terminal/webtermview.coffee
@@ -327,7 +327,7 @@

   mainTabPaneShown: (pane) ->

-    return  unless pane.getElement().contains @getElement()
+    return  unless pane.hasClass('ide') and pane.getElement().contains @getElement()

     el = @container.getElement()
     el.scrollTop = el.scrollHeight


Fixing block component lookup after minification

--- src/js/Block.coffee
+++ src/js/Block.coffee
@@ -118,12 +118,12 @@

   # All the supported components a block can be composed of
   @Components:
-    top:
+    'top':
       ['crossing',
        'crossing-hole',
        'curve',
        'straight']
-    middle:
+    'middle':
       ['crossing',
        'curve',
        'straight',
@@ -132,7 +132,7 @@
        'drop-low',
        'exchange-alt',
        'exchange']
-    low:
+    'low':
       ['crossing',
        'curve',
        'straight']


Move title solver to update_constraints

Move title solver to update_constraints

Not adding any tests, because this will be ripped out soon.

--- bokehjs/src/coffee/models/plots/plot.coffee
+++ bokehjs/src/coffee/models/plots/plot.coffee
@@ -461,20 +461,15 @@
     if @tm_view?
       @tm_view.render()

-    ctx = @canvas_view.ctx
-
     for k, v of @renderer_views
       if not @range_update_timestamp? or v.set_data_timestamp > @range_update_timestamp
         @update_dataranges()
         break

+    ctx = @canvas_view.ctx
     title = @mget('title')
-
     if title
-      @visuals.title_text.set_value(@canvas_view.ctx)
-      th = ctx.measureText(@mget('title')).ascent + @model.get('title_standoff')
-      if th != @title_panel.get('height')
-        @title_panel.set_var('height', th)
+      @visuals.title_text.set_value(ctx)

     @update_constraints()

@@ -561,6 +556,13 @@
     for model_id, view of @renderer_views
       if view.update_constraints?
         view.update_constraints()
+
+    ctx = @canvas_view.ctx
+    title = @mget('title')
+    if title
+      th = ctx.measureText(@mget('title')).ascent + @model.get('title_standoff')
+      if th != @title_panel.get('height')
+        s.suggest_value(@title_panel._height, th)

     s.update_variables(false)


Simplify definition of Plot.plot_canvas attribute

--- bokehjs/src/coffee/models/plots/plot.coffee
+++ bokehjs/src/coffee/models/plots/plot.coffee
@@ -119,7 +119,7 @@
     if not @height?
       @height = @plot_height

-  Object.defineProperty(this.prototype, "plot_canvas", { get: () -> @_plot_canvas })
+  @getter("plot_canvas", () -> @_plot_canvas)

   _doc_attached: () ->
     # Setup side renderers


Fixed non-alphanumeric character input

Fixed non-alphanumeric character input

--- private/coffee/index.coffee
+++ private/coffee/index.coffee
@@ -47,16 +47,13 @@
     # Listen for keyboard events
     $('body').keydown (e) ->
       # Check backspace
-      if e.which == 8
-        backspace = true
-      else
-        char = String.fromCharCode(e.which).toLowerCase()
-      if game
-        if backspace
-          game.removeChar()
-          return false
-        else if game.isValidChar(char)
-          game.addChar(char)
+      if game and e.which == 8
+        game.removeChar()
+        return false
+    $('body').keypress (e) ->
+      char = String.fromCharCode(e.which).toLowerCase()
+      if game and game.isValidChar(char)
+        game.addChar(char)

   # Starts a new game
@@ -79,7 +76,7 @@
           $name = $('<h3>').addClass('name').text(people.firstName)
           $person = $('<li>').addClass('person ' + type).append($picture, $name)
           $('ul.people').append($person)
-
+
       addList results.incorrect, 'incorrect'
       addList results.correct, 'correct'


test: teams: removed login step from tests

since it's automatically logs you in now

--- client/test/lib/teams/teams.coffee
+++ client/test/lib/teams/teams.coffee
@@ -23,7 +23,7 @@
     teamsHelpers.fillUsernamePasswordForm(browser, user)
     # teamsHelpers.setupStackPage(browser)
     # teamsHelpers.congratulationsPage(browser)
-    teamsHelpers.loginToTeam(browser, user)
+    # teamsHelpers.loginToTeam(browser, user)

     browser.end()


Disable Tween on XML pages

Disable Tween on XML pages

--- content_scripts/hud.coffee
+++ content_scripts/hud.coffee
@@ -57,6 +57,12 @@

   constructor: (@cssSelector, insertionPoint = document.documentElement) ->
     @styleElement = document.createElement "style"
+
+    unless @styleElement.style
+      # We're in an XML document, so we shouldn't inject any elements. See the comment in UIComponent.
+      Tween::fade = Tween::stop = Tween::updateStyle = ->
+      return
+
     @styleElement.type = "text/css"
     @styleElement.innerHTML = ""
     insertionPoint.appendChild @styleElement


Save all pane items before window is closed

--- lib/autosave.coffee
+++ lib/autosave.coffee
@@ -1,3 +1,5 @@
+{$} = require 'atom'
+
 module.exports =
   configDefaults:
     enabled: false
@@ -12,6 +14,10 @@
     rootView.on 'pane:before-item-destroyed', (event, paneItem) =>
       @autosave(paneItem)

+    $(window).preempt 'beforeunload', =>
+      for pane in rootView.getPanes()
+        @autosave(paneItem) for paneItem in pane.getItems()
+
   autosave: (paneItem) ->
     paneItem?.save?() if config.get('autosave.enabled')


turns out string interpolation has a rather large cost given all the debug spew.  delaying the interpolation by wrapping it in a closure that we pass to debug.log (which already has support for function args) results in a nice compiler speedup.

--- lib/compiler.coffee
+++ lib/compiler.coffee
@@ -377,7 +377,7 @@
                         else # prop.type is syntax.Literal
                                 pname = prop.value

-                        debug.log "createPropertyStore #{obj}[#{pname}]"
+                        debug.log -> "createPropertyStore #{obj}[#{pname}]"

                         c = irbuilder.createGlobalStringPtr pname, "strconst"
                         @createCall @ejs_runtime.object_setprop_utf8, [obj, c, rhs], "propstore_#{pname}"
@@ -827,14 +827,15 @@
                 ir_func = n.ir_func
                 ir_args = n.ir_func.args
                 debug.log ""
-                debug.log "ir_func = #{ir_func}"
-
-                debug.log "param #{param.llvm_type} #{param.name}" for param in n.params
+                #debug.log -> "ir_func = #{ir_func}"
+
+                #debug.log -> "param #{param.llvm_type} #{param.name}" for param in n.params

                 @currentFunction = ir_func

                 # Create a new basic block to start insertion into.
                 entry_bb = new llvm.BasicBlock "entry", ir_func
+
                 irbuilder.setInsertPoint entry_bb

                 new_scope = {}
@@ -869,12 +870,12 @@
                                 console.warn JSON.stringify param
                                 throw "we don't handle destructured args at the moment."

-                debug.log "alloca #{alloca}" for alloca in allocas
+                debug.log -> "alloca #{alloca}" for alloca in allocas

                 # now store the arguments (use .. to include our args array) onto the stack
                 for i in [0..BUILTIN_PARAMS.length]
                         store = irbuilder.createStore ir_args[i], allocas[i]
-                        debug.log "store #{store} *builtin"
+                        debug.log -> "store #{store} *builtin"

                 # initialize all our named parameters to undefined
                 args_load = irbuilder.createLoad args_alloca, "args_load"
@@ -902,17 +903,17 @@

                                 irbuilder.setInsertPoint then_bb
                                 arg_ptr = irbuilder.createGetElementPointer args_load, [(int32Constant i-BUILTIN_PARAMS.length)], "arg#{i-BUILTIN_PARAMS.length}_ptr"
-                                debug.log "arg_ptr = #{arg_ptr}"
+                                debug.log -> "arg_ptr = #{arg_ptr}"
                                 arg = irbuilder.createLoad arg_ptr, "arg#{i-BUILTIN_PARAMS.length-1}_load"
                                 store = irbuilder.createStore arg, allocas[i+1]
-                                debug.log "store #{store}"
+                                debug.log -> "store #{store}"
                                 irbuilder.createBr merge_bb

                                 irbuilder.setInsertPoint else_bb
                                 irbuilder.createBr merge_bb

                                 irbuilder.setInsertPoint merge_bb
-
+
                 @iifeStack = []

                 @finallyStack = []
@@ -935,7 +936,7 @@
                 return ir_func

         visitUnaryExpression: (n) ->
-                debug.log "operator = '#{n.operator}'"
+                debug.log -> "operator = '#{n.operator}'"

                 builtin = "unop#{n.operator}"
                 callee = @ejs_runtime[builtin]
@@ -963,7 +964,7 @@
                 rv

         visitBinaryExpression: (n) ->
-                debug.log "operator = '#{n.operator}'"
+                debug.log -> "operator = '#{n.operator}'"
                 builtin = "binop#{n.operator}"
                 callee = @ejs_runtime[builtin]
                 if not callee
@@ -991,7 +992,7 @@
                 call

         visitLogicalExpression: (n) ->
-                debug.log "operator = '#{n.operator}'"
+                debug.log -> "operator = '#{n.operator}'"
                 result = @createAlloca @currentFunction, EjsValueType, "result_#{n.operator}"

                 left_visited = @visit n.left
@@ -1080,9 +1081,9 @@
                 argv

         visitCallExpression: (n) ->
-                debug.log "visitCall #{JSON.stringify n}"
-                debug.log "          arguments length = #{n.arguments.length}"
-                debug.log "          arguments[#{i}] =  #{JSON.stringify n.arguments[i]}" for i in [0...n.arguments.length]
+                debug.log -> "visitCall #{JSON.stringify n}"
+                debug.log -> "          arguments length = #{n.arguments.length}"
+                debug.log -> "          arguments[#{i}] =  #{JSON.stringify n.arguments[i]}" for i in [0...n.arguments.length]

                 intrinsicHandler = @ejs_intrinsics[n.callee.name.slice(1)]
                 if not intrinsicHandler
@@ -1108,10 +1109,11 @@
                 @createLoadThis()

         visitIdentifier: (n) ->
-                debug.log "identifier #{n.name}"
+                debug.log -> "identifier #{n.name}"
                 val = n.name
                 source = @findIdentifierInScope val, @current_scope
                 if source?
+                        debug.log -> "found identifier in scope, at #{source}"
                         rv = irbuilder.createLoad source, "load_#{val}"
                         return rv

@@ -1135,14 +1137,14 @@
                         return rv

                 rv = null
-                debug.log "calling getFunction for #{val}"
+                debug.log -> "calling getFunction for #{val}"
                 rv = @module.getFunction val

                 if not rv
-                        debug.log "Symbol '#{val}' not found in current scope"
+                        debug.log -> "Symbol '#{val}' not found in current scope"
                         rv = @createPropertyLoad @loadGlobal(), n, false, false

-                debug.log "returning #{rv}"
+                debug.log -> "returning #{rv}"
                 rv

         visitObjectExpression: (n) ->
@@ -1181,7 +1183,7 @@

                 # string literals
                 if typeof n.raw is "string" and (n.raw[0] is '"' or n.raw[0] is "'")
-                        debug.log "literal string: #{n.value}"
+                        debug.log -> "literal string: #{n.value}"

                         # check if it's an atom first of all
                         atom_name = "atom-#{n.value}"
@@ -1211,21 +1213,21 @@
                         strload = irbuilder.createLoad str_alloca, "%str_alloca"

                         strload.literal = n
-                        debug.log "strload = #{strload}"
+                        debug.log -> "strload = #{strload}"
                         return strload

                 # regular expression literals
                 if typeof n.raw is "string" and n.raw[0] is '/'
-                        debug.log "literal regexp: #{n.raw}"
+                        debug.log -> "literal regexp: #{n.raw}"
                         c = irbuilder.createGlobalStringPtr n.raw, "strconst"
                         regexpcall = @createCall @ejs_runtime.regexp_new_utf8, [c], "regexptmp"
-                        debug.log "regexpcall = #{regexpcall}"
+                        debug.log -> "regexpcall = #{regexpcall}"
                         return regexpcall

                 # number literals
                 if typeof n.value is "number"
-                        debug.log "literal number: #{n.value}"
+                        debug.log -> "literal number: #{n.value}"
                         if n.value is 0
                                 numload = irbuilder.createLoad @ejs_runtime['zero'], "load_zero"
                         else if n.value is 1
@@ -1249,12 +1251,12 @@

                                 numload = irbuilder.createLoad num_alloca, "%num_alloca"
                         numload.literal = n
-                        debug.log "numload = #{numload}"
+                        debug.log -> "numload = #{numload}"
                         return numload

                 # boolean literals
                 if typeof n.value is "boolean"
-                        debug.log "literal boolean: #{n.value}"
+                        debug.log -> "literal boolean: #{n.value}"
                         return @loadBoolEjsValue n.value

                 throw "Internal error: unrecognized literal of type #{typeof n.value}"


correction to the extend function in the setup command

--- lib/cli.coffee
+++ lib/cli.coffee
@@ -1092,7 +1092,7 @@
             exit "object in setup.cson missing 'slug'"

         # update properties for this site
-        site = extend true, {}, setup.site or {}, {
+        site = extend true, {}, {
           created: Date.now()
           name: slug
           package:
@@ -1105,7 +1105,7 @@
               mobile: 'slide'
               web: 'fade'
           slug: slug
-        }
+        }, setup.site or {}

         # make user an admin
         site.users ?= {}


still need one, though

still need one, though

--- lib/esl.coffee
+++ lib/esl.coffee
@@ -485,7 +485,7 @@
 exports.createServer = (requestListener) -> return new eslServer(requestListener)

 exports.createCallServer = ->
-  server = new eslServer ->
+  server = new eslServer (call) ->
     Unique_ID = 'Unique-ID'
     call.connect (call) ->
       unique_id = call.body[Unique_ID]


stump like we mean it

stump like we mean it

--- lib/pce.coffee
+++ lib/pce.coffee
@@ -6,12 +6,13 @@

 module.exports = class ProcessingChainEntrance
   constructor: (@engine, @journal, @replication) ->
+    stump.stumpify(@, @constructor.name)

   start: =>
-    stump.info("Starting PCE")
+    @info("Starting PCE")
     Q.all [
       @journal.start(@forward_operation).then =>
-        stump.info 'INITIALIZED/REPLAYED LOG'
+        @info 'INITIALIZED/REPLAYED LOG'
         null
       @replication.start() ]

@@ -23,6 +24,6 @@
       @journal.record(message)
       @replication.send(message)
     ]).then =>
-      stump.info('FORWARD DONING', retval.toString() )
+      @info('FORWARD DONING', retval.toString() )
       return retval


Chained comparisons now properly apply DeMorgan's Laws. I couldn't believe there wasn't a test to remind me to toggle the {dis,con}junctions. Added that test.


Groups: removed unnecessary check and indentation

--- client/Main/maincontroller/groupscontroller.coffee
+++ client/Main/maincontroller/groupscontroller.coffee
@@ -45,20 +45,19 @@
     oldGroupName        = @currentGroupName
     @currentGroupName   = groupName

-    unless groupName is oldGroupName
-      KD.remote.cacheable groupName, (err, models)=>
-        if err then callback err
-        else if models?
-          [group] = models
-          if group.bongo_.constructorName isnt 'JGroup'
-            @isReady = yes
-          else
-            @setGroup groupName
-            @currentGroupData.setGroup group
-            @isReady = yes
-            callback null, groupName, group
-            @emit 'GroupChanged', groupName, group
-            @openGroupChannel group, => @emit 'GroupChannelReady'
+    KD.remote.cacheable groupName, (err, models)=>
+      if err then callback err
+      else if models?
+        [group] = models
+        if group.bongo_.constructorName isnt 'JGroup'
+          @isReady = yes
+        else
+          @setGroup groupName
+          @currentGroupData.setGroup group
+          @isReady = yes
+          callback null, groupName, group
+          @emit 'GroupChanged', groupName, group
+          @openGroupChannel group, => @emit 'GroupChannelReady'

   getUserArea:->
     @userArea ? group:


Add error notification for XBlocks in Studio

--- cms/static/coffee/src/xblock/cms.runtime.v1.coffee
+++ cms/static/coffee/src/xblock/cms.runtime.v1.coffee
@@ -41,7 +41,7 @@

             # Starting to save, so show the "Saving..." notification
             if data.state == 'start'
-                @_hide_editor()
+                @_hideEditor()
                 @savingNotification.show()

             # Finished saving, so hide the "Saving..." notification
@@ -50,12 +50,23 @@
                 @savingNotification.hide()

         else if name == 'cancel'
-            @_hide_editor()
+            @_hideEditor()

-      _hide_editor: () ->
+        else if name == 'error'
+            if 'msg' of data
+                @_showAlert(data.msg)
+
+      _hideEditor: () ->
           # This will close all open component editors, which works
           # if we assume that <= 1 are open at a time.
           el = $('.component.editing')
           el.removeClass('editing')
           el.find('.component-editor').slideUp(150)
           ModalUtils.hideModalCover()
+
+      _showAlert: (msg) ->
+        new NotificationView.Error({
+            title: "OpenAssessment Save Error",
+            message: msg,
+            closeIcon: false
+        }).show()


minor typo in variable name

minor typo in variable name

--- fizzylogo_populateMethods.coffee
+++ fizzylogo_populateMethods.coffee
@@ -119,10 +119,10 @@
   return FLNumber.createNew @value * operandum.value

-FLNumber.msgPatterns.push flParse "== ( tocampare )"
-FLNumber.methodBodies.push (context) ->
-  tocampare = context.tempVariablesDict[ValidID.fromString "tocampare"]
-  if @value == tocampare.value
+FLNumber.msgPatterns.push flParse "== ( toCompare )"
+FLNumber.methodBodies.push (context) ->
+  toCompare = context.tempVariablesDict[ValidID.fromString "toCompare"]
+  if @value == toCompare.value
     return FLBoolean.createNew true
   else
     return FLBoolean.createNew false


Commit message

Commit message

--- lib/git-plus.coffee
+++ lib/git-plus.coffee
@@ -8,7 +8,5 @@
     atom.workspaceView.command "git-plus:write-all", -> GitWrite(true)

   deactivate: ->
-    # @gitPlusView.destroy()

   serialize: ->
-    # gitPlusViewState: @gitPlusView.serialize()


Refactored leaf node.

Refactored leaf node.

--- lib/hash_map.coffee
+++ lib/hash_map.coffee
@@ -118,17 +118,15 @@
     if util.equal(@key, leaf.key)
       leaf
     else
-      this.baseForAdditionOf(shift, hash, leaf).with(shift, hash, leaf)
+      if hash == @hash
+        base = new CollisionNode(hash)
+      else
+        base = new BitmapIndexedNode()
+      base.with(shift, @hash, this).with(shift, hash, leaf)

   without: (shift, hash, key) -> null

   toString: -> "LeafNode(#{@key}, #{@value})"
-
-  baseForAdditionOf: (shift, hash, leaf) ->
-    if hash == @hash
-      new CollisionNode(hash).with(shift, @hash, this)
-    else
-      new BitmapIndexedNode().with(shift, @hash, this)

 # A collision node contains several key-value pairs in which all keys


:art: combine selectTarget and withFlashing methods

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -110,6 +110,11 @@
     if @target.select()
       callback()

+  selectTargetWithFlashing: (callback) ->
+    @selectTarget =>
+      @withFlashing ->
+        callback()
+
 class Select extends Operator
   @extend()
   execute: ->
@@ -184,12 +189,11 @@
   execute: ->
     if @target.isLinewise?() or settings.get('stayOnTransformString')
       points = _.pluck(@editor.getSelectedBufferRanges(), 'start')
-    @selectTarget =>
-      @withFlashing =>
-        for selection in @editor.getSelections()
-          range = selection.insertText @getNewText(selection.getText())
-          if @adjustCursor
-            selection.cursor.setBufferPosition(points?.shift() ? range.start)
+    @selectTargetWithFlashing =>
+      for selection in @editor.getSelections()
+        range = selection.insertText @getNewText(selection.getText())
+        if @adjustCursor
+          selection.cursor.setBufferPosition(points?.shift() ? range.start)
     @vimState.activateNormalMode()

 class ToggleCase extends TransformString
@@ -334,8 +338,7 @@
   execute: ->
     if @target.isLinewise?()
       points = (s.getBufferRange().start for s in @editor.getSelections())
-    @selectTarget =>
-      @withFlashing ->
+    @selectTargetWithFlashing =>
       @setTextToRegister @editor.getSelectedText()
       for selection in @editor.getSelections()
         point = points?.shift() ? selection.getBufferRange().start
@@ -496,13 +499,12 @@
   hoverText: ':pencil:'
   hoverIcon: ':replace-with-register:'
   execute: ->
-    @selectTarget =>
-      @withFlashing =>
-        points = _.pluck(@editor.getSelectedBufferRanges(), 'start')
-        @editor.replaceSelectedText {}, (text) =>
-          @vimState.register.get().text ? text
-        ranges = (new Range(p, p) for p in points)
-        @editor.setSelectedBufferRanges(ranges)
+    @selectTargetWithFlashing =>
+      points = _.pluck(@editor.getSelectedBufferRanges(), 'start')
+      @editor.replaceSelectedText {}, (text) =>
+        @vimState.register.get().text ? text
+      ranges = (new Range(p, p) for p in points)
+      @editor.setSelectedBufferRanges(ranges)
     @vimState.activateNormalMode()

 class ToggleLineComments extends Operator
@@ -511,11 +513,10 @@
   hoverIcon: ':toggle-line-comment:'
   execute: ->
     markerByCursor = @markCursorBufferPositions()
-    if @target.select()
-      @withFlashing =>
-        @editor.transact =>
-          for s in @editor.getSelections()
-            s.toggleLineComments()
+    @selectTargetWithFlashing =>
+      @editor.transact =>
+        for s in @editor.getSelections()
+          s.toggleLineComments()
     @restoreMarkedCursorPositions markerByCursor
     @vimState.activateNormalMode()


improve flash-UI feedback when Y in vC mode.

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -55,7 +55,9 @@
     @vimState.mark.setRange('[', ']', range)

   needFlash: ->
-    if @flashTarget and not @isMode('visual')
+    return unless @flashTarget
+    {mode, submode} = @vimState
+    if mode isnt 'visual' or (@target.isMotion() and submode isnt @target.wise)
       settings.get('flashOnOperate') and (@getName() not in settings.get('flashOnOperateBlacklist'))

   flashIfNecessary: (ranges) ->


:bug: fix toggle range marker on repeat situation

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -402,16 +402,10 @@
     for rangeMarker in @vimState.getRangeMarkers() when containsPoint(rangeMarker, point)
       return rangeMarker

-  initialize: ->
-    rangeMarker = @getRangeMarkerAtCursor()
-    if rangeMarker?
+  execute: ->
+    if rangeMarker = @getRangeMarkerAtCursor()
       rangeMarker.destroy()
       @vimState.removeRangeMarker(rangeMarker)
-      @abort()
-
-  execute: ->
-    if rangeMarker = @getRangeMarkerAtCursor()
-      rangeMarker.destroy()
     else
       super


Guard against ing elements with no src attribute

--- lib/renderer.coffee
+++ lib/renderer.coffee
@@ -60,9 +60,9 @@
   html = $(html)
   for imgElement in html.find("img")
     img = $(imgElement)
-    src = img.attr('src')
-    continue if src.match /^(https?:\/\/)/
-    img.attr('src', path.resolve(path.dirname(filePath), src))
+    if src = img.attr('src')
+      continue if src.match /^(https?:\/\/)/
+      img.attr('src', path.resolve(path.dirname(filePath), src))

   html


patches

patches

--- lib/selector.coffee
+++ lib/selector.coffee
@@ -5,8 +5,9 @@
     @selector ?= new SelectListView
     @selector.setItems []
     @selector.storeFocusedElement()
+    @selector.getFilterKey = => 'text'
     @selector.viewForItem = (item) =>
-      "
#{item}
"
+      "
#{item.text}
"

     if xs.constructor == Promise
       @selector.setLoading "Loading..."


Slight change in the seq() function.

Slight change in the seq() function.

--- lib/sequence.coffee
+++ lib/sequence.coffee
@@ -37,12 +37,12 @@
     null
   else if src.constructor == Sequence
     src
+  else if typeof src.toSeq == 'function'
+    src.toSeq()
   else if typeof src.length == 'number'
     fromArray src, 0
-  else if typeof src.toSeq == 'function'
-    src.toSeq()
   else if typeof src.first == 'function' and typeof src.rest == 'function'
-    seq.conj src.first(), src.rest
+    src
   else
     throw new Error("cannot make a sequence from #{src}")


rename status bar icon variable for readability

--- lib/wakatime.coffee
+++ lib/wakatime.coffee
@@ -11,7 +11,7 @@
 packageVersion = null
 lastHeartbeat = 0
 lastFile = ''
-statusBarTileView = null
+statusBarIcon = null
 pluginReady = false

 # package dependencies
@@ -48,18 +48,18 @@
     )

   consumeStatusBar: (statusBar) ->
-    statusBarTileView = new StatusBarTileView()
-    statusBarTileView.init()
-    @statusBarTile = statusBar?.addRightTile(item: statusBarTileView, priority: 300)
+    statusBarIcon = new StatusBarTileView()
+    statusBarIcon.init()
+    @statusBarTile = statusBar?.addRightTile(item: statusBarIcon, priority: 300)
     if pluginReady
-      statusBarTileView.setTitle('WakaTime ready')
-      statusBarTileView.setStatus()
+      statusBarIcon.setTitle('WakaTime ready')
+      statusBarIcon.setStatus()
       if not atom.config.get 'wakatime.showStatusBarIcon'
-        statusBarTileView?.hide()
+        statusBarIcon?.hide()

   deactivate: ->
     @statusBarTile?.destroy()
-    statusBarTileView?.destroy()
+    statusBarIcon?.destroy()
     @settingChangedObserver?.dispose()

 checkCLI = () ->
@@ -94,15 +94,15 @@
 finishActivation = () ->
   pluginReady = true
   setupEventHandlers()
-  statusBarTileView?.setTitle('WakaTime ready')
-  statusBarTileView?.setStatus()
+  statusBarIcon?.setTitle('WakaTime ready')
+  statusBarIcon?.setStatus()
   log.debug 'Finished initializing WakaTime.'

 settingChangedHandler = (settings) ->
   if settings.showStatusBarIcon
-    statusBarTileView?.show()
+    statusBarIcon?.show()
   else
-    statusBarTileView?.hide()
+    statusBarIcon?.hide()
   if atom.config.get 'wakatime.debug'
     log.setLevel('DEBUG')
   else
@@ -152,8 +152,8 @@
       if err2?
         msg = 'Error: could not write to wakatime config file'
         log.error msg
-        statusBarTileView?.setStatus('Error')
-        statusBarTileView?.setTitle(msg)
+        statusBarIcon?.setStatus('Error')
+        statusBarIcon?.setTitle(msg)

 getUserHome = ->
   process.env[if process.platform == 'win32' then 'USERPROFILE' else 'HOME'] || ''
@@ -253,13 +253,13 @@
   url = 'https://www.python.org/ftp/python/' + pyVer + '/python-' + pyVer + '-embed-' + arch + '.zip'

   log.debug 'downloading python...'
-  statusBarTileView?.setStatus('downloading python...')
+  statusBarIcon?.setStatus('downloading python...')

   zipFile = __dirname + path.sep + 'python.zip'
   downloadFile(url, zipFile, ->

     log.debug 'extracting python...'
-    statusBarTileView?.setStatus('extracting python...')
+    statusBarIcon?.setStatus('extracting python...')

     unzip(zipFile, __dirname + path.sep + 'python', ->
       fs.unlink(zipFile)
@@ -325,7 +325,7 @@

 installCLI = (callback) ->
   log.debug 'Downloading wakatime-cli...'
-  statusBarTileView?.setStatus('downloading wakatime-cli...')
+  statusBarIcon?.setStatus('downloading wakatime-cli...')
   url = 'https://github.com/wakatime/wakatime/archive/master.zip'
   zipFile = __dirname + path.sep + 'wakatime-master.zip'
   downloadFile(url, zipFile, ->
@@ -334,7 +334,7 @@

 extractCLI = (zipFile, callback) ->
   log.debug 'Extracting wakatime-master.zip file...'
-  statusBarTileView?.setStatus('extracting wakatime-cli...')
+  statusBarIcon?.setStatus('extracting wakatime-cli...')
   removeCLI(->
     unzip(zipFile, __dirname, callback)
   )
@@ -431,13 +431,13 @@

           if msg?
             log.warn msg
-          statusBarTileView?.setStatus(status)
-          statusBarTileView?.setTitle(title)
+          statusBarIcon?.setStatus(status)
+          statusBarIcon?.setTitle(title)

         else
-          statusBarTileView?.setStatus()
+          statusBarIcon?.setStatus()
           today = new Date()
-          statusBarTileView?.setTitle('Last heartbeat sent ' + formatDate(today))
+          statusBarIcon?.setTitle('Last heartbeat sent ' + formatDate(today))
       )
       lastHeartbeat = time
       lastFile = file.path


only chmod wakatime-cli if not Windows platform

--- lib/wakatime.coffee
+++ lib/wakatime.coffee
@@ -312,7 +312,8 @@
   url = s3BucketUrl() + 'wakatime' + ext
   localFile = __dirname + path.sep + 'wakatime-cli' + ext
   downloadFile(url, localFile, () ->
-    fs.chmodSync(localFile, 0o755)
+    if os.platform != 'win32'
+      fs.chmodSync(localFile, 0o755)
     if callback?
       callback()
   )


Add line number padding to expected width

--- spec/app/editor-spec.coffee
+++ spec/app/editor-spec.coffee
@@ -1494,18 +1494,18 @@

     describe "width", ->
       it "sets the width based on largest line number", ->
-        expect(editor.gutter.lineNumbers.outerWidth()).toBe editor.charWidth * 2
+        expect(editor.gutter.lineNumbers.outerWidth()).toBe(editor.charWidth * 2 + editor.gutter.calculateLineNumberPadding())

       it "updates the width and the left position of the scroll view when total number of lines gains a digit", ->
         editor.setText("")

-        expect(editor.gutter.lineNumbers.outerWidth()).toBe editor.charWidth * 1
+        expect(editor.gutter.lineNumbers.outerWidth()).toBe(editor.charWidth * 1 + editor.gutter.calculateLineNumberPadding())
         expect(parseInt(editor.scrollView.css('left'))).toBe editor.gutter.outerWidth()

         for i in [1..9] # Ends on an empty line 10
           editor.insertText "#{i}\n"

-        expect(editor.gutter.lineNumbers.outerWidth()).toBe editor.charWidth * 2
+        expect(editor.gutter.lineNumbers.outerWidth()).toBe(editor.charWidth * 2 + editor.gutter.calculateLineNumberPadding())
         expect(parseInt(editor.scrollView.css('left'))).toBe editor.gutter.outerWidth()

     describe "when lines are inserted", ->


Templates location.

Templates location.

--- vocab/static/vocab/scripts/coffeescript/vocabulary.coffee
+++ vocab/static/vocab/scripts/coffeescript/vocabulary.coffee
@@ -1,11 +1,11 @@
 define [
     'cilantro'
     'cilantro/ui',
-    'tpl!templates/vocab-browser/breadcrumbs.html'
-    'tpl!templates/vocab-browser/browse.html'
-    'tpl!templates/vocab-browser/search-results.html'
-    'tpl!templates/vocab-browser/staged.html'
-    'tpl!templates/vocab-browser/vocab-browser.html'
+    'tpl!templates/vocab/breadcrumbs.html'
+    'tpl!templates/vocab/browse.html'
+    'tpl!templates/vocab/search-results.html'
+    'tpl!templates/vocab/staged.html'
+    'tpl!templates/vocab/vocab-browser.html'
 ], (c, ui,
     breadcrumbsTemplate,
     browseTemplate,


Add slider spec

Add slider spec

--- spec/components/slider.cjsx
+++ spec/components/slider.cjsx
@@ -1,13 +1,17 @@
 Slider = require '../../components/slider'

 module.exports = React.createClass
+  test: ->
+    marginTop: "1rem"
+
   render: ->

-
Sliders

+
Sliders

Normal slider

       <Slider />

With steps, initial value and editable

       <Slider value={5} min={0} max={10} editable />

Pinned and with snaps

-      <Slider pinned snaps value={1} min={0} max={10} step={1} editable />
+
+      <Slider pinned value={1} min={0} max={10} step={1} editable />


verify

verify

--- spec/does/reset_spec.coffee
+++ spec/does/reset_spec.coffee
@@ -1,7 +1,9 @@
 {ipso, mock, tag} = require '../../lib/ipso'

-runtime: -> does._test().runtime
-objects: -> does._test().spectacles
+does = require 'does'
+
+runtime = -> does._test().runtime
+entities = -> does._test().entities

 #
 # tests does.reset() here due to the complexity of setting up
@@ -32,6 +34,9 @@
         mock1 = mock 'mock1'
         MyClass.does SHOULD_NOT_CAUSE_FAILURE: -> mock1

+    before ipso (ModuleMock) ->
+        MyClass.does SHOULD_NOT_CAUSE_FAILURE_EITHER: -> ModuleMock
+
     beforeEach ipso -> MyClass.does each_DESCRIBE_1: ->

     context 'OUTER', ->
@@ -55,12 +60,12 @@
                 MyClass.each_INNER_1()
                 MyClass.each_INNER_2()

-        it 'no longer expects INNER functions', ipso (MyClass, NOT) ->
+        it 'no longer expects INNER functions but fails because not all outer expectaations were called', ipso (MyClass, NOT) ->

             NOT MyClass.each_INNER_1
             NOT MyClass.each_INNER_2

-            MyClass.each_ROOT_1()
+            #MyClass.each_ROOT_1()
             MyClass.each_DESCRIBE_1()
             MyClass.each_OUTER_1()

@@ -70,25 +75,37 @@
         NOT MyClass.each_INNER_2
         NOT MyClass.each_OUTER_1

-        #NOT MyClass.each_ROOT_1
+        # NOT MyClass.each_ROOT_1
         MyClass.each_ROOT_1()
         MyClass.each_DESCRIBE_1()

-    context 'USING MOCK TAGS', ->
+
+    xcontext 'USING MOCK TAGS', ->

         beforeEach ipso (mock1) -> mock1.does

             function1: ->
             function2: ->

-        it 'fails because expectations on the mock were not called', ipso (mock1) ->
+        beforeEach ipso (ModuleMock) -> ModuleMock.does
+
+            function1: ->
+
+        it 'fails because expectations on the mock were not called', ipso (mock1, ModuleMock) ->
+
+

             mockedThing = MyClass.SHOULD_NOT_CAUSE_FAILURE()

             mockedThing.is mock1
             mockedThing.function1()

-
+            moduleMock = MyClass.SHOULD_NOT_CAUSE_FAILURE_EITHER()
+            moduleMock.function1()
+            #ModuleMock.$ipso.save()
+
+
+after -> console.log entities()


Allow level to be specified for creature in data

--- src/entities/creature.coffee
+++ src/entities/creature.coffee
@@ -22,7 +22,7 @@
 		{
 			@personalities
 			@inventory, @equipment
-			@xp
+			@xp, level
 		} = data

 		@species ?= new creatureSpecies.StrangeGoo
@@ -31,6 +31,9 @@
 		if @health? and not (@health instanceof RangedValue)
 			@health = new RangedValue @health

+		if level? and not @xp?
+			@xp = calc.xpForLevel level
+
 		@xp ?= 0

 		Object.defineProperty @, 'level',


Fixed sidebar padding

Fixed sidebar padding

--- www/css.coffee
+++ www/css.coffee
@@ -79,4 +79,4 @@
 CSS.add "a:hover", "color:#000"

 CSS.add "div.module_title", "font-size: 28pt; margin-bottom: 20px;"
-CSS.add "div.sidebar", "padding-top: 55px; padding-left: 20px"
+CSS.add "div.sidebar", "padding-top: 5px; padding-left: 20px"


Home: password modal added

Home: password modal added

--- client/Home/AppView.coffee
+++ client/Home/AppView.coffee
@@ -13,12 +13,64 @@
     @signUpForm = new HomeRegisterForm
       cssClass    : 'login-form register'
       buttonTitle : 'Sign up'
+      callback    : @bound 'showPasswordModal'

     @testimonials = new TestimonialsView

     @footer = new FooterView

+
+  showPasswordModal: (formData) ->
+
+    unless @signUpForm.email.input.valid and @signUpForm.username.input.valid
+      @signUpForm.button.hideLoader()
+
+    {appManager, mainView} = KD.singletons
+
+    mainView.setClass 'blur'
+
+    modal = new KDModalViewWithForms
+      cssClass                : 'password'
+      width                   : 600
+      height                  : 'auto'
+      overlay                 : yes
+      title                   : 'Almost there, please enter a strong password.'
+      tabs                    :
+        forms                 :
+          password            :
+            callback          : (form) =>
+              appManager.require 'Login', (controller) =>
+                KD.mixpanel 'Register submit, click'
+                controller.getView().doRegister formData, @signUpForm
+                log 'set the password here'
+                modal.destroy()
+            fields            :
+              password        :
+                type          : 'password'
+                cssClass      : 'half'
+                name          : 'password'
+                placeholder   : 'password'
+                nextElement   :
+                  confirm     :
+                    cssClass  : 'half'
+                    type      : 'password'
+                    name      : 'confirm'
+                    placeholder : 'confirm password'
+            buttons           :
+              submit          :
+                cssClass      : 'solid green medium'
+                type          : 'submit'
+                title         : 'Submit'
+
+    modal.once 'KDObjectWillBeDestroyed', =>
+      mainView.unsetClass 'blur'
+      @signUpForm.button.hideLoader()
+
+
+
+
   pistachio : ->
+
     """


Rename Meter module

Rename Meter module

--- src/game_object_meter.coffee
+++ src/game_object_meter.coffee
@@ -83,7 +83,7 @@

       player = GameObject

-      player.include Metered
+

       player.meter 'health',
         border
@@ -141,7 +141,6 @@
   Shows the named meter

       player = GameObject
-

       # creates a health meter but disables visibility
       player.meter 'health'


#1485 - Cloned multi choice question uses same choice list

--- jsapp/xlform_model_view/model.survey.coffee
+++ jsapp/xlform_model_view/model.survey.coffee
@@ -56,8 +56,9 @@
       @rows.add(row.toJSON(), at: index)
       new_row = @rows.at(index)
       survey = @getSurvey()
-      if rowlist = new_row.getList()
+      if rowlist = row.getList()
         survey.choices.add(options: rowlist.options.toJSON())
+        new_row.get('type').set('list', rowlist)
       name_detail = new_row.get('name')
       name_detail.set 'value', name_detail.deduplicate(survey)


Fix brain deep copy issue

Fix brain deep copy issue

--- src/hubot-slack-relay.coffee
+++ src/hubot-slack-relay.coffee
@@ -45,8 +45,11 @@
     #store array before saving, due to bad mergeData in brain
     temp = relays

-    robot.brain.set BRAIN_KEY, temp
+    robot.brain.set BRAIN_KEY, relays
     robot.brain.save()
+
+    #re-assign relays for deep copy after save
+    relays = temp

   robot.respond /relay add\s+(\S+)\s+(\S+)\s+(\S+)/i, (res) =>


Binded to wrong turbolinks event

Binded to wrong turbolinks event

Turbolinks page:change fires every time a page is changed. When using back and forward as well. The back and forward dom is cached, however, and event bindings are preserved on the document.body nodes

--- src/jquery.turbolinks.coffee
+++ src/jquery.turbolinks.coffee
@@ -25,4 +25,4 @@
   callbacks.push(callback)

 # Bind `ready` to Tubolinks page change event
-$(document).on('page:change', ready)
+$(document).on('page:load', ready)