updating not not to exclamation marks

updating not not to exclamation marks

--- src/flux/task-plan.coffee
+++ src/flux/task-plan.coffee
@@ -60,7 +60,7 @@
       plan.title and plan.opens_at and plan.due_at and plan.settings?.page_ids?.length > 0
     isPublished: (id) ->
       plan = @_getPlan(id)
-      not not plan?.published_at
+      !!plan?.published_at

 extendConfig(TaskPlanConfig, new CrudConfig())
 {actions, store} = makeSimpleStore(TaskPlanConfig)


Refactoring

Refactoring

--- _includes/coffeescripts/contact.coffee
+++ _includes/coffeescripts/contact.coffee
@@ -14,21 +14,31 @@
       scrollTop: $form.offset().top - 35
     , 100

+  # District selector for Contact us triggered:
+  #   * on page load from cookie
+  #   * when user selects from menu
+  #   * when user enter an address search
+  if $("aside.contact-us.multi-district").length
+    $.cookie.json = true
+    $contactDistrict = $("#contact-district")

-  # District selector for Contact us
-  if $("aside.contact-us.multi-district").length
     $("aside.contact-us.multi-district .vcard").hide()

-    $.cookie.json = true
-    # Get selected district
+    # District selector is changed by user or address search
+    $contactDistrict.change ->
+      # Hide all contact cards
+      $("aside.contact-us.multi-district .vcard").hide()
+      # Show selected districts contact card
+      $("#district-#{$(@).val()}").show()
+
+      # Set selected district in cookie
+      $.cookie('city-district', $(@).val())
+
+    # Get selected district from cookie if any
     selectedDistrict = $.cookie('city-district')
     if selectedDistrict
-      $("#contact-district").val selectedDistrict
-      $("#district-#{selectedDistrict}").show()
-
-    # User selects a district
-    $("#contact-district").change ->
-      updateVCard $(@).val()
+      $contactDistrict.val selectedDistrict
+      $contactDistrict.change()

     # User types an address and select
     $("#district-search").autocomplete
@@ -42,19 +52,7 @@
           success: (data) ->
             response $.map data.addresses, (item) ->
               label: "#{item.name} (#{item.towndistrict})"
-              value: item.name
               district: item.towndistrict
       minLength: 2
       select: (event, ui) ->
-        district = ui.item.district.toLowerCase()
-        $("#contact-district").val(ui.item.district.toLowerCase())
-        $("#district-search").val()
-        updateVCard district
-
-  updateVCard = (district) ->
-    $("aside.contact-us.multi-district .vcard").hide()
-    $("#district-#{district}").show()
-
-    # Set selected district in cookie
-    $.cookie('city-district', district)
-    $("#district-search").val("")
+        $contactDistrict.val(ui.item.district.toLowerCase()).change()


edited comments on TaxonConceptLinkView

edited comments on TaxonConceptLinkView

--- app/assets/javascripts/species/views/taxon_concept_link_view.js.coffee
+++ app/assets/javascripts/species/views/taxon_concept_link_view.js.coffee
@@ -2,7 +2,7 @@
 #  headers, I want to fire a new search.
 #
 # This view has an atomic template, that contains the name of the taxon
-#  clicked in the results heading. When clickedS,
+#  clicked in the results heading. When clicked,
 #  `newTaxonSearch` is called on the `TaxonConceptsController`, that will then
 #  reset the `taxonConceptQuery` property on the `SearchController` and fire
 #  a new call to `loadTaxonConcepts`.


Add `tokenBased` access level

Add `tokenBased` access level

--- services/web/app/coffee/Features/Authorization/PublicAccessLevels.coffee
+++ services/web/app/coffee/Features/Authorization/PublicAccessLevels.coffee
@@ -1,4 +1,5 @@
 module.exports =
 	READ_ONLY: "readOnly"
 	READ_AND_WRITE: "readAndWrite"
-	PRIVATE: "private"+	PRIVATE: "private"
+	TOKEN_BASED: "tokenBased"


fix acceptance test to work with redis cluster too

--- services/document-updater/test/acceptance/coffee/ApplyingUpdatesToADocTests.coffee
+++ services/document-updater/test/acceptance/coffee/ApplyingUpdatesToADocTests.coffee
@@ -7,6 +7,7 @@
 rclient_history = require("redis-sharelatex").createClient(Settings.redis.history)
 rclient_du = require("redis-sharelatex").createClient(Settings.redis.documentupdater)
 Keys = Settings.redis.documentupdater.key_schema
+HistoryKeys = Settings.redis.history.key_schema

 MockTrackChangesApi = require "./helpers/MockTrackChangesApi"
 MockWebApi = require "./helpers/MockWebApi"
@@ -49,10 +50,10 @@
 				done()

 		it "should push the applied updates to the track changes api", (done) ->
-			rclient_history.lrange "UncompressedHistoryOps:#{@doc_id}", 0, -1, (error, updates) =>
+			rclient_history.lrange HistoryKeys.uncompressedHistoryOps({@doc_id}), 0, -1, (error, updates) =>
 				throw error if error?
 				JSON.parse(updates[0]).op.should.deep.equal @update.op
-				rclient_history.sismember "DocsWithHistoryOps:#{@project_id}", @doc_id, (error, result) =>
+				rclient_history.sismember HistoryKeys.docsWithHistoryOps({@project_id}), @doc_id, (error, result) =>
 					throw error if error?
 					result.should.equal 1
 					done()
@@ -82,9 +83,9 @@
 				done()

 		it "should push the applied updates to the track changes api", (done) ->
-			rclient_history.lrange "UncompressedHistoryOps:#{@doc_id}", 0, -1, (error, updates) =>
+			rclient_history.lrange HistoryKeys.uncompressedHistoryOps({@doc_id}), 0, -1, (error, updates) =>
 				JSON.parse(updates[0]).op.should.deep.equal @update.op
-				rclient_history.sismember "DocsWithHistoryOps:#{@project_id}", @doc_id, (error, result) =>
+				rclient_history.sismember HistoryKeys.docsWithHistoryOps({@project_id}), @doc_id, (error, result) =>
 					result.should.equal 1
 					done()

@@ -127,12 +128,12 @@
 						done()

 			it "should push the applied updates to the track changes api", (done) ->
-				rclient_history.lrange "UncompressedHistoryOps:#{@doc_id}", 0, -1, (error, updates) =>
+				rclient_history.lrange HistoryKeys.uncompressedHistoryOps({@doc_id}), 0, -1, (error, updates) =>
 					updates = (JSON.parse(u) for u in updates)
 					for appliedUpdate, i in @updates
 						appliedUpdate.op.should.deep.equal updates[i].op

-					rclient_history.sismember "DocsWithHistoryOps:#{@project_id}", @doc_id, (error, result) =>
+					rclient_history.sismember HistoryKeys.docsWithHistoryOps({@project_id}), @doc_id, (error, result) =>
 						result.should.equal 1
 						done()


Revert "Make very simple shallow copy of aceDelta when there's an undo error"

This reverts commit 1d77a95f17dde6f8792bca1989d65952474b144c.

--- services/web/public/coffee/ide/editor/directives/aceEditor/undo/UndoManager.coffee
+++ services/web/public/coffee/ide/editor/directives/aceEditor/undo/UndoManager.coffee
@@ -233,11 +233,16 @@
 			start = aceDelta.start
 			if !start?
 				error = new Error("aceDelta had no start event.")
-				inspectedAceDelta = {}
-				for key, value of aceDelta
-					inspectedAceDelta[key] = typeof value
+				JSONstringifyWithCycles = (o) ->
+					seen = []
+					return JSON.stringify o, (k,v) ->
+						if (typeof v == 'object')
+							if ( !seen.indexOf(v) )
+								return '__cycle__'
+							seen.push(v);
+						return v
 				Raven?.captureException(error, {
-					aceDelta: JSON.stringify(inspectedAceDelta)
+					aceDelta: JSONstringifyWithCycles(aceDelta)
 				})
 				throw error
 			linesBefore = docLines.slice(0, start.row)


Tweak the command line options.

Tweak the command line options.

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -15,16 +15,17 @@
   .describe 's', 'client secret'
   .alias 's', 'client-secret'

-  .describe 'language'
+  .describe 'language', 'Language used for slugs when referencing parent.'
   .nargs 'language', 1
   .default 'language', 'en'

-  .describe 'parentBy'
+  .describe 'parentBy', 'Property used to reference parent - use externalId or slug or id'
   .nargs 'parentBy', 1
   .default 'parentBy', 'externalId'

-  .describe 'continueOnProblems'
+  .describe 'continueOnProblems', 'Continue with creating/updating further categories even if API returned with 400 status code.'
   .boolean 'continueOnProblems'
+  .default 'continueOnProblems', false

   .command 'export', 'Export categories'
   .command 'import', 'Import categories'


Forgot to run tests before commit :(

Forgot to run tests before commit :(

--- src/coffeelint.coffee
+++ src/coffeelint.coffee
@@ -193,7 +193,8 @@

         # Do line linting.
         tokensByLine = lexicalLinter.tokensByLine
-        lineLinter = new LineLinter(source, config, _rules, tokensByLine, literate)
+        lineLinter = new LineLinter(source, config, _rules, tokensByLine,
+            literate)
         lineErrors = lineLinter.lint()
         errors = errors.concat(lineErrors)
         block_config = lineLinter.block_config


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/collidable.coffee
+++ src/collidable.coffee
@@ -14,7 +14,7 @@
       touching: NONE

     self.attrAccessor(
-      "immovable"
+      "immovable",
       "velocity"
     )


Fix displaced socket contents in undo stack

--- src/controller.coffee
+++ src/controller.coffee
@@ -339,6 +339,7 @@
           'socketReparse'
           'handwrittenReparse'
           'blockMove'
+          'blockMoveToSocket'
           'blockMoveToFloat'
           'blockMoveFromFloat'
           'createIndent'
@@ -396,6 +397,9 @@
               if operation.after?
                 pos = @tree.getTokenAtLocation operation.after

+                if operation.displaced?
+                  pos.insert operation.displaced
+
                 until pos.type is 'blockStart' then pos = pos.next
                 pos.block.moveTo null

@@ -421,6 +425,7 @@
                 operation.block.moveTo target

                 moveCursorToRaw operation.block.end
+
             when 'blockMoveToFloat'
               # Remove the block from the list of floating blocks
               @floatingBlocks.splice operation.floatingBlockIndex
@@ -496,13 +501,16 @@

           return

-        console.log 'before', parent
         # Log the undo operation
         addMicroUndoOperation
           type: 'blockMove'
           before: if parent? then parent.getSerializedLocation() else null
           after: if target? then target.getSerializedLocation() else null
+          displaced: if target?.type is 'socketStart' then target.socket.content().clone() else null
           block: block.clone()
+
+        if target?.type is 'socketStart'
+          target.socket.content().remove()

         block.moveTo target

@@ -1135,9 +1143,6 @@
                 moveBlockTo @selection, highlight.end

               when 'socket'
-                # Remove any previously occupying block or text
-                if highlight.content()? then highlight.content().remove()
-
                 # Insert
                 moveBlockTo @selection, highlight.start


Add your own

Add your own

--- src/gameoflife.coffee
+++ src/gameoflife.coffee
@@ -27,7 +27,7 @@
     @_cols = cols
     @_sequencers = []

-    @_fbRef = new Firebase('https://glichjs.firebaseio.com/public')
+    @_fbRef = new Firebase('ADD_YOUR_OWN')
     @_seedFbRef = @_fbRef.child('seed')
     @_sequencersFbRef = @_fbRef.child('sequencers')
     @_initSeed()


Fix some freeze-melt bugs

Fix some freeze-melt bugs

--- src/controller.coffee
+++ src/controller.coffee
@@ -2517,8 +2517,7 @@
             div.style.top = (line * lineHeight - aceScrollTop + @scrollOffsets.main.y) + 'px'
           ), fadeTime

-      for line, element of @lineNumberTags
-        element.style.display = 'none'
+      @lineNumberWrapper.style.display = 'none'

       # Kick off fade-out transition

@@ -2567,14 +2566,16 @@
   Editor::performFreezeAnimation = (fadeTime = 500, translateTime = 500, cb = ->)->
     if not @currentlyUsingBlocks and not @currentlyAnimating
       @fireEvent 'statechange', [true]
-      setValueResult = @setValue @aceEditor.getValue()
+      setValueResult = @setValue_raw @aceEditor.getValue()

       unless setValueResult.success
         return setValueResult

       if @aceEditor.getFirstVisibleRow() is 0
+        console.log 'is 0'
         @mainScroller.scrollTop = 0
       else
+        console.log 'scrolling to line', @aceEditor.getFirstVisibleRow()
         @mainScroller.scrollTop = @view.getViewNodeFor(@tree).bounds[@aceEditor.getFirstVisibleRow()].y

       setTimeout (=>
@@ -2682,8 +2683,7 @@
           @iceElement.style.transition = ''

           @currentlyAnimating = false
-          for line, element of @lineNumberTags
-            element.style.display = 'block'
+          @lineNumberWrapper.style.display = 'block'
           @redrawMain()
           @paletteHeader.style.zIndex = 257

@@ -2951,30 +2951,31 @@
   Editor::setTrimWhitespace = (trimWhitespace) ->
     @trimWhitespace = trimWhitespace

+  Editor::setValue_raw = (value) ->
+    if @trimWhitespace then value = value.trim()
+
+    newParse = coffee.parse value, wrapAtRoot: true
+
+    if value isnt @tree.stringify()
+      @addMicroUndoOperation 'CAPTURE_POINT'
+    @addMicroUndoOperation new SetValueOperation @tree, newParse
+
+    @tree = newParse; @gutterVersion = -1
+    @tree.start.insert @cursor
+    @redrawMain()
+
+    return success: true
+
   Editor::setValue = (value) ->
-    #try
-      # Whitespace trimming hack to account
-      # for ACE editor extra line in some applications
-
-      @aceEditor.setValue value
-      @aceEditor.resize true
-
-      if @trimWhitespace then value = value.trim()
-
-      newParse = coffee.parse value, wrapAtRoot: true
-
-      if value isnt @tree.stringify()
-        @addMicroUndoOperation 'CAPTURE_POINT'
-      @addMicroUndoOperation new SetValueOperation @tree, newParse
-
-      @tree = newParse; @gutterVersion = -1
-      @tree.start.insert @cursor
-      @redrawMain()
-
-      return success: true
-
-    #catch e
-    #  return success: false, error: e
+
+    oldScrollTop = @aceEditor.session.getScrollTop()
+
+    @aceEditor.setValue value, -1
+    @aceEditor.resize true
+
+    @aceEditor.session.setScrollTop oldScrollTop
+
+    @setValue_raw value

   Editor::getValue = -> if @currentlyUsingBlocks then @tree.stringify() else @aceEditor.getValue()

@@ -3015,7 +3016,12 @@
       @resize(); @redrawMain()

     else
-      @aceEditor.setValue @getValue(), -1
+      oldScrollTop = @aceEditor.session.getScrollTop()
+
+      @aceEditor.setValue value, -1
+      @aceEditor.resize true
+
+      @aceEditor.session.setScrollTop oldScrollTop

       @iceElement.style.top = @iceElement.style.left = '-9999px'
       @aceElement.style.top = @aceElement.style.left = '0px'
@@ -3219,6 +3225,9 @@
     @gutter = document.createElement 'div'
     @gutter.className = 'ice-gutter'

+    @lineNumberWrapper = document.createElement 'div'
+    @gutter.appendChild @lineNumberWrapper
+
     @gutterVersion = -1

     @lineNumberTags = {}
@@ -3246,7 +3255,7 @@
     lineDiv.style.fontSize = @fontSize + 'px'
     lineDiv.style.paddingTop = treeView.distanceToBase[line].above - @view.opts.textHeight + 'px'

-    @gutter.appendChild lineDiv
+    @lineNumberWrapper.appendChild lineDiv

   Editor::findLineNumberAtCoordinate = (coord) ->
     treeView = @view.getViewNodeFor @tree


Catch format content errors.

Catch format content errors.

--- app/assets/javascripts/_site.js.coffee
+++ app/assets/javascripts/_site.js.coffee
@@ -165,18 +165,22 @@
     $('[data-behavior~=entry_content_target]').fitVids({ customSelector: "iframe[src*='youtu.be'], iframe[src*='www.flickr.com'], iframe[src*='view.vzaar.com']"});

   formatEntryContent: (entryId, resetScroll=true, readability=true) ->
+    feedbin.applyStarred(entryId)
     if resetScroll
       feedbin.resetScroll
     if readability
       feedbin.readability()
-    feedbin.syntaxHighlight()
-    feedbin.footnotes()
-    feedbin.nextEntryPreview()
-    feedbin.audioVideo()
-    feedbin.localizeTime($('[data-behavior~=entry_content_target]'))
-    feedbin.applyUserTitles()
-    feedbin.applyStarred(entryId)
-    feedbin.fitVids()
+    try
+      feedbin.syntaxHighlight()
+      feedbin.footnotes()
+      feedbin.nextEntryPreview()
+      feedbin.audioVideo()
+      feedbin.localizeTime($('[data-behavior~=entry_content_target]'))
+      feedbin.applyUserTitles()
+      feedbin.fitVids()
+    catch error
+      if 'console' of window
+        console.log error

   refresh: ->
     if feedbin.data


Select all when undoing text change

Select all when undoing text change

--- src/controller.coffee
+++ src/controller.coffee
@@ -369,8 +369,10 @@
               socketStart = @tree.getTokenAtLocation operation.location
               socketStart.socket.content().remove()
               socketStart.insert new model.TextToken operation.before
-
-              moveCursorTo socketStart
+
+              setTextInputFocus socketStart.socket
+              textInputSelectAll()
+
             when 'socketReparse'
               socketStart = @tree.getTokenAtLocation operation.location
               socketStart.append socketStart.socket.end
@@ -797,8 +799,8 @@
       ctrlKeyPressed = false

       @el.addEventListener 'keydown', (event) =>
-        # Keyboard shortcuts don't apply if they were executed in a text input area
-        if event.target.tagName in ['INPUT', 'TEXTAREA'] then return
+        # Keyboard shortcuts don't apply if they were executed in a text input area (except for UNDO)
+        if event.target.tagName in ['INPUT', 'TEXTAREA'] and not (event.keyCode in [17, 90]) then return

         switch event.keyCode
           when 13 then unless @isEditingText() then insertHandwrittenBlock()
@@ -1450,6 +1452,10 @@
         # Focus the hidden input
         setTimeout (=> @hiddenInput.focus()), 0

+      textInputSelectAll = =>
+        textInputAnchor = 0; textInputHead = @focus.stringify().length
+        @hiddenInput.setSelectionRange textInputAnchor, textInputHead
+
       setTextInputHead = (point) =>
         textInputHead = Math.round (point.x - @focus.view.bounds[_editedInputLine].x) / @mainCtx.measureText(' ').width


Correct function name.

Correct function name.

--- app/assets/javascripts/_site.js.coffee
+++ app/assets/javascripts/_site.js.coffee
@@ -254,7 +254,7 @@
       feedbin.readability()
     try
       feedbin.playState()
-      feedbin.playTime(entryId)
+      feedbin.timeRemaining(entryId)
       feedbin.syntaxHighlight()
       feedbin.footnotes()
       feedbin.nextEntryPreview()


Remove stopPropagation in favor of just preventDefault.

--- src/controller.coffee
+++ src/controller.coffee
@@ -260,15 +260,11 @@
         for handler in editorBindings[event.type]
           handler.call this, trackPoint, event, state

-        # Stop mousedown event propagation so that
+        # Stop mousedown event default behavior so that
         # we don't get bad selections
         if event.type is 'mousedown'
-          event.stopPropagation?()
           event.preventDefault?()
-
-          event.cancelBubble = true
           event.returnValue = false
-
           return false

       dispatchKeyEvent = (event) =>


Removed extra console.log.

Removed extra console.log.

--- app/assets/javascripts/_site.js.coffee
+++ app/assets/javascripts/_site.js.coffee
@@ -999,8 +999,6 @@
     hideUpdates: ->
       $(document).on 'click', '[data-behavior~=hide_updates]', (event) ->
         container = $(@).parents('.diff-wrap')
-        console.log 'hideUpdates', event
-        console.log 'feedbin.data.update_message_seen', feedbin.data.update_message_seen
         if feedbin.data.update_message_seen
           container.addClass('hide')
         else


+custom data model stored method

+custom data model stored method

fixed: list active item bug

--- src/controller.coffee
+++ src/controller.coffee
@@ -29,14 +29,13 @@
       when 'object' then value += JSON.stringify val
       else value += val.toString()
     env += "var #{key}=#{value};"
-  return "(function(){#{env}(#{@toString()})()})();"
+  return "#{env}(#{@toString()})();"

 # Application script
 application = ->
   # application object
   app = window.app = {}
   app.callers = {}
-  app.model = {}

   # application events
   app.selector = window.selector = (selname) ->
@@ -46,7 +45,7 @@
     .done -> app.callers[selname](selname) if typeof app.callers[selname] is 'function'

   # get element value or attrible
-  getValue = (elem, name) ->
+  getValue = app.getValue = (elem, name) ->
     switch name.toString().toLowerCase()
       when 'text' then elem.text()
       when 'html' then elem.html()
@@ -54,7 +53,7 @@
       else elem.attr name

   # set element value or attrible
-  setValue = (elem, name, value) ->
+  setValue = app.setValue = (elem, name, value) ->
     switch name.toString().toLowerCase()
       when 'text' then elem.text value
       when 'html' then elem.html value
@@ -62,40 +61,45 @@
       else elem.attr name, value

   # data model
-  model = app.model = (models, selname) ->
+  models = app.models = (model, selname) ->
     # getting data
     get = ->
       data = {}
-      _get = (sets, root) ->
+      _get = (sets) ->
         sets._selname = selname
-        switch sets.base
-          when 'list' then app.model.list.get sets, root
-          else app.model.base.get sets, root
-      for name, sets of models
-        if (typeof sets isnt 'object') or $.isArray sets
-          data = _get models, $('html')
+        sets.base ?= 'base'
+        if (models[sets.base]?) and (typeof models[sets.base].get is 'function')
+          models[sets.base].get sets
+        else models.base.get sets, $('html')
+      for name, sets of model
+        if (typeof sets is 'string') or $.isArray sets
+          data = _get model
           break
-        data[name] = _get sets, $('html')
+        data[name] = _get sets
       JSON.stringify data
+
     # setting data
     set = (data) ->
-      _set = (sets, data, root) ->
+      _set = (sets, data) ->
         sets._selname = selname
-        switch sets.base
-          when 'list' then app.model.list.set sets, data, root
-          else app.model.base.set sets, data, root
-      for name, sets of models
-        if (typeof sets isnt 'object') or $.isArray sets
-          _set models, data, $('html')
+        sets.base ?= 'base'
+        if (models[sets.base]?) and (typeof models[sets.base].get is 'function')
+          models[sets.base].set sets, data
+        else models.base.set sets, data, $('html')
+      for name, sets of model
+        if (typeof sets is 'string') or $.isArray sets
+          _set model, data
           break
-        _set sets, data[name], $('html')
+        _set sets, data[name]
+
     # post event
     $.post "#{location.pathname}?_id=event&_key=data&selector=#{selname}",
       get(), set, 'json'

   # base data model
-  model.base =
+  models.base =
     get: (sets, root) ->
+      root ?= $('html')
       data = {}
       sets = sets.entry if sets.entry
       for id, attrs of sets
@@ -106,6 +110,7 @@
       return data

     set: (sets, data, root) ->
+      root ?= $('html')
       sets = sets.entry if sets.entry
       for id, attrs of sets
         elem = root.find '#' + id
@@ -114,7 +119,7 @@
         else setValue elem, attr, data[id][attr] for attr in attrs

   # list data model
-  model.list =
+  models.list =
     actived: (sets) ->
       root = $ '#' + sets.root
       temp = "[style*='#{sets.active.style}']"
@@ -138,19 +143,20 @@

     get: (sets) ->
       data = {}
+      actived = models.list.actived sets
       switch sets.method.toLowerCase()
         when 'remove'
-          actived = model.list.actived sets
-          data = model.base.get sets.entry, actived if sets.entry
+          data = models.base.get sets.entry, actived
           data._id = actived.attr 'id'
         when 'active'
-          target = model.list.target sets
-          data = model.base.get sets.entry, target
+          target = actived
+          target = models.list.target sets unless sets.active.index? and actived.length > 0
+          data = models.base.get sets.entry, target
           data._id = target.attr 'id'
       return data

     set: (sets, data) ->
-      actived = model.list.actived sets
+      actived = models.list.actived sets
       method = sets.method.toLowerCase()
       switch method
         when 'add', 'insert'
@@ -171,11 +177,12 @@
             if (actived.index() < 0) or (method is 'add') then root.append entry
             else entry.insertBefore actived
           unless template.attr('id') then template.remove()
+
         when 'active'
           return if sets.active.index? and actived.length > 0
           root = $ '#' + sets.root
-          target = model.list.target sets
-          model.base.set sets, data, target
+          target = models.list.target sets
+          models.base.set sets, data, target
           # active style
           if sets.active.class
             root.children().removeClass sets.active.class
@@ -186,6 +193,7 @@
             root.children().attr 'style', style
             style = if target.attr 'style' then target.attr 'style' else ''
             target.attr 'style', "#{style};#{sets.active.style};"
+
         when 'blur', 'remove'
           root = $ '#' + sets.root
           if sets.active.class
@@ -195,7 +203,7 @@
             style = if template.attr 'style' then template.attr 'style' else ''
             root.children().attr 'style', style
           # remove actived item
-          actived.remove() if (method is 'remove') and (actived.index() > -1 )
+          actived.remove() if (method is 'remove') and (actived.index() > -1)

   # getting user event
   window.constructor::__defineGetter__ 'event', ->
@@ -304,20 +312,19 @@

   # User date model
   model: (models) ->
-    return @handle (-> app.model models, selname), models: models
-    # user template
-    if (typeof template is 'object') and (template isnt null)
-      model = template
-      template = 'base'
-    # data model
-    if (typeof model is 'object') and (model isnt null) and (!util.isArray model)
-      return if @query._key isnt 'script'
-      # user template
-      if typeof template is 'function'
-        @handle (-> func model, selname), func: template, model: model
-      # template library
-      else
-        @handle (-> app.model model, selname), key: template, model: model
+    return if @data
+    # custom data model stored method
+    stored = (sets, name) =>
+      if sets.base and (sets.base.get or sets.base.set)
+        name = "#{name}#{@uid()}"
+        base = ''
+        base += "app.models.#{name}.#{key}=#{func.toString()};" for key, func of sets.base
+        @_script += "app.models.#{name}={};#{base}"
+        sets.base = name
+    if models.base then stored models, 'func'
+    else stored sets, name for name, sets of models
+    # send data model to client
+    @handle (-> app.models models, selname), models: models

   # Respond client
   do: (req, @_buffer) ->


Fixed naming of xaxis.

Fixed naming of xaxis.

--- app/assets/javascripts/app/controllers/report.js.coffee
+++ app/assets/javascripts/app/controllers/report.js.coffee
@@ -157,14 +157,14 @@
         xaxis.push [minute, '']
     else if @params.timeRange is 'day'
       for hour in [0..23]
-        xaxis.push [hour, hour]
+        xaxis.push [hour, hour+1]
     else if @params.timeRange is 'month'
-      for day in [1..31]
-        xaxis.push [day, day]
+      for day in [0..30]
+        xaxis.push [day, day+1]
     else if @params.timeRange is 'week'
-      xaxis = [[1, 'Mon'], [2, 'Tue'], [3, 'Wed'], [4, 'Thr'], [5, 'Fri'], [6, 'Sat'], [7, 'Sun'] ]
+      xaxis = [[0, 'Mon'], [1, 'Tue'], [2, 'Wed'], [3, 'Thr'], [4, 'Fri'], [5, 'Sat'], [6, 'Sun'] ]
     else
-      xaxis = [[1, 'Jan'], [2, 'Feb'], [3, 'Mar'], [4, 'Apr'], [5, 'Mai'], [6, 'Jun'], [7, 'Jul'], [8, 'Aug'], [9, 'Sep'], [10, 'Oct'], [11, 'Nov'], [12, 'Dec']]
+      xaxis = [[0, 'Jan'], [1, 'Feb'], [2, 'Mar'], [3, 'Apr'], [4, 'Mai'], [5, 'Jun'], [6, 'Jul'], [7, 'Aug'], [8, 'Sep'], [9, 'Oct'], [10, 'Nov'], [11, 'Dec']]

     dataPlot = []
     for key, value of data


Corrige bug onde estava mostrando meses a partir de Fevereiro

--- app/assets/javascripts/graph.js.coffee
+++ app/assets/javascripts/graph.js.coffee
@@ -11,19 +11,17 @@
          window.testdata = testdata
          chart = nv.models.multiChart()
                .margin({top: 30, right: 60, bottom: 50, left: 70})
-               .x((d,i) -> i)
+               .x((d,i) -> d.x)
                .color(d3.scale.category10().range())

          chart.xAxis.tickFormat((d) ->
-           dx = testdata[0].values[d] && testdata[0].values[d].x || 0
+           index = d - 1
+           dx = testdata[0].values[index] && testdata[0].values[index].x
            d3.time.format('%b')(new Date(dx))
          )

          chart.yAxis1.showMaxMin(false)
              .tickFormat(d3.format(',s.2'))
-
-         chart.yAxis2.showMaxMin(false)
-             .tickFormat((d) -> '$' + d3.format(',f')(d))

          d3.select('.graph svg')
              .datum(testdata)


msg cuando llega fichero

msg cuando llega fichero

--- app/assets/javascripts/myrtc.js.coffee
+++ app/assets/javascripts/myrtc.js.coffee
@@ -19,7 +19,7 @@
   chatOutput = document.getElementById('chat-output')
   chatInput = document.getElementById('chat-input')
   div = document.createElement('div')
-  div.innerHTML = '
anon: '+data+'
'
+  div.innerHTML = '
'+user+': '+data+'
'
   chatOutput.insertBefore(div, chatOutput.firstChild)
   div.tabIndex = 0
   div.focus()
@@ -55,6 +55,7 @@
       connection.onFileSent = (file) ->
         console.log(file)
       connection.onFileReceived = (filename) ->
+        appendDIV('Te llegó un fichero', 'bot')
         console.log(filename)
       document.getElementById('file').onchange = ->
         connection.send(this.files[0])


New Files: Makes moving and deleting work in search results

fixes CNVS-17008

Test Plan:
	- Search for something in New Files
	- Use the Gear Menu to delete a file
	- It should delete
	- Use the Gear Menu to move a file
	- It should move

Change-Id: I2357be398a0885a1aeab3e70c4ebfdf73c3c326f
Reviewed-on: https://gerrit.instructure.com/44682
Reviewed-by: Ryan Shaw <ea3cd978650417470535f3a4725b6b5042a6ab59@instructure.com>
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
QA-Review: Jahnavi Yetukuri <ed2b2672ccc2e59e56c0615df7f01b579202e014@instructure.com>
Product-Review: Clay Diffrient <9dff2e5c98626d20d2848250c411e8009465bb87@instructure.com>

--- app/coffeescripts/react_files/components/ItemCog.coffee
+++ app/coffeescripts/react_files/components/ItemCog.coffee
@@ -4,6 +4,7 @@
   'compiled/react/shared/utils/withReactDOM'
   'compiled/fn/preventDefault'
   '../modules/customPropTypes'
+  '../modules/filesEnv'
   'compiled/models/Folder'
   './RestrictedDialogForm'
   '../utils/openMoveDialog'
@@ -11,7 +12,7 @@
   '../utils/deleteStuff'
   'jquery'
   'jqueryui/dialog'
-], (I18n, React, withReactDOM, preventDefault, customPropTypes, Folder, RestrictedDialogForm, openMoveDialog, downloadStuffAsAZip, deleteStuff, $) ->
+], (I18n, React, withReactDOM, preventDefault, customPropTypes, filesEnv, Folder, RestrictedDialogForm, openMoveDialog, downloadStuffAsAZip, deleteStuff, $) ->

   ItemCog = React.createClass
     displayName: 'ItemCog'
@@ -19,13 +20,16 @@
     propTypes:
       model: customPropTypes.filesystemObject

-
     render: withReactDOM ->
       wrap = (fn) =>
-        preventDefault (event)=>
+        preventDefault (event) =>
+          singularContextType = @props.model.collection?.parentFolder?.get('context_type').toLowerCase()
+          pluralContextType = singularContextType + 's' if singularContextType?
+          contextType = pluralContextType || filesEnv.contextType
+          contextId = @props.model.collection?.parentFolder?.get('context_id') || filesEnv.contextId
           fn([@props.model], {
-            contextType: @props.model.collection?.parentFolder.get('context_type').toLowerCase() + 's'
-            contextId: @props.model.collection?.parentFolder.get('context_id')
+            contextType: contextType
+            contextId: contextId
             returnFocusTo: event.target
           })


Fix background source url

Fix background source url

--- app/assets/javascripts/timer.js.coffee
+++ app/assets/javascripts/timer.js.coffee
@@ -131,6 +131,7 @@
     return if $('#backimg_front').length == 0
     self.background(
       image_url: self.image_url
+      image_source: self.image_source
       image_illustrator: self.image_illustrator
       by_system: true
     ).always ->


OX-135 adjusted range of routeClippingDistance, one voxel now possible

--- app/assets/javascripts/view/gui.coffee
+++ app/assets/javascripts/view/gui.coffee
@@ -115,7 +115,7 @@
                           .step(0.25)
                           .name("Move Value")
                           .onChange(@setMoveValue)
-    (fView.add @settings, "routeClippingDistance", 1, 500)
+    (fView.add @settings, "routeClippingDistance", 0.1, 200)
                           .name("Clipping Distance")
                           .onChange(@setRouteClippingDistance)
     (fView.add @settings, "displayCrosshairs")


toggles layer on votes via js

toggles layer on votes via js

--- app/assets/javascripts/votes.js.coffee
+++ app/assets/javascripts/votes.js.coffee
@@ -2,9 +2,11 @@

   hoverize: (votes) ->
     $(votes).hover ->
-      $("div.not-logged", votes).show()
+      $("div.anonymous-votes", votes).show();
+      $("div.not-logged", votes).show();
     , ->
-      $("div.not-logged", votes).hide()
+      $("div.anonymous-votes", votes).hide();
+      $("div.not-logged", votes).hide();

   initialize: ->
     App.Votes.hoverize votes for votes in $("div.votes")


Fixed custom middleware coming after our middleware

--- src/lib/docpad.coffee
+++ src/lib/docpad.coffee
@@ -2887,30 +2887,36 @@
 				serverExpress.use(express.bodyParser())  if opts.middlewareBodyParser isnt false
 				serverExpress.use(express.methodOverride())  if opts.middlewareMethodOverride isnt false

-				# DocPad Header Middleware
-				serverExpress.use(docpad.serverMiddlewareHeader)
-
-				# Router Middleware
-				serverExpress.use(serverExpress.router)  if opts.middlewareExpressRouter isnt false
-
 				# Emit the serverExtend event
 				# So plugins can define their routes earlier than the DocPad routes
 				docpad.emitSync 'serverExtend', {server:serverExpress,serverExpress,serverHttp,express}, (err) ->
 					return next(err)  if err

+					# DocPad Header Middleware
+					# Keep it before the serverExtend event
+					serverExpress.use(docpad.serverMiddlewareHeader)
+
+					# Router Middleware
+					# Keep it before the serverExtend event
+					serverExpress.use(serverExpress.router)  if opts.middlewareExpressRouter isnt false
+
 					# DocPad Router Middleware
+					# Keep it before the serverExtend event
 					serverExpress.use(docpad.serverMiddlewareRouter)

 					# Static
+					# Keep it before the serverExtend event
 					if config.maxAge
 						serverExpress.use(express.static(config.outPath,{maxAge:config.maxAge}))
 					else
 						serverExpress.use(express.static(config.outPath))

 					# DocPad 404 Middleware
+					# Keep it before the serverExtend event
 					serverExpress.use(docpad.serverMiddleware404)  if opts.middleware404 isnt false

 					# DocPad 500 Middleware
+					# Keep it before the serverExtend event
 					serverExpress.error(docpad.serverMiddleware500)  if opts.middleware500 isnt false

 				# Start the Server


Init filesByUrl correctly with configredo

--- src/lib/docpad.coffee
+++ src/lib/docpad.coffee
@@ -923,6 +923,7 @@
 		@exchange = {}
 		@pluginsTemplateData = {}
 		@instanceConfig = {}
+		@filesByUrl = {}
 		@locales = balUtil.dereference(@locales)
 		@userConfig = balUtil.dereference(@userConfig)
 		@initialConfig = balUtil.dereference(@initialConfig)


removed unnecessary notify var

removed unnecessary notify var

--- src/lib/docpad.coffee
+++ src/lib/docpad.coffee
@@ -1824,7 +1824,6 @@

 		# Prepare
 		docpad = @
-		notify = @notify

 		# Check
 		balUtil.packageCompare


If it's not documented it doesn't exist.

--- app/frontend/scripts/helpers.js.coffee
+++ app/frontend/scripts/helpers.js.coffee
@@ -64,6 +64,10 @@

 # Queue or unqueue a song
 #
+# id     - The ID of the song
+# queued - The Boolean value of whether this song should be queued or not.
+#          'true' means Add to Queue, 'false' means Remove from Queue
+#
 play.queue = (id, queued) ->
   song = new Song({
     id: id


Store name after computing

Store name after computing

--- src/ls-archive.coffee
+++ src/ls-archive.coffee
@@ -31,7 +31,7 @@
     @isDirectory() and entry.getPath().indexOf("#{@getPath()}/") is 0

   getPath: -> @path
-  getName: -> path.basename(@path)
+  getName: -> @name ?= path.basename(@path)
   isFile: -> @type is 0
   isDirectory: -> @type is 5
   isSymbolicLink: -> @type is 2


ComputeProvider: update: revive client and pass credential

--- workers/social/lib/social/models/computeproviders/computeprovider.coffee
+++ workers/social/lib/social/models/computeproviders/computeprovider.coffee
@@ -168,7 +168,12 @@
     provider.fetchPlans client, options, callback

-  @update = secure revive no, (client, options, callback)->
+  @update = secure revive
+
+    shouldReviveClient   : yes
+    shouldPassCredential : yes
+
+  , (client, options, callback)->

     {provider} = options
     provider.update client, options, callback


* use class name to check whether inheritsFrom

--- src/nosql-encoding.coffee
+++ src/nosql-encoding.coffee
@@ -4,7 +4,7 @@
 AbstractNoSQL         = require("abstract-nosql")
 Codec                 = require("buffer-codec")
 EncodingIterator      = require("encoding-iterator")
-AbstractIterator      = EncodingIterator.super_
+#AbstractIterator      = EncodingIterator.super_
 inherits              = require("abstract-object/lib/util/inherits")
 isInheritedFrom       = require("abstract-object/lib/util/isInheritedFrom")
 inheritsDirectly      = require("abstract-object/lib/util/inheritsDirectly")
@@ -18,14 +18,15 @@

   constructor: (aClass)->
     if (this not instanceof EncodingNoSQL)
-      vParentClass = isInheritedFrom aClass, AbstractNoSQL
+      if isInheritedFrom aClass, 'EncodingNoSQL'
+        throw new InvalidArgumentError("class has already been encoding-able")
+      vParentClass = isInheritedFrom aClass, 'AbstractNoSQL'
       if vParentClass
-        if vParentClass isnt EncodingNoSQL
-          inheritsDirectly vParentClass, EncodingNoSQL
-          vIteratorClass = aClass::IteratorClass
-          vIteratorClass = isInheritedFrom vIteratorClass, AbstractIterator if vIteratorClass
-          if vIteratorClass and vIteratorClass isnt EncodingIterator
-            inheritsDirectly vIteratorClass, EncodingIterator
+        inheritsDirectly vParentClass, EncodingNoSQL
+        vIteratorClass = aClass::IteratorClass
+        if vIteratorClass and not isInheritedFrom vIteratorClass, 'EncodingIterator'
+          vIteratorClass = isInheritedFrom vIteratorClass, 'AbstractIterator'
+          inheritsDirectly vIteratorClass, EncodingIterator if vIteratorClass
         return aClass
       else
         throw new InvalidArgumentError("class should be inherited from AbstractNoSQL")


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_levels.coffee
+++ src/engine_levels.coffee
@@ -28,4 +28,5 @@
     #TODO Handle integer levels?
     loadLevel level

-  reloadLevel: () +  reloadLevel: ->
+    loadLevel


Use HTTPS

Use HTTPS

--- src/js/ogl-browse.coffee
+++ src/js/ogl-browse.coffee
@@ -30,7 +30,7 @@
   loader = ($('<div>').attr('class','ui active mini loader'))
   repo_li.append(loader)

-  $.ajax "http://openlibrary.org/ia/#{identifier}.json",
+  $.ajax "https://openlibrary.org/ia/#{identifier}.json",
     type: 'GET'
     dataType: 'json'
     crossDomain: 'true'


Set up environment variable to hold Kato "All" room HTTP POST URL.

--- src/kato-http-api.coffee
+++ src/kato-http-api.coffee
@@ -8,7 +8,7 @@
 #   None
 #
 # Commands:
-#   Emit event "kato-http-message" from your script, after setting room name-id matches in Hubot's brain with
+#   Emit event "kato-http-message" from your script, after setting Kato "All" room URL in environment variables.
 #
 #
 # Notes:
@@ -18,27 +18,26 @@
 #   ocean

 module.exports = (robot) ->
+
+  config = secrets:
+    katoRoomURL: process.env.HUBOT_KATO_ALL_ROOM_HTTP_POST_URL
+
   robot.on 'kato-http-post', (kato-http-post) ->
     sendMessage kato-http-post
-
-  robot.brain.data.kato-http-api.rooms or= {}
-
+
   sendMessage = (message) ->

     data = JSON.stringify({
-      room: message.room || 'all',
       text: message.text,
       from: message.from || robot.name,
       color: message.color || 'grey',
       renderer: 'markdown'
     })

-    roomURL = robot.brain.data.kato-http-api.rooms[data.room]
-
-    robot.http(roomURL)
+    robot.http(config.secrets.katoRoomURL)
       .header('Content-Type', 'application/json')
       .post(data) (err, res, body) ->
         if err
           robot.emit 'error', err, res, body
           return
-        robot.emit res, body+        robot.emit res, body


Tweak enabling a few more use cases...

Tweak enabling a few more use cases...

--- src/language-mode.coffee
+++ src/language-mode.coffee
@@ -262,14 +262,15 @@
       return currentIndentLevel if precedingRow < 0

     desiredIndentLevel = @editor.indentationForBufferRow(precedingRow)
-    return desiredIndentLevel if @buffer.isRowBlank(precedingRow)

     unless @editor.isBufferRowCommented(precedingRow)
       precedingLine = @buffer.lineForRow(precedingRow)
       desiredIndentLevel += 1 if increaseIndentRegex?.testSync(precedingLine)
       desiredIndentLevel -= 1 if decreaseNextIndentRegex?.testSync(precedingLine)

-    desiredIndentLevel -= 1 if decreaseIndentRegex?.testSync(line)
+    unless @buffer.isRowBlank(precedingRow)
+      desiredIndentLevel -= 1 if decreaseIndentRegex?.testSync(line)
+
     Math.max(desiredIndentLevel, 0)

   # Calculate a minimum indent level for a range of lines excluding empty lines.


fixes #68

fixes #68

--- src/loader/loader.coffee
+++ src/loader/loader.coffee
@@ -278,11 +278,13 @@
         return localforage.setItem(key, content, cb)

     get_contents_keys: (cb) ->
-        localforage.keys (err, keys) =>
-            return console.error(err) if err?
+        localforage.keys()
+            .then (keys) =>
             for key in keys
                 cb(key)
             return
+            .catch (err) =>
+                return console.error(err)
         return

     del_content: (key, cb) ->
@@ -322,7 +324,7 @@

         unless @emit("EvaluationStarted", @_current_manifest) is false
             @evaluate(@_current_manifest.modules)
-            @_cleanUp()
+                .then => @_cleanUp()

         return

@@ -334,10 +336,8 @@

         module = queue.shift()
         key = @make_key(module)
-        @get_content key, (err, module_source) =>
-            if err?
-                @emit("EvaluationError", module, new DBError(module.url, err))
-                return
+        return @get_content(key)
+            .then (module_source) =>

             unless module_source?
                 @emit("EvaluationError", module, new NoSourceError(module.url))
@@ -371,7 +371,10 @@

             @emit("ModuleEvaluated", module)

-            @evaluate(queue)
+                return @evaluate(queue)
+            .catch (err) =>
+                @emit("EvaluationError", module, new DBError(module.url, err))
+                return

     checkUpdate: () ->
         return if @_update_started
@@ -420,8 +423,8 @@

     _updateModule: (module) ->
         key = @make_key(module)
-        @get_content key, (err, module_source) =>
-            return @_downloadModule(module) if err?
+        @get_content(key)
+            .then (module_source) =>
             return @_downloadModule(module) unless module_source?

             if @hash_func(module_source) != module.hash
@@ -433,6 +436,8 @@
             @_reportTotalProgress()
             @_checkAllUpdated()
             return
+            .catch (err) =>
+                return @_downloadModule(module)
         return

     _reportTotalProgress: ->
@@ -463,15 +468,18 @@
             if @hash_func(module_source) != module.hash
                 @emit("ModuleDownloadFailed", event, module)
                 return
-            @set_content @make_key(module), module_source, (err, content) =>
-                if err?
-                    @emit("ModuleDownloadFailed", null, module, new DBError(module.url, err))
-                    return
+            @set_content(@make_key(module), module_source)
+                .then (content) =>
                 module.source = module_source
                 module.loaded = module.size
                 @emit("ModuleDownloaded", module)
                 @_reportTotalProgress()
                 @_checkAllUpdated()
+                    return
+                .catch (err) =>
+                    @emit("ModuleDownloadFailed", null, module, new DBError(module.url, err))
+                    return
+
         module_request.onprogress = (event) =>
             module.loaded = event.loaded
             @emit("ModuleDownloadProgress", event, module)
@@ -506,7 +514,7 @@
             return unless key? # wierd error
             return unless key.indexOf(@prefix) is 0
             return if key in useful
-            @del_content key, (error) =>
-                @logger.error(error)
+            @del_content(key)
+                .catch (error) => @logger.error(error)
             return
         return


Use a workflow id from the workflowStore to create new classifications

--- app/stores/classification-store.coffee
+++ app/stores/classification-store.coffee
@@ -31,7 +31,7 @@
         utc_offset: ((new Date).getTimezoneOffset() * 60).toString()
       links:
         project: config.projectId
-        workflow: config.workflowId
+        workflow: workflowStore.data.id
         subjects: [subjectStore.subject.id]

     @trigger @data


Formatting updates

Formatting updates

--- src/pushbullet.coffee
+++ src/pushbullet.coffee
@@ -31,4 +31,4 @@
     pushbullet.history options, (err, res) ->
       if not err
         push = res.pushes[0]
-        msg.send "Last push was from #{push.sender_name}"
+        msg.send "Last push was \"#{push.}\" from #{push.sender_name}"


:lipstick:

:lipstick:

--- lib/file-info-view.coffee
+++ lib/file-info-view.coffee
@@ -34,7 +34,6 @@
       trigger: 'click'
       delay:
         show: 0
-

   subscribeToActiveItem: ->
     @modifiedSubscription?.dispose()


Remove posting to twitter through API

Remove posting to twitter through API

--- src/share/base.coffee
+++ src/share/base.coffee
@@ -47,7 +47,7 @@
     params = opts.params
     params.url ||= window.location.href

-    return Hull.api({ provider:'twitter', path: "/api/v1/services/twitter/#{opts.method}"},'post',params) if hasIdentity('twitter') and not opts.anonymous
+    # return Hull.api({ provider:'twitter', path: "/api/v1/services/twitter/#{opts.method}"},'post',params) if hasIdentity('twitter') and not opts.anonymous

     querystring = to_qs(params)
     url = "https://twitter.com/intent/tweet?#{querystring}"


Upgrade git-run

Upgrade git-run

--- lib/models/git-run.coffee
+++ lib/models/git-run.coffee
@@ -1,21 +1,22 @@
-{$, EditorView, View} = require 'atom'
+{$, TextEditorView, View} = require 'atom-space-pen-views'

 git = require '../git'
 StatusView = require '../views/status-view'

 class InputView extends View
   @content: ->
-    @div class: 'overlay from-top', =>
-      @subview 'commandEditor', new EditorView(mini: true, placeHolderText: 'Git command and arguments')
+    @div =>
+      @subview 'commandEditor', new TextEditorView(mini: true, placeHolderText: 'Git command and arguments')

   initialize: ->
     @currentPane = atom.workspace.getActivePane()
-    atom.workspaceView.append this
+    @panel ?= atom.workspace.addModalPanel(item: this)
+    @panel.show()
     @commandEditor.focus()
-    @on 'core:cancel', => @detach()
+    @on 'core:cancel', => @panel.destroy()
     @commandEditor.on 'core:confirm', =>
-      @detach()
-      args = $(this).text().split(' ')
+      @panel.destroy()
+      args = @commandEditor.getText().split(' ')
       if args[0] is 1 then args.shift()
       git.cmd
         args: args


поддержка YAML конфигов

поддержка YAML конфигов

--- lib/nbuild/builder.coffee
+++ lib/nbuild/builder.coffee
@@ -13,10 +13,12 @@
 _             = require 'underscore'
 path          = require 'path'
 CSON          = require 'CSON'
+YAML        = require 'js-yaml'
 {deepExtend}  = require './helpers'

 {normalize, basename, dirname, extname, join, existsSync, relative} = path

+YAML_REGEX        = /^\s*#YAML/i
 CSON_REGEX        = /^\s*#CSON/i
 VARIABLE_REGEX    = /\$\(([\S]+?)\)/g
 JSON_CMD_REGEX    = /^\$json\(([\S]+?)\)$/i
@@ -148,7 +150,10 @@
       data  = fs.readFileSync(configFile, 'utf-8')
       parse = {}
       try
-        if CSON_REGEX.test(data)
+        if YAML_REGEX.test(data)
+          parse = YAML.load(data)
+          console.log parse
+        else if CSON_REGEX.test(data)
           parse = CSON.parse(data)
         else
           parse = JSON.parse(data)


Change provider to take minimumWordLength into account

--- lib/paths-provider.coffee
+++ lib/paths-provider.coffee
@@ -18,7 +18,8 @@
     return [] unless basePath?

     prefix = @prefixForCursor(options.editor, options.buffer, options.cursor, options.position)
-    return [] unless prefix.length
+
+    return [] unless prefix.length > atom.config.get('autocomplete-plus.minimumWordLength')

     suggestions = @findSuggestionsForPrefix(options.editor, basePath, prefix)
     return [] unless suggestions.length


Removed unused code

Removed unused code

--- packages/rocketchat-ui/lib/RoomHistoryManager.coffee
+++ packages/rocketchat-ui/lib/RoomHistoryManager.coffee
@@ -155,10 +155,8 @@

 		return room.hasMore.get()

-	hasMoreNext = (rid, override) ->
+	hasMoreNext = (rid) ->
 		room = getRoom rid
-		if override?
-			room.hasMoreNext.set(override)
 		return room.hasMoreNext.get()

@@ -169,10 +167,8 @@
 			getMore rid

-	isLoading = (rid, override) ->
+	isLoading = (rid) ->
 		room = getRoom rid
-		if override?
-			room.isLoading.set(override)
 		return room.isLoading.get()

 	clear = (rid) ->


Wrap div in a pre

Wrap div in a pre

--- src/highlights.coffee
+++ src/highlights.coffee
@@ -16,8 +16,9 @@
   #   :scopeName    - An optional String scope name of a grammar. The best match
   #                   grammar will be used if this is unspecified.
   #
-  # Returns a String of HTML. The HTML will contains one
 per line and each
-  # line will contain one or more  elements for the tokens in the line.
+  # Returns a String of HTML. The HTML will contains one
 with one

+  # per line and each line will contain one or more  elements for the
+  # tokens in the line.
   highlightSync: ({filePath, fileContents, scopeName}={}) ->
     fileContents ?= fs.readFileSync(filePath, 'utf8') if filePath
     grammar = @registry.grammarForScopeName(scopeName)
@@ -30,7 +31,7 @@
       if lastLineTokens.length is 1 and lastLineTokens[0].value is ''
         lineTokens.pop()

-    html = ''
+    html = '
'
     for tokens in lineTokens
       scopeStack = []
       html += '
'
@@ -40,6 +41,7 @@
         html += "#{@escapeString(value)}"

       html += '
'
+    html += '
'
     html

   escapeString: (string) ->


support bundled scripts

support bundled scripts


Fixed regression issue in array detection.

--- lib/typeresolution.coffee
+++ lib/typeresolution.coffee
@@ -44,7 +44,7 @@

 # Helps to identify whether given node is an implicit array.
 hasMultipleValues = (node) ->
-  !!node.valueDefinition?.values?.length
+  (node.valueDefinition?.values?.length or 0) > 1

 # Helps to identify whether given node is an implicit object.


Add serialization version to TextBuffer

Add serialization version to TextBuffer

--- src/app/text-buffer.coffee
+++ src/app/text-buffer.coffee
@@ -15,7 +15,8 @@
 module.exports =
 class TextBuffer
   @acceptsDocuments: true
-  @idCounter = 1
+  @version: 1
+  @idCounter: 1
   registerDeserializer(this)

   @deserialize: (state) ->


Added TLS support for MLLP routes.

Added TLS support for MLLP routes.

--- src/middleware/router.coffee
+++ src/middleware/router.coffee
@@ -152,12 +152,9 @@
     handleServerError ctx, reason

 sendRequest = (ctx, route, options) ->
-  if route.type is 'tcp'
-    logger.info 'Routing tcp request'
+  if route.type is 'tcp' or 'mllp'
+    logger.info 'Routing socket request'
     return sendSocketRequest ctx, route, options
-  else if route.type is 'mllp'
-    logger.info 'Routing mllp request'
-    return sendMLLPSocketRequest ctx, route, options
   else
     logger.info 'Routing http(s) request'
     return sendHttpRequest ctx, route, options
@@ -259,8 +256,12 @@
 #    status: <200 if all work, else 500>
 #    body: <the received data from the socket>
 #    timestamp: <the time the response was recieved>
+#
+# Supports both normal and MLLP sockets
 ###
 sendSocketRequest = (ctx, route, options) ->
+  mllpEndChar = String.fromCharCode(0o034)
+
   defered = Q.defer()
   requestBody = ctx.body
   response = {}
@@ -281,16 +282,26 @@
     options.ca = route.cert

   client = method.connect options, ->
-    logger.info "Opened tcp connection to #{options.host}:#{options.port}"
-    client.end requestBody
+    logger.info "Opened #{route.type} connection to #{options.host}:#{options.port}"
+    if route.type is 'tcp'
+      client.end requestBody
+    else if route.type is 'mllp'
+      client.write requestBody
+    else
+      logger.error "Unkown route type #{route.type}"

   bufs = []
   client.on 'data', (chunk) ->
     bufs.push chunk
+    if route.type is 'mllp' and chunk.toString().indexOf(mllpEndChar) > -1
+      logger.debug 'Received MLLP response end character'
+      client.end()

   client.on 'error', (err) -> defered.reject err

   client.on 'end', ->
+    logger.info "Closed #{route.type} connection to #{options.host}:#{options.port}"
+
     if route.secured and not client.authorized
       return defered.reject new Error 'Client authorization failed'
     response.body = Buffer.concat bufs
@@ -301,50 +312,6 @@

   return defered.promise

-###
-# A promise returning function that send a request to the given route using sockets and resolves
-# the returned promise with a response object of the following form: ()
-#   response =
-#    status: <200 if all work, else 500>
-#    body: <the received data from the socket>
-#    timestamp: <the time the response was recieved>
-###
-sendMLLPSocketRequest = (ctx, route, options) ->
-
-  endChar = `String.fromCharCode(034)`
-  defered = Q.defer()
-  requestBody = ctx.body
-  client = new net.Socket()
-  response = {}
-
-  client.connect options.port, options.hostname, ->
-    logger.info "Opened mllp connection to #{options.hostname}:#{options.port}"
-
-  client.on 'connect', ()->
-    client.write requestBody
-
-  bufs = []
-  client.on 'data', (chunk) ->
-    bufs.push chunk
-    n = chunk.toString().indexOf(endChar)
-    if n > -1
-      logger.info 'Received response end character'
-      response.body = Buffer.concat bufs
-      response.status = status.OK
-      response.timestamp = new Date()
-      if not defered.promise.isRejected()
-        defered.resolve response
-        client.end()
-
-
-  client.on 'error', (err) -> defered.reject err
-
-  client.on 'end', ->
-    logger.info "Closed mllp connection to #{options.hostname}:#{options.port}"
-
-  return defered.promise
-
-
 getDestinationPath = (route, requestPath) ->
   if route.path
     route.path


Fixes #17

Fixes #17

--- web/scripts/referenceUI.coffee
+++ web/scripts/referenceUI.coffee
@@ -69,10 +69,7 @@

     $(dictionary).css({width:'35%',height:'90%',position:'absolute',left:'5%',top:'5%',bottom:'80%','border':'1px solid black'})
     $(input).css({width:'50%',height:'40%',position:'absolute',right:'5%',top:'5%','border':'1px solid black'})
-    $(output).css(
-        {width:'50%',height:'40%',position:'absolute',
-        right:'5%',top:'50%','border':'1px solid black',
-        "overflow":"auto"})
+    $(output).css({width:'50%',height:'45%',position:'absolute',right:'5%',top:'50%','border':'1px solid black',"overflow":"auto"})

     $(refContainer).prepend(dictionary)
     $(refContainer).prepend(input)
@@ -124,7 +121,7 @@

         $(dictionary).animate({width:'35%',height:'90%',opacity:'1'})
         $(input).animate({width:'50%',height:'40%',opacity:'1'})
-        $(output).animate({width:'50%',height:'45%',opacity:'1',top:'50%'})
+        $(output).animate({width:'50%',height:'40%',opacity:'1',top:'50%'})

         $(".en").hover(enHover,lvHover)
         $(".en").click(enClick)


release-script

release-script

--- webpack/scripts/release.coffee
+++ webpack/scripts/release.coffee
@@ -37,7 +37,6 @@
   msg = ":robot: bleep bloop; this is your friendly neighborhood build bot announcing [#{build}](https://github.com/retorquere/zotero-better-bibtex/releases/download/builds/zotero-better-bibtex-#{version}.xpi)#{reason}."
   console.log(msg)

-  return
   try
     yield github({
       uri: "/issues/#{issue}/comments"
@@ -85,7 +84,7 @@
       }
     })

-    console.log("uploading #{xpi} to #{release.current.name}")
+    console.log("uploading #{xpi} to #{release.current.tag_name}")
     yield github.upload({
       release: release.current,
       name: xpi,
@@ -99,8 +98,6 @@
       path: path.resolve(__dirname, '../../gen/update.rdf')
       content_type: 'application/rdf+xml'
     })
-
-    # yield release.builds.upload(xpi, 'application/x-xpinstall', fs.readFileSync(path.join(build_root, "xpi/#{xpi}")))

     yield announce(555) # TODO: remove after release


Edited isNaN check in fullpie.coffee

Edited isNaN check in fullpie.coffee

--- widgets/fullpie/fullpie.coffee
+++ widgets/fullpie/fullpie.coffee
@@ -48,9 +48,26 @@
     for val in data
       sum += val.value

+    arcs.append("svg:text").attr("transform", (d, i) ->
+      procent_val = Math.round(data[i].value/sum * 100)
+      d.innerRadius = (radius * (100-procent_val)/100) - 45  #45=max text size/2
+      d.outerRadius = radius
+      "translate(" + arc.centroid(d) + ")")
+      .attr('fill', "#fff")
+      .attr("text-anchor", "middle").text((d, i) -> data[i].label).attr('font-size', '28px')
+      .append('svg:tspan')
+      .attr('x', 0)
+      .attr('dy', 25)
+      .attr('font-size', '90%')
+      .text((d,i) -> data[i].value + ' (' + Math.round(data[i].value/sum * 100) + '%)')
+
 #    arcs.append("svg:text").attr("transform", (d, i) ->
-#      procent_val = Math.round(data[i].value/sum * 100)
-#      d.innerRadius = (radius * (100-procent_val)/100) - 45  #45=max text size/2
+#      percent_val = Math.round(data[i].value/sum * 100)
+#	  if (_.isNan(percent_val))
+#		percent_val = 0
+#	  if (_.isNan(data[i].value))
+#	    data[i].val = 0
+#      d.innerRadius = (radius * (100-percent_val)/100) - 45  #45=max text size/2
 #      d.outerRadius = radius
 #      "translate(" + arc.centroid(d) + ")")
 #      .attr('fill', "#fff")
@@ -59,21 +76,4 @@
 #      .attr('x', 0)
 #      .attr('dy', 25)
 #      .attr('font-size', '90%')
-#      .text((d,i) -> data[i].value + ' (' + Math.round(data[i].value/sum * 100) + '%)')
-
-    arcs.append("svg:text").attr("transform", (d, i) ->
-      percent_val = Math.round(data[i].value/sum * 100)
-	  if (_.isNan(percent_val))
-		percent_val = 0
-	  if (_.isNan(data[i].value))
-	    data[i].val = 0
-      d.innerRadius = (radius * (100-percent_val)/100) - 45  #45=max text size/2
-      d.outerRadius = radius
-      "translate(" + arc.centroid(d) + ")")
-      .attr('fill', "#fff")
-      .attr("text-anchor", "middle").text((d, i) -> data[i].label).attr('font-size', '28px')
-      .append('svg:tspan')
-      .attr('x', 0)
-      .attr('dy', 25)
-      .attr('font-size', '90%')
-      .text((d,i) -> data[i].value + ' (' + percent_val + '%)')
+#      .text((d,i) -> data[i].value + ' (' + percent_val + '%)')


Edited isNaN check in fullpie.coffee

Edited isNaN check in fullpie.coffee

--- widgets/fullpie/fullpie.coffee
+++ widgets/fullpie/fullpie.coffee
@@ -47,8 +47,8 @@
     sum=0
     for val in data
       sum += val.value
-	if isNaN(sum)
-	  sum = 0
+	if isNaN(sum) or sum == 0
+	  sum = 1

     arcs.append("svg:text").attr("transform", (d, i) ->
       procent_val = Math.round(data[i].value/sum * 100)


DRY up reading archive entries

DRY up reading archive entries

--- src/ls-archive.coffee
+++ src/ls-archive.coffee
@@ -78,13 +78,11 @@
   zipStream.on 'error', callback
   zipStream.on 'entry', (entry) ->
     if filePath is entry.path
-      if entry.type isnt 'File'
+      if entry.type is 'File'
+        readEntry(entry, callback)
+      else
         callback("#{filePath} is a folder in the archive: #{archivePath}")
-        return
-
-      contents = []
-      entry.on 'data', (data) -> contents.push(data)
-      entry.on 'end', -> callback(null, Buffer.concat(contents).toString())
+        entry.autodrain()
     else
       entry.autodrain()

@@ -116,13 +114,15 @@
   tarStream.on 'entry', (entry) ->
     return unless filePath is entry.props.path

-    unless entry.props.type is '0'
+    if entry.props.type is '0'
+      readEntry(entry, callback)
+    else
       callback("#{filePath} is not a normal file in the archive: #{archivePath}")
-      return

-    contents = []
-    entry.on 'data', (data) -> contents.push(data)
-    entry.on 'end', -> callback(null, Buffer.concat(contents).toString())
+readEntry = (entry, callback) ->
+  contents = []
+  entry.on 'data', (data) -> contents.push(data)
+  entry.on 'end', -> callback(null, Buffer.concat(contents).toString())

 module.exports =
   list: (archivePath, callback) ->


number_extensions

--- src/number_extensions.coffee
+++ src/number_extensions.coffee
@@ -93,11 +93,9 @@
 @returns A number in the range [min, max]
 @type Number

-

-   x = 2
-
+

    # limit the output of this computation to between 0 and 255
-   (x * 255).clamp(0, 255)
+   (2 * 255).clamp(0, 255)
 => 255

 ###


use css and svg transform

use css and svg transform

Fix #152

--- src/render/render_svg.coffee
+++ src/render/render_svg.coffee
@@ -20,10 +20,8 @@
     paths.map (path) -> SVG.path path_dict(path)

   svg_tag = (attrs, body) ->
-    if utils.no_css_transforms()
-      attrs.transform = world.bind() (-> world.get('ie_transform') || '')
-    else
-      attrs.style = world.bind() (-> world.get('transform') || '')
+    attrs.transform = world.bind() (-> world.get('ie_transform') || '')
+    attrs.style = world.bind() (-> world.get('transform') || '')
     SVG.svg {
       xmlns: "http://www.w3.org/2000/svg"
       "xmlns:xlink": "http://www.w3.org/1999/xlink"


Update src/scripts/likeaboss.coffee

Update src/scripts/likeaboss.coffee

added animated gifs and boss/baws/like a baws options.

--- src/scripts/likeaboss.coffee
+++ src/scripts/likeaboss.coffee
@@ -23,8 +23,25 @@
   "http://images.cheezburger.com/completestore/2011/2/20/a4ea536d-4b21-4517-b498-a3491437d224.jpg",
   "http://funcorner.eu/wp-content/uploads/2011/03/like_a_boss.jpg",
   "http://www.japemonster.com/wp-content/uploads/2011/08/demotivational-posters-like-a-boss.jpg",
+  "https://i.chzbgr.com/maxW500/6972126976/hAA5A99AF/",
+  "http://like-a-boss.org/wp-content/uploads/2011/06/abd-17.gif",
+  "http://like-a-boss.org/wp-content/uploads/2011/06/abd-25.gif",
+  "http://like-a-boss.org/wp-content/uploads/2011/06/abd-31.gif",
+  "http://like-a-boss.org/wp-content/uploads/2011/06/abd-53.gif",
+  "http://like-a-boss.org/wp-content/uploads/2011/06/tumblr_lk82o89vSG1qe0eclo1_r7_500.gif",
+  "https://i.chzbgr.com/maxW500/6669391104/h7509954E/",
+  "http://i.imgur.com/eNXkb.gif",
+  "http://i.imgur.com/WN8Ud.gif",
+  "http://i.imgur.com/9y0VV.gif",
+  "http://i.imgur.com/68Jtv.gif",
+  "http://i.imgur.com/hdVDd.gif",
+  "http://i.imgur.com/B0ehW.gif",
+  "http://i.imgur.com/3GU2Q.gif",
+  "http://i.imgur.com/Z3aAs.gif",
+  "http://i.imgur.com/diA9N.gif",
+  "http://i.imgur.com/ze3MJ.gif"
   ]

 module.exports = (robot) ->
-  robot.hear /like a boss/i, (msg) ->
+  robot.hear /like a boss|boss|like a baws|baws/i, (msg) ->
     msg.send msg.random images


Fix where no oncall returned if missing configuration variable

Introduced in #117. Also fixes case where an ignored schedule would still appear in the logs if no username was assigned to it.

Fixes #118

--- src/scripts/pagerduty.coffee
+++ src/scripts/pagerduty.coffee
@@ -614,11 +614,18 @@

     renderSchedule = (s, cb) ->
       withCurrentOncall msg, s, (username, schedule) ->
+        # If there is an allowed schedules array, skip returned schedule not in it
+        if allowed_schedules.length and schedule.id not in allowed_schedules
+          robot.logger.debug "Schedule #{schedule.id} (#{schedule.name}) not in HUBOT_PAGERDUTY_SCHEDULES"
+          return cb null
+
+        # Ignore schedule if no user assigned to it
         if (username)
-          if !allowed_schedules or schedule.id in allowed_schedules
-            messages.push("* #{username} is on call for #{schedule.name} - #{schedule.html_url}")
+          messages.push("* #{username} is on call for #{schedule.name} - #{schedule.html_url}")
         else
           robot.logger.debug "No user for schedule #{schedule.name}"
+
+        # Return callback
         cb null

     if scheduleName?


cd before coffee compile to make the maps work

--- asterisk.coffee
+++ asterisk.coffee
@@ -89,8 +89,6 @@
     fs.existsSync(filename) and fs.statSync(filename).isFile()

-
-
 lint = (s, filename) ->

     if ends_with(filename, ".py")
@@ -122,7 +120,9 @@

 coffeemake = (s, filename) ->
     print "running coffee", filename
-    command = "coffee -cm #{filename}"
+    path = filename[...filename.lastIndexOf("/")]
+    command = "cd #{path}; coffee -cm #{filename}"
+    console.log "$", command
     exec command, (error, stdout, stderr) ->
         marks = []
         #print "stderr", stderr.split("\n")
@@ -279,6 +279,7 @@
                     return error("not logged in")

                 s = kargs.query
+                console.log "s", kargs.query
                 dir = kargs.directory
                 if s and s[0] == "/"
                     dir = s[0..s.lastIndexOf("/")-1]


static render: getting rid of deprecation warning

--- src/smc-webapp/render.coffee
+++ src/smc-webapp/render.coffee
@@ -3,10 +3,10 @@

 # Code for static server-side rendering of the subscription options.
 exports.render_subscriptions = ->
-    React = require('react')
+    ReactDOMServer = require('react-dom/server')
     billing = require('./billing.cjsx')
     fs = require('fs')
-    html = React.renderToString(billing.render_static_pricing_page())
+    html = ReactDOMServer.renderToString(billing.render_static_pricing_page())
     filename = '../static/policies/pricing.html'
     s = fs.readFileSync(filename+'.template').toString()
     i = s.indexOf('start:SubscriptionGrid')


further work on sagews worksheet render rewrite

--- src/smc-webapp/sagews.coffee
+++ src/smc-webapp/sagews.coffee
@@ -42,7 +42,7 @@

 class SynchronizedWorksheet extends SynchronizedDocument2
     constructor: (@editor, @opts) ->
-        #window.w = @
+        window.w = @
         # these two lines are assumed, at least by the history browser
         @codemirror  = @editor.codemirror
         @codemirror1 = @editor.codemirror1
@@ -773,8 +773,66 @@

     _process_sage_updates: (cm, start, stop) =>
         dbg = (m) -> console.log("_process_sage_updates: #{m}")
-        #dbg("start=#{start}, stop=#{stop}")
-        return
+        if not cm?
+            cm = @focused_codemirror()
+        if not start?
+            start = 0
+        if not stop?
+            stop = cm.lineCount()-1
+        dbg("start=#{start}, stop=#{stop}")
+        ###
+        What this function does:
+
+            - Ensure that each cell start line is properly marked so it looks like a horizontal
+              line, which can be clicked, and is colored to indicate state.
+
+            - Ensure that each output line is replaced by an output element, with the proper
+              output rendered in it.
+
+        ###
+        for line in [start..stop]
+            x = cm.getLine(line)
+            if not x?
+                continue
+
+            marks = cm.findMarks({line:line, ch:0}, {line:line,ch:x.length})
+            switch x[0]
+                when MARKERS.cell
+                    if marks.length == 0
+                        # create the input mark here
+                        console.log("creating input mark at line #{line}")
+                        input = cell_start_template.clone()
+                        opts =
+                            shared         : false
+                            inclusiveLeft  : false
+                            inclusiveRight : true
+                            atomic         : true
+                            replacedWith   : input[0] #$("<div style='margin-top: -30px; border: 1px solid red'>")[0]
+                        mark = cm.markText({line:line, ch:0}, {line:line, ch:x.length}, opts)
+                        mark.element = input
+
+                when MARKERS.output
+                    if marks.length == 0
+                        # create the output mark here
+                        console.log("creating output mark at line #{line}")
+                        output = output_template.clone()
+                        opts =
+                            shared         : false
+                            inclusiveLeft  : true
+                            inclusiveRight : true
+                            atomic         : true
+                            replacedWith   : output[0]
+                        mark = cm.markText({line:line, ch:0}, {line:line+1, ch:x.length}, opts)
+                        mark.element = input
+                        cm.addLineClass(line, 'gutter', 'sagews-output-cm-gutter')
+                        cm.addLineClass(line, 'text',   'sagews-output-cm-text')
+                        cm.addLineClass(line, 'wrap',   'sagews-output-cm-wrap')
+
+                else
+                    if marks.length > 0
+                        for m in marks
+                            m.clear()
+

     _process_sage_updates0: (cm, start, stop) =>
         #console.log("process_sage_updates(start=#{start}, stop=#{stop}):'#{cm.getValue()}'")


change time to move chat.

change time to move chat.

--- src/smc-webapp/smc_chat.cjsx
+++ src/smc-webapp/smc_chat.cjsx
@@ -493,8 +493,8 @@
         # issue -- if the user is switching tabs back and forth in a session, that is very
         # unlikely, due to the browser caching the dynamic content.
         # The user is also unlikely to manually scroll the page then see it jump to
-        # this fixed position dwithin 300ms of mounting.
-        for tm in [0, 150, 300]
+        # this fixed position dwithin 500ms of mounting.
+        for tm in [0, 150, 500]
             setTimeout(fix_pos, tm)

     componentDidMount: ->


Doesn't crash on empty key bindings.

Doesn't crash on empty key bindings.

--- src/stdlib/key-binder.coffee
+++ src/stdlib/key-binder.coffee
@@ -21,7 +21,7 @@
 #       Watcher.watch path, =>
 #         @load path

-      json = CoffeeScript.eval "return " + (fs.read path)
+      json = (CoffeeScript.eval "return " + (fs.read path)) or {}
       # Iterate in reverse order scopes are declared.
       # Scope at the top of the file is checked last.
       for name in _.keys(json).reverse()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/string_extensions.coffee
+++ src/string_extensions.coffee
@@ -72,7 +72,7 @@

 ###*
 @name extension
-
+@methodOf
 ###
 String::extension = ->
   return this.match(/\.([^\.]*)$/, '').last() || '';


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/string_extensions.coffee
+++ src/string_extensions.coffee
@@ -136,6 +136,7 @@

 @name startsWith
 @methodOf String#
+@param

 @returns {Boolean} True if this string starts with the given string, false otherwise.
 ###


Update about page

Update about page

--- assets/javascripts/templates/pages/about_tmpl.coffee
+++ assets/javascripts/templates/pages/about_tmpl.coffee
@@ -13,7 +13,7 @@

DevDocs combines multiple API documentations in a fast, organized, and searchable interface.

Created and maintained by Thibaut Courouble
-
Proudly sponsored by MaxCDN—content delivery that developers love
+
Sponsored by MaxCDN—content delivery that developers love

Free and open source

@@ -27,6 +27,15 @@
     Gittip. Thanks!

Credits

+
+
Special thanks to:
+

+
Gauges for offering a free account to DevDocs
+
Heroku and New Relic for providing awesome free service
+
Daniel Bruce for the Entypo pictograms
+
Jeremy Kratz for the C/C++ logo
+

+

       Documentation
@@ -34,13 +43,6 @@
       License
     #{("
#{c[0]}© #{c[1]}#{c[2]}" for c in credits).join('')}

-
-
With special thanks to:
-

-
Heroku and New Relic for providing awesome free service
-
Daniel Bruce for the Entypo pictograms
-
Jeremy Kratz for the C/C++ logo
-

Questions & Answsers


textwrap available size catch now uses padding

--- src/textwrap/textwrap.coffee
+++ src/textwrap/textwrap.coffee
@@ -15,7 +15,7 @@

         sizes vars

-        if vars.size.value[0] <= vars.height.value
+        if vars.size.value[0] <= vars.height.inner
           text vars
           wrap vars


Track landing site page visits

Track landing site page visits

--- client/landing/site.landing/coffee/core/maincontrollerloggedout.coffee
+++ client/landing/site.landing/coffee/core/maincontrollerloggedout.coffee
@@ -56,9 +56,13 @@

   setupPageAnalyticsEvent:->

-    KD.singletons.router.on "RouteInfoHandled", (args) ->
+    KD.singletons.router.on "RouteInfoHandled", (route) ->

-      return  unless args
+      return  unless route
+
+      name = route.path.split('/')[1] or '/'
+
+      KD.utils.analytics.page name

   login: (formData, callback) ->


cleanup

cleanup

--- src/ui/views/convhead.coffee
+++ src/ui/views/convhead.coffee
@@ -3,41 +3,41 @@
 onclickaction = (a) -> (ev) -> action a

 module.exports = view (models) ->
-	{conv, viewstate} = models
-	conv_id = viewstate?.selectedConv
-	c = conv[conv_id]
-	return if not c
-	name = nameofconv c
-	div class:'headwrap', ->
-		span class:'name', ->
-			if conv.isQuiet(c)
-		        span class:'material-icons', 'notifications_off'
-			if conv.isStarred(c)
-				span class:'material-icons', "star"
-			name
-		div class:'button', title:'Conversation options',
-			onclick:convoptions, -> span class:'material-icons', 'more_vert'
-		div class:'convoptions', ->
-			div class:'button', title:'Conversation settings',
-				div class:'button', title:'Toggle notifications', onclick:onclickaction('togglenotif'), ->
-		            if conv.isQuiet(c)
-		                span class:'material-icons', 'notifications_off'
-		            else
-		                span class:'material-icons', 'notifications'
-		            div class:'option-label', 'Notifications'
-		        div class:'button', title:'Star/unstar', onclick:onclickaction('togglestar'), ->
-	                if not conv.isStarred(c)
-	                	span class:'material-icons', 'star_border'
-	                else
-	                	span class:'material-icons', 'star'
-	                div class:'option-label', 'Favorite'
-	            div class:'button', title:'Settings',
-					onclick:onclickaction('convsettings'), ->
-						span class:'material-icons', 'info_outline'
-						div class:'option-label', 'Details'
+  {conv, viewstate} = models
+  conv_id = viewstate?.selectedConv
+  c = conv[conv_id]
+  return if not c
+  name = nameofconv c
+  div class:'headwrap', ->
+    span class:'name', ->
+      if conv.isQuiet(c)
+            span class:'material-icons', 'notifications_off'
+      if conv.isStarred(c)
+        span class:'material-icons', "star"
+      name
+    div class:'button', title:'Conversation options',
+      onclick:convoptions, -> span class:'material-icons', 'more_vert'
+    div class:'convoptions', ->
+      div class:'button', title:'Conversation settings',
+        div class:'button', title:'Toggle notifications', onclick:onclickaction('togglenotif'), ->
+                if conv.isQuiet(c)
+                    span class:'material-icons', 'notifications_off'
+                else
+                    span class:'material-icons', 'notifications'
+                div class:'option-label', 'Notifications'
+            div class:'button', title:'Star/unstar', onclick:onclickaction('togglestar'), ->
+                  if not conv.isStarred(c)
+                    span class:'material-icons', 'star_border'
+                  else
+                    span class:'material-icons', 'star'
+                  div class:'option-label', 'Favorite'
+              div class:'button', title:'Settings',
+          onclick:onclickaction('convsettings'), ->
+            span class:'material-icons', 'info_outline'
+            div class:'option-label', 'Details'

 convoptions  = ->
-	{viewstate} = models
-	document.querySelector('.convoptions').classList.toggle('open');
-	if viewstate.state == viewstate.STATE_ADD_CONVERSATION
-		action 'saveconversation'
+  {viewstate} = models
+  document.querySelector('.convoptions').classList.toggle('open');
+  if viewstate.state == viewstate.STATE_ADD_CONVERSATION
+    action 'saveconversation'


month names

month names

--- src/modules/graph.coffee
+++ src/modules/graph.coffee
@@ -81,7 +81,7 @@
         # Get available space.
         { height, width } = document.querySelector('#graph').getBoundingClientRect()

-        margin = { top: 10, right: 30, bottom: 40, left: 50 }
+        margin = { top: 30, right: 30, bottom: 40, left: 50 }
         width -= margin.left + margin.right
         height -= margin.top + margin.bottom

@@ -121,11 +121,28 @@
         .append("g")
         .attr("transform", "translate(" + margin.left + "," + margin.top + ")")

-        # Add the x-axis.
+        # Add the days x-axis.
         svg.append("g")
-        .attr("class", "x axis")
+        .attr("class", "x axis day")
         .attr("transform", "translate(0,#{height})")
         .call(xAxis)
+
+        # Add the months x-axis.
+        m = [
+            'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
+            'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
+        ]
+
+        mAxis = xAxis
+        .orient("top")
+        .tickSize(height)
+        .tickFormat( (d) -> m[d.getMonth()] )
+        .ticks(2)
+
+        svg.append("g")
+        .attr("class", "x axis month")
+        .attr("transform", "translate(0,#{height})")
+        .call(mAxis)

         # Add the y-axis.
         svg.append("g")


Refactor complex ¯4○ for clarity.

Refactor complex ¯4○ for clarity.

--- src/vocabulary/circle.coffee
+++ src/vocabulary/circle.coffee
@@ -109,9 +109,10 @@
           when -5 then Complex.asinh x
           when -4
             if x.re is -1 and x.im is 0 then 0
-            else Complex.multiply (Complex.add x, 1), Complex.sqrt(
-              Complex.divide (Complex.subtract x, 1), Complex.add x, 1
-            )
+            else
+              a = Complex.add x, 1
+              b = Complex.subtract x, 1
+              Complex.multiply a, Complex.sqrt (Complex.divide b, a)
           when -3 then Complex.atan x
           when -2 then Complex.acos x
           when -1 then Complex.asin x


Add closing parenthesis

Add closing parenthesis

--- admin/static/coffee/dataexplorer.coffee
+++ admin/static/coffee/dataexplorer.coffee
@@ -86,105 +86,128 @@
         suggestions:
             stream: [
                 {
-                    suggestion: 'get('
+                    suggestion: 'get()'
                     description: 'get( id )'
-                }
-                {
-                    suggestion: 'filter('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'filter()'
                     description: 'filter( predicate )'
+                    has_argument: true
                 }
                 {
                     suggestion: 'length()'
                     description: 'length()'
-                }
-                {
-                    suggestion: 'map('
+                    has_argument: false
+                }
+                {
+                    suggestion: 'map()'
                     description: 'map( attribute )'
-                }
-                {
-                    suggestion: 'slice'
+                    has_argument: true
+                }
+                {
+                    suggestion: 'slice()'
                     description: 'slice( start, end )'
-                }
-                {
-                    suggestion: 'orderby('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'orderby()'
                     description: 'orderby( expression )'
-                }
-                {
-                    suggestion: 'distinct'
+                    has_argument: true
+                }
+                {
+                    suggestion: 'distinct()'
                     description: 'distinct( expression )'
-                }
-                {
-                    suggestion: 'reduce('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'reduce()'
                     description: 'reduce( expression )'
-                }
-                {
-                    suggestion: 'pluck('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'pluck()'
                     description: 'pluck( expression )'
-                }
-                {
-                    suggestion: 'extend('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'extend()'
                     description: 'extend( expression )'
+                    has_argument: true
                 }
             ]
             view:[
                 {
-                    suggestion: 'pluck('
+                    suggestion: 'pluck()'
                     description: 'pluck( expression )'
+                    has_argument: true
                 }
             ]
             db:[
                 {
-                    suggestion: 'table('
+                    suggestion: 'table()'
                     description: 'table( table_name )'
+                    has_argument: true
                 }
                 {
                     suggestion: 'list()'
                     description: 'list()'
-                }
-                {
-                    suggestion: 'create'
+                    has_argument: false
+                }
+                {
+                    suggestion: 'create()'
                     description: 'create( database_name, primary_datacenter_id )'
+                    has_argument: true
                 }
                 {
                     suggestion: 'drop()'
                     description: 'drop()'
+                    has_argument: false
                 }
             ]
             table:[
                 {
-                    suggestion: 'insert('
+                    suggestion: 'insert()'
                     description: 'insert( document )'
+                    has_argument: true
                 }

             ]
             r:[
                 {
-                    suggestion: 'dbCreate('
+                    suggestion: 'dbCreate()'
                     description: 'dbCreate( database_name, primary_datacenter )'
-                }
-                {
-                    suggestion: 'dbDrop('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'dbDrop()'
                     description: 'dbDrop( database_name )'
+                    has_argument: true
                 }
                 {
                     suggestion: 'dbList()'
                     description: 'dbList()'
-                }
-                {
-                    suggestion: 'expr('
+                    has_argument: false
+                }
+                {
+                    suggestion: 'expr()'
                     description:'expr( expression )'
-                }
-                {
-                    suggestion: 'fn('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'fn()'
                     description: 'fn( argument..., body )'
-                }
-                {
-                    suggestion: 'ifThenElse('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'ifThenElse()'
                     description: 'ifThenElse( expression, callback_true, callback_false)'
-                }
-                {
-                    suggestion: 'let('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'let()'
                     description: 'let( arguments..., body)'
+                    has_argument: true
                 }

             ]
@@ -192,73 +215,90 @@
                 {
                     suggestion: 'r'
                     description : 'The main ReQL namespace'
-                }
-                {
-                    suggestion: 'r('
+                    has_argument: false
+                }
+                {
+                    suggestion: 'r()'
                     description : 'Variable'
-                }
-
-                {
-                    suggestion: 'R('
+                    has_argument: true
+                }
+
+                {
+                    suggestion: 'R()'
                     description : 'Attribute Selector'
+                    has_argument: true
                 }
             ]
             expr: [
                 {
-                    suggestion: 'add('
+                    suggestion: 'add()'
                     description: 'add( expression )'
-                }
-                {
-                    suggestion: 'sub('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'sub()'
                     description: 'sub( expression )'
-                }
-                {
-                    suggestion: 'mul('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'mul()'
                     description: 'mul( expression )'
-                }
-                {
-                    suggestion: 'div('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'div()'
                     description: 'div( expression )'
-                }
-                {
-                    suggestion: 'mod('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'mod()'
                     description: 'mod( expression )'
-                }
-                {
-                    suggestion: 'eq('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'eq()'
                     description: 'eq( expression )'
-                }
-                {
-                    suggestion: 'ne('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'ne()'
                     description: 'ne( expression )'
-                }
-                {
-                    suggestion: 'lt('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'lt()'
                     description: 'lt( expression )'
-                }
-                {
-                    suggestion: 'le('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'le()'
                     description: 'le( expression )'
-                }
-                {
-                    suggestion: 'gt('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'gt()'
                     description: 'gt( expression )'
-                }
-                {
-                    suggestion: 'ge('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'ge()'
                     description: 'ge( expression )'
-                }
-                {
-                    suggestion: 'not('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'not()'
                     description: 'not( expression )'
-                }
-                {
-                    suggestion: 'and('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'and()'
                     description: 'and( expression )'
-                }
-                {
-                    suggestion: 'or('
+                    has_argument: true
+                }
+                {
+                    suggestion: 'or()'
                     description: 'or( expression )'
+                    has_argument: true
                 }

             ]
@@ -301,10 +341,14 @@
                 start_line_index = 0
             else
                 start_line_index += 1
+
+            ch = (@query_first_part + @current_completed_query + suggestion_to_write).length - start_line_index
+            if event.target.dataset.has_argument is true
+                ch--

             @cursor =
                 line: saved_cursor.line
-                ch: (@query_first_part + @current_completed_query + suggestion_to_write).length - start_line_index
+                ch: ch

             setTimeout @position_cursor_after_click, 1 # Ugliest hack ever.

@@ -356,7 +400,8 @@
                         else
                             start_line_index += 1
                         position = (@query_first_part + @current_completed_query + @current_suggestions[@current_highlighted_suggestion].suggestion).length - start_line_index
-
+                        if @current_suggestions[@current_highlighted_suggestion].has_argument is true
+                            position--
                         @position_cursor
                             line: saved_cursor.line
                             ch: position
@@ -409,31 +454,7 @@
             query = query_before_cursor.slice slice_index

             @query_first_part = query_before_cursor.slice 0, slice_index
-            ###
-            #TODO handle string
-            next_dot_position = query_after_cursor.indexOf('.')
-            next_parenthesis_position = query_after_cursor.indexOf(')')
-            if next_dot_position is -1 and next_parenthesis_position is -1
-                @query_last_part = ''
-            else
-                if next_dot_position is -1
-                    slice_position = next_parenthesis_position
-                else if next_parenthesis_position is -1
-                    slice_position = next_dot_position
-                else
-                    slice_position = Math.min next_dot_position, next_parenthesis_position
-
-                @query_last_part = query_after_cursor.slice slice_position
-                slice_position--
-                while query_after_cursor[slice_position]? and /\s/.test(query_after_cursor[slice_position])
-                    @query_last_part = query_after_cursor[slice_position] + @query_last_part
-                    slice_position--
-            ###
-            ###
-            slice_position = 0
-            while query_after_cursor[slice_position]? and /\s/.test(query_after_cursor[slice_position])
-                slice_position++
-            ###
+            # We might want to use tab to move faster (like w in vim)
             @query_last_part = query_after_cursor #.slice slice_position

             last_function = @extract_last_function(query)


Refactor Angular line_items_controller

Refactor Angular line_items_controller

--- app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee
+++ app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee
@@ -12,22 +12,21 @@
   $scope.sharedResource = false
   $scope.columns = Columns.columns
   $scope.sorting = SortOptions
-  $scope.distributorFilter = ''
-  $scope.supplierFilter = ''
-  $scope.orderCycleFilter = ''
-  $scope.quickSearch = ''
   $scope.page = 1
   $scope.per_page = 50

   $scope.confirmRefresh = ->
     LineItems.allSaved() || confirm(t("unsaved_changes_warning"))

-  $scope.resetSelectFilters = ->
+  $scope.resetFilters = ->
     $scope.distributorFilter = ''
     $scope.supplierFilter = ''
     $scope.orderCycleFilter = ''
     $scope.quickSearch = ''
     $scope.page = 1
+
+  $scope.resetSelectFilters = ->
+    $scope.resetFilters()
     $scope.refreshData()

   $scope.changePage = (newPage) ->
@@ -36,43 +35,57 @@

   $scope.refreshData = ->
     unless !$scope.orderCycleFilter? || $scope.orderCycleFilter == ''
-      start_date = OrderCycles.byID[$scope.orderCycleFilter].orders_open_at
-      end_date = OrderCycles.byID[$scope.orderCycleFilter].orders_close_at
-      format = "YYYY-MM-DD HH:mm:ss Z"
-      $scope.startDate = moment(start_date, format).format('YYYY-MM-DD')
-      $scope.endDate = moment(end_date, format).startOf('day').format('YYYY-MM-DD')
+      $scope.setOrderCycleDateRange()

-    formatted_start_date = moment($scope.startDate).format()
-    formatted_end_date = moment($scope.endDate).add(1,'day').format()
+    $scope.formattedStartDate = moment($scope.startDate).format()
+    $scope.formattedEndDate = moment($scope.endDate).add(1,'day').format()

-    return unless moment(formatted_start_date).isValid() and moment(formatted_start_date).isValid()
+    return unless moment($scope.formattedStartDate).isValid() and moment($scope.formattedEndDate).isValid()

+    $scope.loadOrders()
+    $scope.loadLineItems()
+
+    unless $scope.initialized
+      $scope.loadAssociatedData()
+
+    $scope.dereferenceLoadedData()
+
+  $scope.setOrderCycleDateRange = ->
+    start_date = OrderCycles.byID[$scope.orderCycleFilter].orders_open_at
+    end_date = OrderCycles.byID[$scope.orderCycleFilter].orders_close_at
+    format = "YYYY-MM-DD HH:mm:ss Z"
+    $scope.startDate = moment(start_date, format).format('YYYY-MM-DD')
+    $scope.endDate = moment(end_date, format).startOf('day').format('YYYY-MM-DD')
+
+  $scope.loadOrders = ->
     RequestMonitor.load $scope.orders = Orders.index(
       "q[state_not_eq]": "canceled",
       "q[completed_at_not_null]": "true",
       "q[distributor_id_eq]": $scope.distributorFilter,
       "q[order_cycle_id_eq]": $scope.orderCycleFilter,
-      "q[completed_at_gteq]": formatted_start_date,
-      "q[completed_at_lt]": formatted_end_date
+      "q[completed_at_gteq]": $scope.formattedStartDate,
+      "q[completed_at_lt]": $scope.formattedEndDate
     )

+  $scope.loadLineItems = ->
     RequestMonitor.load LineItems.index(
       "q[order_state_not_eq]": "canceled",
       "q[order_completed_at_not_null]": "true",
       "q[order_distributor_id_eq]": $scope.distributorFilter,
       "q[variant_product_supplier_id_eq]": $scope.supplierFilter,
       "q[order_order_cycle_id_eq]": $scope.orderCycleFilter,
-      "q[order_completed_at_gteq]": formatted_start_date,
-      "q[order_completed_at_lt]": formatted_end_date,
+      "q[order_completed_at_gteq]": $scope.formattedStartDate,
+      "q[order_completed_at_lt]": $scope.formattedEndDate,
       page: $scope.page,
       per_page: $scope.per_page
     )

-    unless $scope.initialized
-      RequestMonitor.load $scope.distributors = Enterprises.index(action: "visible", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
-      RequestMonitor.load $scope.orderCycles = OrderCycles.index(ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{moment().subtract(90,'days').format()}")
-      RequestMonitor.load $scope.suppliers = Enterprises.index(action: "visible", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
+  $scope.loadAssociatedData = ->
+    RequestMonitor.load $scope.distributors = Enterprises.index(action: "visible", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
+    RequestMonitor.load $scope.orderCycles = OrderCycles.index(ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{moment().subtract(90,'days').format()}")
+    RequestMonitor.load $scope.suppliers = Enterprises.index(action: "visible", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")

+  $scope.dereferenceLoadedData = ->
     RequestMonitor.load $q.all([$scope.orders.$promise, $scope.distributors.$promise, $scope.orderCycles.$promise, $scope.suppliers.$promise, $scope.line_items.$promise]).then ->
       Dereferencer.dereferenceAttr $scope.orders, "distributor", Enterprises.byID
       Dereferencer.dereferenceAttr $scope.orders, "order_cycle", OrderCycles.byID
@@ -80,6 +93,7 @@
       Dereferencer.dereferenceAttr $scope.line_items, "order", Orders.byID
       $scope.bulk_order_form.$setPristine()
       StatusMessage.clear()
+
       unless $scope.initialized
         $scope.initialized = true

@@ -176,4 +190,5 @@
       lineItem.final_weight_volume = LineItems.pristineByID[lineItem.id].final_weight_volume * lineItem.quantity / LineItems.pristineByID[lineItem.id].quantity
       $scope.weightAdjustedPrice(lineItem)

+  $scope.resetFilters()
   $scope.refreshData()


Fix form button alignment issue

Fix form button alignment issue

--- app/assets/javascripts/hyper_admin/angularjs/directives/form/form_actions.js.coffee
+++ app/assets/javascripts/hyper_admin/angularjs/directives/form/form_actions.js.coffee
@@ -2,7 +2,7 @@
   .directive "formActions", ->
     template: """

-

+

     <md-button type="submit" class="md-primary md-raised"
       ng-disabled="form.$invalid">Submit</md-button>
     <md-button class="md-warn" ui-sref="^">Cancel


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_selector.coffee
+++ src/engine_selector.coffee
@@ -61,7 +61,7 @@
   ###
   each: (selector, fn) ->
     self.find(selector).each (obj, index) ->
-      fn()
+      fn(obj, )

   find: (selector) ->
     results = []


make ui responive by removing p timeout

make ui responive by removing p timeout

--- app/assets/javascripts/commit.js.coffee
+++ app/assets/javascripts/commit.js.coffee
@@ -17,16 +17,11 @@
   # Good place to put this? Jeff
   $x_position: $("#x-position")
   $y_position: $("#y-position")
-  tooltip_timeout: false
   draw_tooltip: (e) =>
-    clearTimeout(@tooltip_timeout)
     x = e.offsetX - 20
     y = e.offsetY
     @$y_position.text(Math.round(@ry(y)))
-    @tooltip_timeout = setTimeout =>
-      @$x_position.text(JSON.stringify(@filtered_commits[Math.round(@rx(x))]))
-      console.log @filtered_commits[Math.round(@rx(x))], Math.round(@ry(y))
-    , 50
+    @$x_position.text(JSON.stringify(@filtered_commits[Math.round(@rx(x))]))

   summed_additions_deletions: (d) => @get_aggregated_additions(d) + @get_aggregated_deletions(d)