Allow an initializeButtonClickWithRender click callback to return false to cancel

This is unused. Maybe YAGNI. oh well.

--- app/assets/javascripts/announcer.js.coffee
+++ app/assets/javascripts/announcer.js.coffee
@@ -29,7 +29,7 @@
     button = $(options.selector)
     button.click (event) =>
       event.preventDefault()
-      options.click?(event)
+      return if options.click?(event) == false
       $.ajax
         url: options.url
         method: options.method || 'POST'


Add errors to watch output

Add errors to watch output

--- scripts/watch.coffee
+++ scripts/watch.coffee
@@ -32,3 +32,9 @@

 				child.stdout.on "error", (data) ->
 					process.stderr.write Buffer(data).toString "utf8"
+
+				child.stderr.on "data", (data) ->
+					process.stdout.write Buffer(data).toString "utf8"
+
+				child.stderr.on "error", (data) ->
+					process.stderr.write Buffer(data).toString "utf8"


remove / in prefix

remove / in prefix

--- src/router.coffee
+++ src/router.coffee
@@ -110,7 +110,7 @@
     incubator ctrlObj, action

     if toString.call(path) is '[object String]' and @prefix
-      path = '/' + p.join(@prefix, path)
+      path = p.join @prefix, path

     # Register apis
     @_stack.push


show confirmation dialog before hangup

show confirmation dialog before hangup

--- app/assets/javascripts/controllers/agent_bridge.coffee
+++ app/assets/javascripts/controllers/agent_bridge.coffee
@@ -2,8 +2,12 @@

   actions:
     hangupCall: ->
-      return false unless @get 'myCall'
-      $.post("/calls/#{@get 'id'}", {'_method': 'DELETE'})
+      return false unless @get('myCall')
+      callId = @get('id')
+
+      app.dialog('Do you want to hangup this call?', 'question', 'Hangup', 'Cancel').then (->
+        $.post("/calls/#{callId}", {'_method': 'DELETE'})
+      ), (->)
       false

 })


remove archived account from BS

remove archived account from BS

--- app/assets/javascripts/directives/balance/sheet.coffee
+++ app/assets/javascripts/directives/balance/sheet.coffee
@@ -17,8 +17,9 @@
         $scope.projectPromise.then (data) ->
           $scope.project = data
           accounts = Resources.Account.query { project_id: data.id }
-          accounts.$promise.then (accounts) ->
+          accounts.$promise.then (accounts) ->
             angular.forEach(accounts, (account) ->
+              return if account.archived
               if (account.account_type == $scope.typeIn)
                 $scope.in.addAccount(account)
               else if (account.account_type == $scope.typeOut)


Fix sliders being disabled when toggle has no value

--- app/assets/javascripts/lib/models/input_element.coffee
+++ app/assets/javascripts/lib/models/input_element.coffee
@@ -100,7 +100,7 @@
       App.update_merit_order_checkbox()

   handle_boolean_callbacks: ->
-    enabled = @get('user_value')
+    enabled = @get('user_value') || false

     # Handle when_true, when_false config
     { when_true, when_false } = (@get('config') || {})


:new: Implement LinterViews::renderPanelMarkers

--- lib/linter-views-new.coffee
+++ lib/linter-views-new.coffee
@@ -16,6 +16,9 @@
     @bottomContainer = new BottomContainer().prepare(@linter.state)
     @bottomBar = null

+    @subscriptions.add atom.config.observe('linter.underlineIssues', (underlineIssues) =>
+      @underlineIssues = underlineIssues
+    )
     @subscriptions.add @linter.onDidClassifyMessages =>
       @render()

@@ -23,6 +26,7 @@
     @messages = @linter.messages.getAllMessages()
     @updateLineMessages()
     @renderPanelMessages()
+    @renderPanelMarkers()

   renderCount: ->
     count = @linter.messages.getCount()
@@ -39,6 +43,20 @@
       messages = @lineMessages
     @panel.updateMessages messages, @state.scope is 'Project'

+  renderPanelMarkers: ->
+    @removeMarkers()
+    activeEditor = atom.workspace.getActiveTextEditor()
+    return unless activeEditor
+    @messages.forEach (message) =>
+      return unless message.currentFile
+      @markers.push marker = activeEditor.markBufferRange message.range, {invalidate: 'never'}
+      activeEditor.decorateMarker(
+        marker, type: 'line-number', class: "linter-highlight #{message.class}"
+      )
+      if @underlineIssues then activeEditor.decorateMarker(
+        marker, type: 'highlight', class: "linter-highlight #{message.class}"
+      )
+
   updateLineMessages: ->
     @lineMessages =
       if @bottomContainer.getTab('File').attached
@@ -51,7 +69,12 @@
       item: @bottomContainer,
       priority: -100

+  removeMarkers: ->
+    @markers.forEach (marker) -> try marker.destroy()
+    @markers = []
+
   destroy: ->
+    @removeMarkers()
     @subscriptions.dispose()
     @bottomBar.destroy()
     @panel.destroy()


Adjusted anatomicalLocation api to point to correct location

--- app/assets/javascripts/condition.js.coffee
+++ app/assets/javascripts/condition.js.coffee
@@ -100,4 +100,4 @@
   ###*
   @returns {CodedValue}
   ###
-  anatomicalLocation: -> hQuery.createCodedValue @json['anatomicalLocation']
+  anatomicalLocation: -> hQuery.createCodedValue @json['anatomical_location']


Replace marker 'observe' methods w/ ordinary 'changed' event

--- lib/misspelling-view.coffee
+++ lib/misspelling-view.coffee
@@ -15,7 +15,7 @@
     @misspellingValid = true

     @marker = @editSession.markScreenRange(range, invalidationStrategy: 'between')
-    @marker.observe ({newHeadScreenPosition, newTailScreenPosition, valid}) =>
+    @marker.on 'changed', ({newHeadScreenPosition, newTailScreenPosition, valid}) =>
       @startPosition = newTailScreenPosition
       @endPosition = newHeadScreenPosition
       @updateDisplayPosition = valid


Fix for rule question edit

Fix for rule question edit

--- app/assets/javascripts/chapter_concept_review_order.js.coffee
+++ app/assets/javascripts/chapter_concept_review_order.js.coffee
@@ -52,6 +52,10 @@
 dataLoad = (cla) ->
   new window[cla] {el} for el in $("""*[data-view="#{cla}"]""")

-jQuery ($) ->
+
+loadSeriesRoots = ->
   dataLoad 'ConceptReviewRoot'
   dataLoad 'LessonAnswerRoot'
+
+jQuery(document).on 'page:load', loadSeriesRoots
+jQuery loadSeriesRoots


HOTFIX for clarat-org/clarat#694 - only show sorting when in edit route

--- app/assets/javascripts/rails_admin/custom/ui.js.coffee
+++ app/assets/javascripts/rails_admin/custom/ui.js.coffee
@@ -59,26 +59,28 @@

   next_steps_offers_area = $(".js-next-steps-offers")
   if next_steps_offers_area.length
-    offer_id = /^.*\/offer\/(\d+)\/edit.*$/.exec(location.href)[1]
-    $.get "/next_steps_offers/#{offer_id}.json", (nso_array) ->
-      container = next_steps_offers_area.find('.controls')
-      container.append $("
Reihenfolge

")
-      list = $('#nso_sortable')
-      for nso in nso_array
-        list.append("
#{nso.name}
")
-      Sortable.create list[0],
-        onSort: (event) ->
-          console.log event
-          event.item # dragged HTMLElement
-          items = list.find('li')
-          for index in range(event.oldIndex, event.newIndex)
-            item = $(items[index])
-            console.log item
-            $.post(
-              "/next_steps_offers/#{item.data('id')}.json",
-              _method: 'put'
-              next_steps_offer:
-                sort_value: index
-              , (response) ->
-                console.log response
-            )
+    match = /^.*\/offer\/(\d+)\/edit.*$/.exec(location.href)
+    if match
+      offer_id = match[1]
+      $.get "/next_steps_offers/#{offer_id}.json", (nso_array) ->
+        container = next_steps_offers_area.find('.controls')
+        container.append $("
Reihenfolge

")
+        list = $('#nso_sortable')
+        for nso in nso_array
+          list.append("
#{nso.name}
")
+        Sortable.create list[0],
+          onSort: (event) ->
+            console.log event
+            event.item # dragged HTMLElement
+            items = list.find('li')
+            for index in range(event.oldIndex, event.newIndex)
+              item = $(items[index])
+              console.log item
+              $.post(
+                "/next_steps_offers/#{item.data('id')}.json",
+                _method: 'put'
+                next_steps_offer:
+                  sort_value: index
+                , (response) ->
+                  console.log response
+              )


kinetic_thingy_delegate: Fix bug in context menu.

--- Oghma/kinetic_thingy_delegate.coffee
+++ Oghma/kinetic_thingy_delegate.coffee
@@ -463,7 +463,7 @@
   context_menu: ( event ) ->
     if @is_context_menuable( event )
       menu = Ext.create( 'Oghma.Ext.Menu', items: @context_menu_items() )
-      event.stopPropagation()
+      event.evt.stopPropagation()
       menu.showAt( [ event.evt.pageX, event.evt.pageY ] )
     this


add the stepId to the metadata URL when it's missing

This lets us get the metadata for the first step in the wizard (whose URL path normally doesn't include the stepId, unlike the subsequent steps).

--- app/assets/javascripts/hat-trick.js.coffee
+++ app/assets/javascripts/hat-trick.js.coffee
@@ -360,6 +360,8 @@
     metadataUrl = document.location.pathname
     lastChar = metadataUrl.charAt(metadataUrl.length - 1)
     metadataUrl += "/" unless lastChar is "/"
+    stepId = this.currentStepId()
+    metadataUrl += "#{stepId}/" if metadataUrl.search("#{stepId}/$") is -1
     metadataUrl += "metadata"
     $.ajax
       type: "GET"


self closing is by default off for xml

self closing is by default off for xml

--- src/schema.coffee
+++ src/schema.coffee
@@ -49,7 +49,7 @@
 # Valid self-closing HTML 5 elements.
 # set true when all tags are self closing
 self_closing =
-    'xml'  : -> on
+    'xml'  : -> off
     'svg1.1': -> on
     'html' : -> "area br col embed hr img input link meta param"
     'html5': -> "#{do self_closing.html} base command keygen source track wbr"


Return on all videos pages

Return on all videos pages

--- app/assets/javascripts/videos/infinitescroll.js.coffee
+++ app/assets/javascripts/videos/infinitescroll.js.coffee
@@ -1,6 +1,6 @@
 $ ->
   # Don't run on non-video pages
-  return if not $('.videos').length
+  return if not $('.videos .videoList').length

   nearBottom = () ->
     $(window).scrollTop() > $(document).height() - $(window).height() - 600


Mark implicit parens generated.

Mark implicit parens generated.

--- rewriter.coffee
+++ rewriter.coffee
@@ -162,7 +162,7 @@
           not ((post = @tokens[i + 1]) and post.generated and post[0] is '{')))

     action = (token, i) ->
-      @tokens.splice i, 0, ['CALL_END', ')', token[2]]
+      @tokens.splice i, 0, @generated(['CALL_END', ')', token[2]])

     @scanTokens (token, i, tokens) ->
       tag     = token[0]
@@ -179,7 +179,7 @@
       return 1 unless callObject or
         prev?.spaced and (prev.call or prev[0] in IMPLICIT_FUNC) and
         (tag in IMPLICIT_CALL or not (token.spaced or token.newLine) and tag in IMPLICIT_UNSPACED_CALL)
-      tokens.splice i, 0, ['CALL_START', '(', token[2]]
+      tokens.splice i, 0, @generated(['CALL_START', '(', token[2]])
       @detectEnd i + 1, condition, action
       prev[0] = 'FUNC_EXIST' if prev[0] is '?'
       2


debounce call to update ve placeholder

debounce call to update ve placeholder

--- app/assets/javascripts/views/paper_edit_view.js.coffee
+++ app/assets/javascripts/views/paper_edit_view.js.coffee
@@ -10,7 +10,10 @@

   bindPlaceholderEvent: ->
     $('.editable').on "keyup", "div[contenteditable]", (e) =>
-      @set('controller.showPlaceholder', @get('visualEditor.isEmpty'))
+      Ember.run.debounce(@, @updatePlaceholder, 1000)
+
+  updatePlaceholder: ->
+    @set('controller.showPlaceholder', @get('visualEditor.isEmpty'))

   applyManuscriptCss:(->
     $('#paper-body').attr('style', @get('controller.model.journal.manuscriptCss'))


345 improvement

345 improvement

--- src/server.coffee
+++ src/server.coffee
@@ -51,19 +51,19 @@
   #
   _write_pipe: ->
     setInterval (=>
-      return if @buffer.length == 0
-      console.log "writing buffer #{@buffer}"
-      @ws.write(@buffer, (err, written) =>
-        throw err if err
-        @buffer = ''
-      )
+      if @buffer.length > 0
+        @ws.write(@buffer, (err, written) =>
+          throw err if err
+          # @ws.flush()
+          @buffer = ''
+        )
     ), 15

   #
   # convert halo rgba string to a UART instruction
   # @example
-  #   _data_to_instruction({ color: '000,110,255,000\n' })
-  #   # => '4,1,000,110,255,000;'
+  #   _data_to_instruction({ color: '000,110,255,000\n255,000,000,000' })
+  #   # => '345,5,1,255,000,000;2,255,000,000,3,000,000,000,4,000,000,000,5,000,000,000;'
   #
   _data_to_instruction: (data) ->
     # break colors string into array


reset the message/lenght variables after processing audit

--- src/server.coffee
+++ src/server.coffee
@@ -298,6 +298,10 @@
         logger.info "[Auditing #{type}] Received message from #{sock.remoteAddress}"
         auditing.processAudit message, -> logger.info "[Auditing #{type}] Processed audit"

+        # reset message and length variables
+        message = ""
+        length = 0
+
     sock.on 'error', (err) ->
       logger.error err


Add arrows to relations with direction

Add arrows to relations with direction

--- app/frontend/javascripts/views/visualization-canvas.js.coffee
+++ app/frontend/javascripts/views/visualization-canvas.js.coffee
@@ -5,6 +5,7 @@

   TWO_PI:          2*Math.PI
   HALF_PI:         Math.PI*0.5
+  SIXTH_PI:        Math.PI/6
   LABEL_MAX_WIDTH: 130
   context:         null
   quadtree:        null
@@ -199,40 +200,46 @@

   drawNodes: ->
     @data_nodes.forEach (d) =>
+      x = d.x|0
+      y = d.y|0
+      size = d.size|0
       # set styles
       @context.fillStyle = d.fill
       # draw node
       @context.beginPath()
-      @context.moveTo d.x|0, d.y|0
-      @context.arc d.x|0, d.y|0, d.size|0, 0, @TWO_PI, true
+      @context.moveTo x, y
+      @context.arc x, y, size, 0, @TWO_PI, true
       @context.fill()
       @context.closePath()
       # draw image
       if d.img
-        @context.save()
-        @context.clip()
-        @context.drawImage d.imgObj, (d.x-d.size)|0, (d.y-d.size)|0, (2*d.size)|0, (2*d.size)|0
-        @context.restore()
+        @drawNodeImage d.imgObj, x-size, y-size, 2*size

   drawNodesActive: ->
     @data_nodes.forEach (d) =>
+      x = d.x|0
+      y = d.y|0
+      size = d.size|0
       # set styles
       @context.lineWidth = d.strokeWidth
       @context.strokeStyle = d.stroke
       @context.fillStyle = d.fill
       # draw node
       @context.beginPath()
-      @context.moveTo d.x|0, d.y|0
-      @context.arc d.x|0, d.y|0, d.size|0, 0, @TWO_PI, true
+      @context.moveTo x, y
+      @context.arc x, y, size, 0, @TWO_PI, true
       @context.fill()
       @context.stroke()
       @context.closePath()
       # draw image
       if d.img
-        @context.save()
-        @context.clip()
-        @context.drawImage d.imgObj, (d.x-d.size)|0, (d.y-d.size)|0, (2*d.size)|0, (2*d.size)|0
-        @context.restore()
+        @drawNodeImage d.imgObj, x-size, y-size, 2*size
+
+  drawNodeImage: (img, x, y, size) ->
+    @context.save()
+    @context.clip()
+    @context.drawImage img, x, y, size, size
+    @context.restore()

   drawNodesLabels: ->
     # set styles
@@ -245,17 +252,20 @@

   drawNodeLabel: (d) =>
     ypos = null
+    x = d.x|0
+    y = d.y|0
+    size = d.size|0
     @context.fillStyle = d.fontColor
     @context.font      = '300 '+d.fontSize+'px Montserrat'
     if (@parameters.showNodesLabelComplete or @node_hovered or @node_active) and d.long_label
       d.long_label.forEach (line, i) =>
-        ypos = (d.y+d.size+(i*d.fontSize))|0
-        @context.strokeText line, d.x|0, ypos+1
-        @context.fillText   line, d.x|0, ypos
-    else
-      ypos = (d.y+d.size)|0
-      @context.strokeText d.short_label, d.x|0, ypos+1
-      @context.fillText   d.short_label, d.x|0, ypos
+        ypos = y+size+(i*d.fontSize)
+        @context.strokeText line, x, ypos+1
+        @context.fillText   line, x, ypos
+    else
+      ypos = y+size
+      @context.strokeText d.short_label, x, ypos+1
+      @context.fillText   d.short_label, x, ypos

   drawRelations: ->
     # make stroke color dynamic based on nodes state !!!
@@ -269,8 +279,10 @@
     @context.strokeStyle = '#cccccc'
     @context.beginPath()
     @data_relations_visibles.forEach (link) =>
-      @context.moveTo link.source.x|0, link.source.y|0
-      @context.lineTo link.target.x|0, link.target.y|0
+      if link.direction
+        @drawRelationArrow link.source, link.target
+      else
+        @drawRelation link.source, link.target
     @context.stroke()
     @context.closePath()

@@ -286,10 +298,39 @@
     @data_relations_visibles.forEach (link) =>
       @context.strokeStyle = link.color
       @context.beginPath()
-      @context.moveTo link.source.x|0, link.source.y|0
-      @context.lineTo link.target.x|0, link.target.y|0
+      if link.direction
+        @drawRelationArrow link.source, link.target
+      else
+        @drawRelation link.source, link.target
       @context.stroke()
       @context.closePath()
+
+  drawRelation: (source, target) ->
+    @context.moveTo source.x|0, source.y|0
+    @context.lineTo target.x|0, target.y|0
+
+  drawRelationArrow: (source, target) ->
+    # vector auxiliar methods from https://stackoverflow.com/questions/13165913/draw-an-arrow-between-two-circles
+    length  = ({x,y}) -> Math.sqrt(x*x + y*y)
+    sum     = ({x:x1,y:y1}, {x:x2,y:y2}) -> {x:x1+x2, y:y1+y2}
+    diff    = ({x:x1,y:y1}, {x:x2,y:y2}) -> {x:x1-x2, y:y1-y2}
+    prod    = ({x,y}, scalar) -> {x:x*scalar, y:y*scalar}
+    div     = ({x,y}, scalar) -> {x:x/scalar, y:y/scalar}
+    unit    = (vector) -> div(vector, length(vector))
+    scale   = (vector, scalar) -> prod(unit(vector), scalar)
+    free    = ([coord1, coord2]) -> diff(coord2, coord1)
+
+    v2 = scale free([source, target]), target.size
+    p2 = diff target, v2
+
+    dx = p2.x-source.x
+    dy = p2.y-source.y
+    angle = Math.atan2 dy, dx
+    @context.moveTo source.x|0, source.y|0
+    @context.lineTo p2.x, p2.y
+    @context.lineTo p2.x-6*Math.cos(angle-@SIXTH_PI), p2.y-6*Math.sin(angle-@SIXTH_PI)
+    @context.moveTo p2.x, p2.y
+    @context.lineTo p2.x-6*Math.cos(angle+@SIXTH_PI), p2.y-6*Math.sin(angle+@SIXTH_PI)

   drawRelationsLabels: ->
     @context.textBaseline = 'bottom'


fix assignment disappearing from view when added to new group with drag and drop

fixes CNVS-18904

test plan:
- already have a group with at least 1 assignment
- create a new group
- drag an existing assignment to the new group
- then add an assignment with the "+" on the new group
- both assignments should still be visible
- assignment list items in group should have no change to expected behaviors

Change-Id: I5dc18e5008d293b8ebb57d97878ed0db27e88eda
Reviewed-on: https://gerrit.instructure.com/49787
Tested-by: Jenkins
Reviewed-by: Mike Nomitch <74443f6f110b6b7b934c89126258ed3d843d673f@instructure.com>
Reviewed-by: Simon Williams <088e16a1019277b15d58faf0541e11910eb756f6@instructure.com>
QA-Review: Adam Stone <a0b2b61e2edcf99aa16080c2254a6ae6923d1fac@instructure.com>
Product-Review: Hilary Scharton <b55b20a171673afabe1f3f421d6770a86afaa815@instructure.com>

--- app/coffeescripts/views/DraggableCollectionView.coffee
+++ app/coffeescripts/views/DraggableCollectionView.coffee
@@ -98,17 +98,22 @@
       @_removeFromGroup(model)
       @_addToGroup(model)

+    # must explicitly update @empty attribute from CollectionView class so view
+    # will properly recognize if it does/doesn't have items on subsequent
+    # re-renders, since drag & drop doesn't trigger a render
     _removeFromGroup: (model) ->
       old_group_id = model.get(@groupKey)
       old_group = @parentCollection.findWhere id: old_group_id
       old_children = old_group.get(@childKey)
       old_children.remove(model, {silent: true})
+      @empty = _.isEmpty(old_children.models)

     _addToGroup: (model) ->
       model.set(@groupKey, @groupId)
       new_group = @parentCollection.findWhere id: @groupId
       new_children = new_group.get(@childKey)
       new_children.add(model, {silent: true})
+      @empty = false if @empty

     # Internal: On a user's sort action, update the sort order on the server.
     #


new ljdc

new ljdc

--- src/codinglove.coffee
+++ src/codinglove.coffee
@@ -26,10 +26,10 @@

 module.exports = (robot)->
   robot.respond /(donne moi de la )?joie( bordel)?/i, (message)->
-    send_meme message, 'http://lesjoiesducode.fr/random', (text)->
+    send_new_meme message, 'http://lesjoiesducode.fr/random', (text)->
       message.send text
   robot.respond /derni[èe]re joie/i, (message)->
-    send_meme message, 'http://lesjoiesducode.fr', (text)->
+    send_new_meme message, 'http://lesjoiesducode.fr', (text)->
       message.send text
   robot.respond /((give me|spread) some )?(joy|love)( asshole)?/i, (message)->
     send_meme message, 'http://thecodinglove.com/random', (text)->
@@ -38,6 +38,19 @@
     send_meme message, 'http://thecodinglove.com', (text)->
       message.send text

+send_new_meme = (message, location, response_handler)->
+  url = location
+
+  message.http(url).get() (error, response, body)->
+    return response_handler "Sorry, something went wrong" if error
+
+    if response.statusCode == 302 || response.statusCode == 301
+      location = response.headers['location']
+      return send_new_meme(message, location, response_handler)
+
+    img_src = get_meme_image(body, ".ljdc-posts .blog-post video img")
+
+    txt = get_meme_txt(body, ".ljdc-posts .blog-post h1.blog-post-title")

 send_meme = (message, location, response_handler)->
   url = location


fix if no video tag

fix if no video tag

--- src/codinglove.coffee
+++ src/codinglove.coffee
@@ -48,7 +48,7 @@
       location = response.headers['location']
       return send_new_meme(message, location, response_handler)

-    img_src = get_meme_image(body, ".ljdc-posts .blog-post video img")
+    img_src = get_meme_image(body, ".ljdc-posts .blog-post .blog-post-content img")

     txt = get_meme_txt(body, ".ljdc-posts .blog-post h1.blog-post-title a")


Fix parameter handling for export.

Fix parameter handling for export.

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -271,19 +271,18 @@
       .option '-l, --language [lang]', 'Language used on export for category names (default is en)', 'en'
       .option '--queryType <type>', 'Whether to do a query or a search request', 'query'
       .option '--queryEncoded', 'Whether the given query string is already encoded or not', false
-      .option '--fillAllRows', 'When given product attributes like name will be added to each variant row.', false
-      .option '--categoryBy', 'Define which identifier should be used to for the categories column - either slug or externalId. If nothing given the named path is used.'
+      .option '--fillAllRows', 'When given product attributes like name will be added to each variant row.'
+      .option '--categoryBy <name>', 'Define which identifier should be used to for the categories column - either slug or externalId. If nothing given the named path is used.'
       .usage '--projectKey <project-key> --clientId <client-id> --clientSecret <client-secret> --template <file> --out <file>'
       .action (opts) ->
         GLOBALS.DEFAULT_LANGUAGE = opts.language

         return _subCommandHelp('export') unless program.projectKey
-
         ProjectCredentialsConfig.create()
         .then (credentials) ->
           options =
-            fillAllRows: program.fillAllRows
-            categoryBy: program.categoryBy
+            fillAllRows: opts.fillAllRows
+            categoryBy: opts.categoryBy
             client:
               config: credentials.enrichCredentials
                 project_key: program.projectKey


Missed a console.log

Missed a console.log

--- src/coffeelint.coffee
+++ src/coffeelint.coffee
@@ -227,7 +227,6 @@
     checkTrailingWhitespace : () ->
         if regexes.trailingWhitespace.test(@line)
             # By default only the regex above is needed.
-            console.log @config['no_trailing_whitespace']?.allowed_in_comments
             if !@config['no_trailing_whitespace']?.allowed_in_comments
                 return @createLineError('no_trailing_whitespace')


Updated atom config with preview tabs

Updated atom config with preview tabs

--- editors/atom/config.cson
+++ editors/atom/config.cson
@@ -8,8 +8,7 @@
   editor:
     fontFamily: "Source Code Pro"
     tabLength: 4
-    invisibles:
-      {}
+    invisibles: {}
     fontSize: 14
   core:
     projectHome: "~/Projects"
@@ -19,15 +18,10 @@
     ]
   minimap:
     v4Preview: true
-  linter:
-    {}
-  "linter-flake8":
-    {}
-  "autocomplete-plus":
-    {}
-  "atom-terminal":
-    {}
+  linter: {}
+  "linter-flake8": {}
+  "autocomplete-plus": {}
+  "atom-terminal": {}
   tabs:
-    {}
-  "tree-view":
-    {}
+    usePreviewTabs: true
+  "tree-view": {}


style: prefer postfix loop

style: prefer postfix loop

--- client/Framework/components/upload/kdmultipartuploader.coffee
+++ client/Framework/components/upload/kdmultipartuploader.coffee
@@ -61,8 +61,8 @@

         arrb = new ArrayBuffer len
         ui8a = new Uint8Array arrb
-        while i--
-          ui8a[i] = body.charCodeAt(i) & 0xff
+
+        ui8a[i] = body.charCodeAt(i) & 0xff  while i--

         blob = new Blob [ui8a]
         xhr.send blob


group data: bugfix: this is where the array was coming from

--- client/app/Applications/Groups.kdapplication/groupdata.coffee
+++ client/app/Applications/Groups.kdapplication/groupdata.coffee
@@ -1,10 +1,4 @@
 class GroupData extends KDEventEmitter
-
-  constructor:(currentGroup="koding")->
-    super
-
-    KD.remote.on 'ready', =>
-      KD.remote.cacheable currentGroup, (err, group)=> @setGroup group

   getAt:(path)->
     JsPath.getAt @data, path


Greentest TransactionManager transactions should respond

#8 QueryHandlers should also handle query transmission

--- test/unit/transactions/TransactionManager.spec.coffee
+++ test/unit/transactions/TransactionManager.spec.coffee
@@ -49,6 +49,16 @@
         @transactionErrorCb
       @transaction = @manager.getTransaction @address, @id

+      @responseCallbacks = [
+        @responseCb
+        @transactionResponseCb
+      ]
+      @errorCallbacks = [
+        @errorCb
+        @transactionErrorCb
+      ]
+      @callbacks = @responseCallbacks.concat @errorCallbacks
+

     afterEach ()->
       jasmine.clock().uninstall()
@@ -76,3 +86,12 @@
         expect(callback).toHaveBeenCalled()

       expect(@manager._clearTransaction).toHaveBeenCalledTimes 1
+
+    it 'should respond', ()->
+      for callback in @callbacks
+        expect(callback).not.toHaveBeenCalled()
+
+      @transaction.respond 'a response'
+
+      for callback in @responseCallbacks
+        expect(callback).toHaveBeenCalled()


React must render something.

React must render something.

--- core/app/backbone/views/react_install_extension_button.coffee
+++ core/app/backbone/views/react_install_extension_button.coffee
@@ -23,9 +23,6 @@
       _span [options.iconClass]
       'Install Factlink for ' + browserName.capitalize()

-
-
-
 window.ReactInstallExtensionOrBookmarklet = React.createClass
   displayName: 'ReactInstallExtensionOrBookmarklet'
   render: ->
@@ -48,7 +45,7 @@
         disabled: true],
         'Factlink already installed.'
     else if (extension_installed || !browserName) && !@props.huge_button
-      []
+      _div [], # nothing.
     else
       ReactInstallExtensionButton
         extra_class: extra_class


fix: test cases

fix: test cases

--- tests/integration/components/file-details-test.coffee
+++ tests/integration/components/file-details-test.coffee
@@ -14,4 +14,4 @@
   @render hbs """{{file-details}}"""

-  assert.equal @$().text().trim(), 'High: Medium: Low: Passed: Unknown: Package: Version: PDF Password:   PDF ReportManual'
+  assert.equal @$().text().trim(), 'High: Medium: Low: Passed: Unknown: PackageVersionPDF Password  Copy PasswordPDF ReportManual'


add more delay to toggle article meta-data

- so that double-click selections work better without toggling the meta-data

--- app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee
+++ app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee
@@ -239,11 +239,12 @@
   toggleMetaWithDelay: (e) =>
     # allow double click select
     # by adding a delay to the toggle
-
-    if @lastClick and +new Date - @lastClick < 80
+    delay = 120
+
+    if @lastClick and +new Date - @lastClick < delay
       clearTimeout(@toggleMetaTimeout)
     else
-      @toggleMetaTimeout = setTimeout(@toggleMeta, 80, e)
+      @toggleMetaTimeout = setTimeout(@toggleMeta, delay, e)
       @lastClick = +new Date

   toggleMeta: (e) =>


the select rectangle is still not trigger the correct method

--- app/assets/javascripts/components/mark/tools/rectangle-tool/index.cjsx
+++ app/assets/javascripts/components/mark/tools/rectangle-tool/index.cjsx
@@ -97,6 +97,10 @@
     x: (SELECTED_RADIUS / @props.xScale) * Math.cos theta
     y: -1 * (SELECTED_RADIUS / @props.yScale) * Math.sin theta

+  handleMouseDown: ->
+    console.log 'handleMouseDown()'
+    @props.onSelect @props.mark
+
   render: ->
     console.log "Render: Rectangle STATE @ Render", @state
     classString = "rectangleTool"
@@ -117,26 +121,28 @@

     console.log "render props.clickOffset", @props.clickOffset
     console.log "render props", @props
+    <g
+      tool={this}
+      onMouseDown={@handleMouseDown}
+    >
+      <g className = {classString}
+      onMouseDown={@props.onSelect unless @props.disabled}>

-    <g className = {classString} onMouseDown={@props.onSelect unless @props.disabled}>
+        <Draggable
+          onStart = {@props.handleMarkClick}
+          onDrag = {@handleMainDrag} >
+          <polyline points={points} strokeWidth="5" stroke="orange" fill="none"/>
+        </Draggable>

-
-      <Draggable
-        onStart = {@props.handleMarkClick}
-        onDrag = {@handleMainDrag} >
-        <polyline points={points} strokeWidth="5" stroke="orange" fill="none"/>
-      </Draggable>
-
-      { if @props.selected
-        <g>
-          <DeleteButton tool={this} x={@state.x + (width * DELETE_BUTTON_DISTANCE)} y={@state.y} />
-          <DragHandle x={@props.mark.x} y={@props.mark.y}
-          onDrag={@handleTopLeftDrag}
-          />
-        </g>
-      }
-
-
+        { if @props.selected
+          <g>
+            <DeleteButton tool={this} x={@state.x + (width * DELETE_BUTTON_DISTANCE)} y={@state.y} />
+            <DragHandle x={@props.mark.x} y={@props.mark.y}
+            onDrag={@handleTopLeftDrag}
+            />
+          </g>
+        }
+      </g>
     </g>


updated Bandango.RetencionFormView

updated Bandango.RetencionFormView

--- app/assets/javascripts/views/retenciones/retencion_form_view.js.coffee
+++ app/assets/javascripts/views/retenciones/retencion_form_view.js.coffee
@@ -1,8 +1,24 @@
-Bandango.RetencionFormView = Ember.View.extend Bandango.RetencionFuenteOnFormMixin,
+Bandango.RetencionFormView = Bandango.ModelBackedView.extend Bandango.RetencionFuenteOnFormMixin,
   templateName: "retenciones/form"
+  compraBinding: "controller.model"
+  attributes: [ "numeroAutorizacion",
+                "numeroSerieEstablecimiento",
+                "numeroSeriePuntoEmision",
+                "numeroSerieSecuencial",
+                "fechaEmision",
+                "conceptoRetencionFuente",
+                "compra" ]
+
+  newConceptoRetencion: (conceptoRetencionFuente) ->
+    @_super conceptoRetencionFuente
+    @set "conceptoRetencionFuente", conceptoRetencionFuente

   model: (->
     compra = @get("controller.model")
     store = @get("controller.store")
-    store.createRecord("retencion", compra: compra)
+    store.createRecord("retencion", compra: compra, inForm: true)
   ).property("controller.model")
+
+  actions:
+    addRetencion: ->
+      @get("controller.store").createRecord "retencion", @getFormData()


Fix direction value in new relation rows

--- app/frontend/javascripts/views/visualization-table-relations.js.coffee
+++ app/frontend/javascripts/views/visualization-table-relations.js.coffee
@@ -100,10 +100,11 @@
   addModel: (index) ->
     # We need to set `wait = true` to wait for the server before adding the new model to the collection
     # http://backbonejs.org/#Collection-create
-    model = @collection.create {dataset_id: $('body').data('id'), wait: true}
+    model = @collection.create {dataset_id: $('body').data('id'), 'direction': true, wait: true}
     # We wait until model is synced in server to get its id
     @collection.once 'sync', () ->
       @table.setDataAtRowProp index, 'id', model.id
+      @table.setDataAtRowProp index, 'direction', true
     , @

   # Method called from parent class `VisualizationTableBase`


test travis failures with due date

test travis failures with due date

--- tutor/specs/components/scores/homework-cell.spec.cjsx
+++ tutor/specs/components/scores/homework-cell.spec.cjsx
@@ -30,7 +30,8 @@

   it 'renders score cell', ->
     @props.task.completed_exercise_count = @props.task.exercise_count - 1
-    @props.due_at = moment().add(1, 'day')
+    @props.due_at = moment().add(10, 'day')
+    expect(TH.isDue(@props.task)).to.eq(false)
     wrapper = mount(<Cell {...@props} />)
     expect(wrapper.find('.score a').text()).to.equal('---')
     expect(wrapper.find('.late-caret')).to.have.length(0)


Sim: Mummy doesn't activate on Mummy

Sim: Mummy doesn't activate on Mummy


removed derp benchmark

removed derp benchmark

--- bench/bench.coffee
+++ bench/bench.coffee
@@ -1,69 +0,0 @@
-Orpheus = require '../index'
-redis = require 'redis'
-metrics = require 'metrics'
-async = require 'async'
-
-client = redis.createClient()
-log = console.log
-PREFIX = 'orpheus:benchmark'
-Orpheus.configure
-	client: client
-	prefix: PREFIX
-
-rand_str = (len = 20) ->
-	("abcdefghijklmnopqrstwxyz"[Math.floor(Math.random() * 24)] for i in [1..len]).join('')
-
-rand_num = (min = 0, max = 10000) ->
-	min + Math.floor(Math.random() * max)
-
-class Player extends Orpheus
-	constructor: ->
-		@str 'small'
-		@str 'long'
-		@num 'points'
-player = Player.create()
-REQUESTS = 20000
-
-log "  Orpheus Benchmark"
-log "------------------------"
-
-test = (desc, fn) ->
-	return (callback) ->
-		i = 0
-		time = new Date().getTime()
-		async.whilst ->
-				i < REQUESTS
-			, (cb) ->
-				i++
-				fn cb
-			, (err) ->
-				log "#{desc} | #{REQUESTS} requests | #{new Date().getTime() - time}ms"
-				callback err
-
-timer = new Date().getTime()
-async.series [
-			test "String | new id | small", (cb) -> player().small.set(rand_str(5)).exec(cb)
-		,
-			test "String | new id | long", (cb) -> player().long.set(rand_str(500)).exec(cb)
-		,
-			test "Number | new id | points", (cb) -> player().points.set(rand_num(50000, 1000000)).exec(cb)
-	], (err) ->
-		if err
-			log "error."
-		log "Test Time: #{new Date().getTime() - timer}ms"
-		log "flushing benchmark keys..."
-
-		client.keys "#{PREFIX}*", (err, keys) ->
-			if err
-				log "problem flushing benchmark keys"
-				process.exit 1
-
-			async.forEach keys, (i, cb) ->
-						client.del i, cb
-				, (err, res) ->
-					if err
-						log "problem cleaning test db"
-						process.exit 1
-					else
-						log "done."
-						process.exit()


debug log

debug log

--- routes/lib/speaker.coffee
+++ routes/lib/speaker.coffee
@@ -10,6 +10,7 @@
   if this.body?
     channel = this.body.channel_name;
   else
+    console.log this.body
     channel = "announcement"

   thebody = this.body


Remove console.log.

Remove console.log.

--- src/coffee/exportmapping.coffee
+++ src/coffee/exportmapping.coffee
@@ -55,7 +55,6 @@

     if @header.has(CONS.HEADER_CATEGORIES)
       row[@header.toIndex CONS.HEADER_CATEGORIES] = _.reduce(product.categories or [], (memo, category, index) =>
-        console.log "CAT %j", category, @categoryService.id2fqName
         memo += CONS.DELIM_MULTI_VALUE unless index is 0
         memo + @categoryService.id2fqName[category.id]
       , '')


Allow crypto credentials details to be supplied in config.options.cryptoCredentialsDetails .

--- src/connection.coffee
+++ src/connection.coffee
@@ -175,6 +175,7 @@
     @config.options.tdsVersion ||= DEFAULT_TDS_VERSION
     @config.options.isolationLevel ||= ISOLATION_LEVEL.READ_UNCOMMITTED
     @config.options.encrypt ||= false
+    @config.options.cryptoCredentialsDetails ||= {}

     if !@config.options.port && !@config.options.instanceName
       @config.options.port = DEFAULT_PORT
@@ -379,7 +380,7 @@
     )

   initiateTlsSslHandshake: ->
-    credentials = crypto.createCredentials()
+    credentials = crypto.createCredentials(@config.options.cryptoCredentialsDetails)
     @securePair = tls.createSecurePair(credentials)

     @securePair.on('secure', =>


check if publish date exists before converting

--- api/apps/articles/model/index.coffee
+++ api/apps/articles/model/index.coffee
@@ -118,17 +118,14 @@
   }

 @present = (article) =>
-  if article?.scheduled_publish_at
-    scheduled = moment(article.scheduled_publish_at).toISOString()
-  else
-    scheduled = null
-
+  scheduled = if (date = article?.scheduled_publish_at) then moment(date).toISOString() else null
+  published = if (date = article?.published_at) then moment(date).toISOString() else null
   _.extend article,
     id: article?._id?.toString()
     _id: undefined
     slug: _.last article.slugs
     slugs: undefined
-    published_at: moment(article?.published_at).toISOString()
+    published_at: published
     scheduled_publish_at: scheduled
     updated_at: moment(article?.updated_at).toISOString()


Typo fix: usefull -> useful

Typo fix: usefull -> useful

--- docker_tutorial/static/js/steps.coffee
+++ docker_tutorial/static/js/steps.coffee
@@ -183,7 +183,7 @@

Check your running image

You now have a running container. Let's see what is going on.

Using docker ps we can see a list of all running containers, and using docker inspect
-      we can see all sorts of usefull information about this container.

+      we can see all sorts of useful information about this container.

       """
 assignment: """

Assignment


app-settings-menu: Added app menu items for Ace.

--- client/landing/app/Applications/Ace.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Ace.kdapplication/AppController.coffee
@@ -1,12 +1,36 @@
 class AceAppController extends AppController

   KD.registerAppClass @,
-    name         : "Ace"
-    multiple     : yes
-    hiddenHandle : no
-    openWith     : "lastActive"
-    route        : "/Develop"
-    behavior     : "application"
+    name          : "Ace"
+    multiple      : yes
+    hiddenHandle  : no
+    openWith      : "lastActive"
+    route         : "/Develop"
+    behavior      : "application"
+    menu          : [
+      {
+        title     : "Save"
+        eventName : "save"
+      }
+      {
+        title     : "Save As"
+        eventName : "saveAs"
+      }
+      {
+        type      : "separator"
+      }
+      {
+        title     : "Compile and Run"
+        eventName : "compileAndRun"
+      }
+      {
+        type      : "separator"
+      }
+      {
+        title     : "Preview"
+        eventName : "preview"
+      }
+    ]
     # mimeTypes    : "text"

   constructor: (options = {}, data)->


explicit resize

explicit resize

--- src/controller.coffee
+++ src/controller.coffee
@@ -210,7 +210,7 @@
       # This stage of ICE editor construction, which is repeated
       # whenever the editor is resized, should adjust the sizes
       # of all the ICE editor componenents to fit the wrapper.
-      window.addEventListener 'resize', => @resize()
+      window.addEventListener 'resize', => @resizeBlockMode()

       # ## Tracker Events
       # We allow binding to the tracker element.
@@ -268,7 +268,7 @@
       @tree = new model.Segment()
       @tree.start.insert @cursor

-      @resize()
+      @resizeBlockMode()

       # Now that we've populated everything, immediately re@draw.
       @redrawMain(); @redrawPalette()
@@ -280,7 +280,14 @@
     # all of the natively-added canvases, as well
     # as the wrapper element, whenever a resize
     # occurs.
-    resize: ->
+    resizeTextMode: ->
+      @resizeAceElement()
+      @aceEditor.resize true
+
+    resizeBlockMode: ->
+      @resizeTextMode()
+      @resizeGutter()
+
       @meltElement.style.left = "#{@paletteElement.offsetWidth}px"
       @meltElement.style.height = "#{@wrapperElement.offsetHeight}px"
       @meltElement.style.width ="#{@wrapperElement.offsetWidth - @paletteWrapper.offsetWidth}px"
@@ -294,9 +301,12 @@
       @transitionContainer.style.left = "#{@gutter.offsetWidth}px"

       @resizePalette()
-
-      for binding in editorBindings.resize
-        binding.call this
+      @resizePaletteHighlight()
+      @resizeNubby()
+      @resizeMainScroller()
+      @resizeLassoCanvas()
+      @resizeCursorCanvas()
+      @resizeDragCanvas()

       # Re-scroll and redraw main
       @scrollOffsets.main.y = @mainScroller.scrollTop
@@ -331,6 +341,12 @@
       @paletteHighlightCtx.setTransform 1, 0, 0, 1, -@scrollOffsets.palette.x, -@scrollOffsets.palette.y

       @redrawPalette()
+
+  Editor::resize = ->
+    if @currentlyUsingBlocks
+      @resizeBlockMode()
+    else
+      @resizeTextMode()

   # RENDERING CAPABILITIES
@@ -373,7 +389,8 @@

     @redrawMain()

-  hook 'resize', 0, -> @setTopNubbyStyle @nubbyHeight, @nubbyColor
+  Editor::resizeNubby = ->
+    @setTopNubbyStyle @nubbyHeight, @nubbyColor

   Editor::redrawMain = (opts = {}) ->
     unless @currentlyAnimating_suprressRedraw
@@ -788,7 +805,7 @@
     @dragCtx.clearRect 0, 0, @dragCanvas.width, @dragCanvas.height

   # On resize, we will want to size the drag canvas correctly.
-  hook 'resize', 0, ->
+  Editor::resizeDragCanvas = ->
     @dragCanvas.width = 0
     @dragCanvas.height = 0

@@ -1436,7 +1453,7 @@

     @paletteWrapper.appendChild @paletteHighlightCanvas

-  hook 'resize', 0, ->
+  Editor::resizePaletteHighlight = ->
     @paletteHighlightCanvas.style.top = @paletteHeader.offsetHeight + 'px'
     @paletteHighlightCanvas.width = @paletteCanvas.width
     @paletteHighlightCanvas.height = @paletteCanvas.height
@@ -1561,7 +1578,7 @@

           @redrawTextInput()

-  hook 'resize', 0, ->
+  Editor::resizeAceElement = ->
     @aceElement.style.width = "#{@wrapperElement.offsetWidth}px"
     @aceElement.style.height = "#{@wrapperElement.offsetHeight}px"

@@ -2022,7 +2039,7 @@

   # Deal with resize for the lasso
   # select canvas
-  hook 'resize', 0, ->
+  Editor::resizeLassoCanvas = ->
     @lassoSelectCanvas.width = @meltElement.offsetWidth
     @lassoSelectCanvas.style.width = "#{@lassoSelectCanvas.width}px"

@@ -2633,7 +2650,7 @@

   Editor::copyAceEditor = ->
     @gutter.style.width = @aceEditor.renderer.$gutterLayer.gutterWidth + 'px'
-    @resize()
+    @resizeBlockMode()

   hook 'populate', 0, ->
     @aceElement = document.createElement 'div'
@@ -3076,7 +3093,7 @@
           for div in translatingElements
             div.parentNode.removeChild div

-          @resize()
+          @resizeBlockMode()

           @fireEvent 'toggledone', [@currentlyUsingBlocks]

@@ -3145,7 +3162,7 @@

       @redrawPalette()

-  hook 'resize', 0, ->
+  Editor::resizeMainScroller = ->
     @mainScroller.style.width = "#{@meltElement.offsetWidth}px"
     @mainScroller.style.height = "#{@meltElement.offsetHeight}px"

@@ -3214,7 +3231,7 @@

   Editor::setFontSize = (fontSize) ->
     @setFontSize_raw fontSize
-    @resize()
+    @resizeBlockMode()

   # LINE MARKING SUPPORT
   # ================================
@@ -3388,7 +3405,7 @@
       @mainCanvas.opacity = @paletteWrapper.opacity =
         @highlightCanvas.opacity = 1

-      @resize(); @redrawMain()
+      @resizeBlockMode(); @redrawMain()

     else
       oldScrollTop = @aceEditor.session.getScrollTop()
@@ -3408,7 +3425,7 @@
       @mainCanvas.opacity =
         @highlightCanvas.opacity = 0

-      @resize()
+      @resizeBlockMode()

   # DRAG CANVAS SHOW/HIDE HACK
   # ================================
@@ -3565,7 +3582,7 @@

     @meltElement.appendChild @cursorCanvas

-  hook 'resize', 0, ->
+  Editor::resizeCursorCanvas = ->
     @cursorCanvas.width = @meltElement.offsetWidth
     @cursorCanvas.style.width = "#{@cursorCanvas.width}px"

@@ -3692,8 +3709,10 @@

     @meltElement.appendChild @gutter

-  hook 'resize', 0, ->
+  Editor::resizeGutter = ->
     @gutter.style.width = @aceEditor.renderer.$gutterLayer.gutterWidth + 'px'
+    @gutter.style.height = "#{Math.max @meltElement.offsetHeight, @view.getViewNodeFor(@tree).totalBounds?.height ? 0}px"
+

   Editor::addLineNumberForLine = (line) ->
     treeView = @view.getViewNodeFor @tree
@@ -3752,12 +3771,9 @@
     if changedBox
       @gutter.style.height = "#{Math.max @mainScroller.offsetHeight, treeView.totalBounds.height}px"

-  hook 'resize', 0, ->
-    @gutter.style.height = "#{Math.max @meltElement.offsetHeight, @view.getViewNodeFor(@tree).totalBounds?.height ? 0}px"
-
   Editor::setPaletteWidth = (width) ->
     @paletteWrapper.style.width = width + 'px'
-    @resize()
+    @resizeBlockMode()

   # COPY AND PASTE
   # ================================


Fix socket tabbing bug

Fix socket tabbing bug

--- src/controller.coffee
+++ src/controller.coffee
@@ -1731,10 +1731,10 @@
               parseParent.start.prev.append newParse
               newParse.container.end.append parseParent.end.next

-              newParse.parent = newParse.start.parent = newParse.end.parent =
+              newParse.container.parent = newParse.parent = newParse.container.end.parent =
                 parseParent.parent

-              newParse.notifyChange()
+              newParse.container.notifyChange()

               @addMicroUndoOperation new ReparseOperation parseParent, newParse.container

@@ -2302,7 +2302,8 @@
     head = parent.start
     charsCounted = 0

-    until charsCounted >= chars and head.type is 'socketStart' and head.next.type is 'text'
+    until charsCounted >= chars and head.type is 'socketStart' and
+        (head.next.type is 'text' or head.next is head.container.end)
       if head.type is 'text' then charsCounted += head.value.length

       head = head.next
@@ -2323,6 +2324,7 @@
           persistentParent = @textFocus.parent.parent

           chars = getCharactersTo persistentParent, head.container.start
+          console.log 'chars:', chars
           @setTextInputFocus null
           socket = getSocketAtChar persistentParent, chars
         else


Fixes misnamed variable.

Fixes misnamed variable.

--- src/controller.coffee
+++ src/controller.coffee
@@ -119,7 +119,7 @@
 		catch e
 			# Throws an error if the expression was not valid JavaScript
 			throw new Error e.message + ' in observer binding:\n`' + expr + '`\n' +
-			'Compiled binding:\n' + functionBody
+			'Compiled binding:\n' + normalizedExpr
 		func


Add score adjustment to fuzzy search in tasks, with high priority for tasks that start with the search term, medium for tasks that contain the search term, and low for tasks that don't contain the search term

--- SingularityUI/app/views/tasks.coffee
+++ SingularityUI/app/views/tasks.coffee
@@ -45,6 +45,14 @@
         @listenTo @taskKillRecords, 'change', @render

         @fuzzySearch = _.memoize(@fuzzySearch)
+
+    adjustedScore: (filter, task) ->
+        if task.original.id.toLowerCase().startsWith(filter.toLowerCase())
+            task.score * 10
+        else if task.original.id.toLowerCase().indexOf(filter.toLowerCase()) > -1
+            task.score * 5
+        else
+            task.score

     fuzzySearch: (filter, tasks) =>
         host =
@@ -55,7 +63,7 @@
                 "#{o.id}"
         res1 = fuzzy.filter(filter, tasks, host)
         res2 = fuzzy.filter(filter, tasks, id)
-        _.pluck(_.sortBy(_.union(res1, res2), (r) => r.score), 'original')
+        _.pluck(_.sortBy(_.union(res1, res2), (t) => @adjustedScore(filter, t)), 'original')

     # Returns the array of tasks that need to be rendered
     filterCollection: =>


account: slight style fix

account: slight style fix

--- workers/social/lib/social/models/account/index.coffee
+++ workers/social/lib/social/models/account/index.coffee
@@ -949,6 +949,7 @@
       routingKey: @profile.nickname
       event, contents
     }
+
   getInvitiationRequestRelationships:(options, status, callback)->
     JInvitationRequest = require '../invitationrequest'

@@ -957,7 +958,7 @@

       selector =
         $or: [
-          {'koding.username': @profile.nickname,}
+          {'koding.username': @profile.nickname}
           {email: user.email}
         ]
         status: status


post: remove "permit" wrapping from #reply

reason being, the implementation takes a constructor as a parameter, which means that in practice, this will not be "shareable".  Clients can't really pass constructors to the server

--- workers/social/lib/social/models/messages/post.coffee
+++ workers/social/lib/social/models/messages/post.coffee
@@ -344,62 +344,61 @@
     ]
     daisy queue

-  reply: permit 'reply to posts',
-    success:(client, replyType, comment, callback)->
-      {delegate} = client.connection
-      exempt = delegate.checkFlag('exempt')
-      comment = new replyType body: comment
-      comment.sign(delegate).save (err)=>
-        return callback err if err
-        daisy queue = [
-          ->
-            delegate.addContent comment, (err)->
-              return callback err if err
-              queue.next()
-          ->
-            delegate.updateMetaModifiedAt (err)->
-              return callback err if err
-              queue.next()
-          =>
-            @addComment comment, flags: {isLowQuality: exempt}, (err, docs)=>
-              return callback err if err
-              queue.docs = docs
-              queue.next()
-          =>
-            Relationship.count {sourceId: @getId(),as:'reply'}, (err, count)=>
-              queue.relationshipCount = count
-              return callback err if err
-              queue.next()
-          =>
-            @update $set: repliesCount: queue.relationshipCount, (err)=>
-              return callback err if err
-              queue.next()
-          =>
-            @fetchOrigin (err, origin)=>
-              return callback err if err
-              unless exempt
-                @emit 'ReplyIsAdded', {
-                  origin
-                  subject       : ObjectRef(@).data
-                  actorType     : 'replier'
-                  actionType    : 'reply'
-                  replier       : ObjectRef(delegate).data
-                  reply         : ObjectRef(comment).data
-                  repliesCount  : queue.relationshipCount
-                  relationship  : queue.docs[0]
-                }
-              queue.next()
-          =>
-            @follow client, emitActivity: no, (err)->
-              return callback err if err
-              queue.next()
-          =>
-            @addParticipant delegate, 'commenter', (err)->
-              return callback err if err
-              queue.next()
-          ->
-            callback null, comment
-        ]
+  reply: (client, replyType, comment, callback)->
+    {delegate} = client.connection
+    exempt = delegate.checkFlag('exempt')
+    comment = new replyType body: comment
+    comment.sign(delegate).save (err)=>
+      return callback err if err
+      daisy queue = [
+        ->
+          delegate.addContent comment, (err)->
+            return callback err if err
+            queue.next()
+        ->
+          delegate.updateMetaModifiedAt (err)->
+            return callback err if err
+            queue.next()
+        =>
+          @addComment comment, flags: {isLowQuality: exempt}, (err, docs)=>
+            return callback err if err
+            queue.docs = docs
+            queue.next()
+        =>
+          Relationship.count {sourceId: @getId(),as:'reply'}, (err, count)=>
+            queue.relationshipCount = count
+            return callback err if err
+            queue.next()
+        =>
+          @update $set: repliesCount: queue.relationshipCount, (err)=>
+            return callback err if err
+            queue.next()
+        =>
+          @fetchOrigin (err, origin)=>
+            return callback err if err
+            unless exempt
+              @emit 'ReplyIsAdded', {
+                origin
+                subject       : ObjectRef(@).data
+                actorType     : 'replier'
+                actionType    : 'reply'
+                replier       : ObjectRef(delegate).data
+                reply         : ObjectRef(comment).data
+                repliesCount  : queue.relationshipCount
+                relationship  : queue.docs[0]
+              }
+            queue.next()
+        =>
+          @follow client, emitActivity: no, (err)->
+            return callback err if err
+            queue.next()
+        =>
+          @addParticipant delegate, 'commenter', (err)->
+            return callback err if err
+            queue.next()
+        ->
+          callback null, comment
+      ]


Disable tech works

Disable tech works

--- server/server.coffee
+++ server/server.coffee
@@ -54,11 +54,13 @@

 configurePassport(app, db)

+###
 app.use (req, res, next) ->
     if not req.user?.admin
         res.status(503).send("На сервере проводятся технические работы. Ожидаемая продолжительность — до часа.")
         return
     next()
+###

 setupApi(app)


adjust Config to expose its instance to exports which allows its use as a raw class (i.e. in app.config() and such methods where the app has not been initialized yet and configuration is needed)

--- app/templates/app/src/Config/Config.coffee
+++ app/templates/app/src/Config/Config.coffee
@@ -47,7 +47,7 @@
             if value? and i+1 is path.length
                 setting[prop] = value

-            setting = setting[prop]
+            setting = setting?[prop]

         return setting

@@ -71,4 +71,8 @@

             settings = settings[prop]

-module.exports = (app)-> app.factory 'Config', -> new Config+module.exports = (app)->
+    configuration = new Config
+    app?.factory? 'Config', -> configuration
+
+    return configuration


chore(core): remove room from the watch

chore(core): remove room from the watch

--- scripts/gitter-activity-notifier.coffee
+++ scripts/gitter-activity-notifier.coffee
@@ -5,7 +5,6 @@
 roomNames = [
     'AleksueiR/CyberTests'
     'fgpv-vpgf'
-    'fgpv-vpgf/fgpv-vpgf'
     'fgpv-vpgf/gulp-i18n-csv'
     'fgpv-vpgf/Scrum'
 ]


Fix logic, task lacks correct keys forTaskHelper

--- tutor/src/components/student-dashboard/event-info-icon.cjsx
+++ tutor/src/components/student-dashboard/event-info-icon.cjsx
@@ -3,7 +3,6 @@
 S = require '../../helpers/string'
 {TimeStore} = require '../../flux/time'
 moment   = require 'moment'
-TH = require '../../helpers/task'

 module.exports = React.createClass
   displayName: 'EventInfoIcon'
@@ -12,17 +11,22 @@
     event: React.PropTypes.object.isRequired

   render: ->
-    due = moment(@props.event.due_at)
-    now = TimeStore.getNow()
+    {event} = @props

-    return null if due.isAfter(now, 'd') and TH.hasLateWork(@props.event)
+    now   = TimeStore.getNow()
+    dueAt = moment(event.due_at)
+    isIncomplete = event.complete_exercise_count isnt event.exercise_count
+    pastDue      = event.type is 'homework' and dueAt.isBefore(now, 'd')
+    workedLate   = moment(event.last_worked_at).isAfter(dueAt)
+
+    return null unless workedLate or (pastDue and isIncomplete)

     # use 'day' granularity for checking if the due date is today or after today
-    status = if due.isSame(now, 'd') then 'incomplete' else 'late'
+    status = if dueAt.isSame(now, 'd') then 'incomplete' else 'late'

     tooltip =
       <BS.Tooltip
-        id="event-info-icon-#{@props.event.id}">
+        id="event-info-icon-#{event.id}">
         <b>{S.capitalize(status)}</b>
       </BS.Tooltip>


Split redrawing of datasets and reloading into two separate functions, which are called independently

Signed-off-by: Marko Locher <9efe9a5a1da5f41a4eb7599f2715dc24abf5bbc8@locher.at>

--- src/d3.timeslider.coffee
+++ src/d3.timeslider.coffee
@@ -140,56 +140,63 @@
                 ranges: []
             }

-            @updateDataset(dataset.id)
+            reloadDataset(dataset.id)

         @updateDataset = (dataset) =>
-            callback = debounce(100, dataset, =>
+            el = @svg.select("g.datasets #dataset-#{dataset}")
+            d = @data[dataset]
+
+            # ranges
+            el.selectAll('path').remove()
+            r = el.selectAll('path')
+                .data(d.ranges)
+
+            r.enter().append('path')
+                .attr('d',
+                    d3.svg.line()
+                        .x( (d) => @scales.x(d) )
+                        .y( -5 * d.index )
+                        .interpolate('linear')
+                    )
+                .attr('stroke', d.color)
+
+            r.exit().remove()
+
+            # points
+            el.selectAll('circle').remove()
+            p = el.selectAll('circle')
+                .data(d.points)
+                .remove()
+
+            p.enter().append('circle')
+                    .attr('cx', (d) => @scales.x( new Date(d) ) )
+                    .attr('cy', "#{-5 * d.index}")
+                    .attr('fill', d.color)
+                    .attr('r', 2)
+
+            p.exit().remove()
+
+        reloadDataset = (dataset) =>
+            callback = debounce(50, dataset, =>
                 @data[dataset].callback(@scales.x.domain()[0], @scales.x.domain()[1], (id, data) =>
                     el = @svg.select("g.datasets #dataset-#{id}")
-                    d = @data[id]
-
-                    d.ranges = []
-                    d.points = []
+                    ranges = []
+                    points = []

                     for element in data
                         if(element.length > 1)
-                            d.ranges.push(element)
+                            ranges.push(element)
                         else
-                            d.points.push(element)
-
-                    # ranges
-                    el.selectAll('path').remove()
-                    r = el.selectAll('path')
-                        .data(d.ranges)
-
-                    r.enter().append('path')
-                        .attr('d',
-                            d3.svg.line()
-                                .x( (d) => @scales.x(d) )
-                                .y( -5 * d.index )
-                                .interpolate('linear')
-                            )
-                        .attr('stroke', d.color)
-
-                    r.exit().remove()
-
-                    # points
-                    el.selectAll('circle').remove()
-                    p = el.selectAll('circle')
-                        .data(d.points)
-                        .remove()
-
-                    p.enter().append('circle')
-                            .attr('cx', (d) => @scales.x( new Date(d) ) )
-                            .attr('cy', "#{-5 * d.index}")
-                            .attr('fill', d.color)
-                            .attr('r', 2)
-
-                    p.exit().remove()
+                            points.push(element)
+
+                    @data[id].ranges = ranges
+                    @data[id].points = points
+                    @updateDataset(id)
                 )
             )
             callback()

+
         for dataset in @options.datasets
             do (dataset) => @drawDataset(dataset)

@@ -203,6 +210,7 @@

             # repaint the datasets
             for dataset of @data
+                reloadDataset(dataset)
                 @updateDataset(dataset)

         # resizing (the window)


need to test, but finished off deploying an app to heroku

--- src/deploy/heroku.coffee
+++ src/deploy/heroku.coffee
@@ -20,36 +20,23 @@
 checkApps = (msg, config) ->
   heroku.apps().list (err, res) ->
     app = _.find(res, { name: config.appname })
-    msg.send "You already have an app called this name, deploying code to this app" if app
-    return createBuild msg, config if app
+    msg.send "You already have an app called: #{config.appname}, deploying code to this app" if app
+    return createBuild msg, config, new Date() if app
     createApp msg, config
-
-

 createApp = (msg, config) ->
   msg.send "Creating the heroku app: #{config.appname}"
+  heroku.apps().create name: config.appname, (err, app) ->
+    return msg.reply "Couldn't create the app: #{config.appname}, this name could be taken" if err
+    msg.send "The app: #{config.appname} was successfully created!"
+    createBuild msg, config, app.released_at

-# createApp = (msg, appName, tarball) ->

-#     appName = appName.substring(0, 30)
-
-#     # create app
-#     msg.send "Creating the heroku app called: `#{appName}`"
-#     heroku.apps().create name: appName, (err, apps) ->
-#       console.log err, apps
-#       if err
-#         if err.body.message == "Name is already taken"
-#           msg.reply "The heroku app: `#{appName}` already exists, therefore creating a new build, this will fail if you don't own this app"
-#           createBuild msg, appName, tarball, Date.now()
-#         else
-#           msg.reply "There was an error trying to create the heroku app: `#{appName}`"
-#       else
-#         msg.send "Creating a new build for the new heroku app: `#{apps.name}`"
-#         createBuild msg, apps.name, tarball, apps.released_at
-
-
-    # Create build
-    # POST /apps/{app id or name}/builds -> source_blob_url, source_blob_version
+createBuild = (msg, config, version) ->
+    heroku.apps(config.appname).builds().create source_blob: url: config.tarball, version: version, (err, build) ->
+      console.log err, build
+      return msg.reply "The build failed" if err
+      msg.send "The app #{config.url} was successfully deployed to heroku"


disable loading bar so only the loading circle is visible

--- app/assets/javascripts/app.js.coffee
+++ app/assets/javascripts/app.js.coffee
@@ -8,6 +8,12 @@
 ])

 @baseControllers = angular.module("baseControllers", [])
+
+@suploy.config [
+  "cfpLoadingBarProvider"
+  (cfpLoadingBarProvider) ->
+    cfpLoadingBarProvider.includeBar = false
+]

 @suploy.run [
   "$templateCache"


Fix/highlight in book search (#1409)

Fix/highlight in book search (#1409)

* Modified latest.coffee so that url will maintain the minimal parameter

* Modified the code to be more succinct

* changed latest.coffee to maintain minimal view when going to updated version from minimal view.

* Fixed a whitespace error.

* Added a space for consistency.

* Added a check to make sure that the page version does not get added if undefined.

* Fixed a whitespace error

--- src/scripts/modules/media/tabs/contents/contents.coffee
+++ src/scripts/modules/media/tabs/contents/contents.coffee
@@ -152,7 +152,10 @@
         return if page.get('searchHtml')
         book = page.get('book')
         bookId = "#{book.get('id')}@#{book.get('version')}"
-        pageId = "#{page.get('id')}@#{page.get('version')}"
+        pageId = "#{page.get('id')}"
+        pageVersion = page.get('version')
+        pageId += "@#{pageVersion}" if pageVersion?
+
         BookSearchResults.fetch(
           bookId: "#{bookId}:#{pageId}"
           query: response.query.search_term


minor fix in set(cycle)

minor fix in set(cycle)

--- src/aniSprite.coffee
+++ src/aniSprite.coffee
@@ -61,7 +61,7 @@
             to.stop ?= to.start + env.ANICYCLE_DEFAULT_CONFIG.numFrames - 1
             to.name ?= if what.slice(5) then what.slice(5) else env.ANICYCLE_DEFAULT_CONFIG.name
             @_ani.cycles.push(new AniCycle(to))
-            @_ani.current ?= to
+            @_ani.current ?= @_ani.cycles[0]
         else
             super what, to
         this


Fixed issue for root user not being allowed to be deleted

--- src/api/users.coffee
+++ src/api/users.coffee
@@ -126,15 +126,15 @@
     return;
   }

+  var email = unescape (email);
+
   // Test if the user is root@openhim.org
-  if ( this.authenticated.email === 'root@openhim.org' ) {
+  if ( email === 'root@openhim.org' ) {
     logger.info('User ' +this.authenticated.email+ ' is OpenHIM root, User cannot be deleted through the API')
     this.body = 'User ' +this.authenticated.email+ ' is OpenHIM root, User cannot be deleted through the API'
     this.status = 'forbidden';
     return;
   }
-
-  var email = unescape (email);

   try {
     yield User.findOneAndRemove({ email: email }).exec();


more debug to know when we actually have a peer connection

--- app/assets/javascripts/webrtc.coffee
+++ app/assets/javascripts/webrtc.coffee
@@ -215,6 +215,9 @@
     @peers[peer_id] = peer_connection
     peer_connection.oniceconnectionstatechange = (ev) ->
       console.log('oniceconnectionstatechange', ev)
+      console.log('peer_connection.iceConnectionState == ' + peer_connection.iceConnectionState )
+      if( peer_connection.iceConnectionState == 'completed' )
+        console.log('WE HAVE A PEER CONNECTION....')
     peer_connection.onicecandidate = (event) =>
       if (event.candidate)
         @send('relay', {


disable debug

disable debug

--- lib/main.coffee
+++ lib/main.coffee
@@ -3,7 +3,7 @@

 module.exports = InnoSetupCore =
   subscriptions: null
-  debug: true
+  debug: false
   which: null
   prefix: null


cleanup

cleanup

--- lib/main.coffee
+++ lib/main.coffee
@@ -172,7 +172,9 @@
       needToLog = false

     land = (editor) =>
-      @land(editor, {point, direction, needToLog})
+      @land(editor, point)
+      if settings.get('debug') and needToLog
+        @logHistory(direction)

     activePane = atom.workspace.getActivePane()
     if editor.getURI() is URI
@@ -183,7 +185,7 @@
     else
       atom.workspace.open(URI, searchAllPanes: settings.get('searchAllPanes')).then(land)

-  land: (editor, {point, direction, needToLog}) ->
+  land: (editor, point) ->
     originalRow = editor.getCursorBufferPosition().row

     editor.setCursorBufferPosition(point, autoscroll: false)
@@ -191,9 +193,6 @@

     if settings.get('flashOnLand') and (originalRow isnt point.row)
       @flash(editor)
-
-    if settings.get('debug') and needToLog
-      @logHistory(direction)

   flashMarker: null
   flash: (editor) ->


:art: Remove an extra comma

:art: Remove an extra comma

--- lib/main.coffee
+++ lib/main.coffee
@@ -19,6 +19,6 @@
             return {
               type: error.id.substr(1, error.id.length - 2)
               text: "#{error.code} - #{error.reason}"
-              filePath,
+              filePath
               range: [point, point]
             }


Conditionally add dev mode commands inside the `activate` method

--- lib/main.coffee
+++ lib/main.coffee
@@ -45,6 +45,18 @@

     @subscriptions.add atom.commands.add 'atom-workspace', 'core:cancel', ->
       notification.dismiss() for notification in atom.notifications.getNotifications()
+
+    if atom.inDevMode()
+      @subscriptions.add atom.commands.add 'atom-workspace', 'notifications:toggle-dev-panel', -> Notifications.togglePanel()
+      @subscriptions.add atom.commands.add 'atom-workspace', 'notifications:trigger-error', ->
+        try
+          abc + 2 # nope
+        catch error
+          options =
+            detail: error.stack.split('\n')[1]
+            stack: error.stack
+            dismissable: true
+          atom.notifications.addFatalError("Uncaught #{error.stack.split('\n')[0]}", options)

   deactivate: ->
     @subscriptions.dispose()
@@ -101,16 +113,4 @@
     return true if fs.isAbsolute(file)
   false

-if atom.inDevMode()
-  atom.commands.add 'atom-workspace', 'notifications:toggle-dev-panel', -> Notifications.togglePanel()
-  atom.commands.add 'atom-workspace', 'notifications:trigger-error', ->
-    try
-      abc + 2 # nope
-    catch error
-      options =
-        detail: error.stack.split('\n')[1]
-        stack: error.stack
-        dismissable: true
-      atom.notifications.addFatalError("Uncaught #{error.stack.split('\n')[0]}", options)
-
 module.exports = Notifications


:fire: unused

:fire: unused

--- lib/main.coffee
+++ lib/main.coffee
@@ -1,4 +1,4 @@
-{CompositeDisposable, Disposable, Emitter, Range} = require 'atom'
+{CompositeDisposable, Disposable, Emitter} = require 'atom'
 _ = require 'underscore-plus'
 settings = require './settings'
 QuickHighlightView = require './quick-highlight-view'


dyndoc home

dyndoc home

--- lib/main.coffee
+++ lib/main.coffee
@@ -26,7 +26,7 @@
 module.exports =
   configDefaults:
     dyndoc: 'local' # or 'server'
-    dyndocHome: path.join process.env["HOME"],"devel","dyndoc"
+    dyndocHome: path.join process.env["HOME"],"dyndoc"
     addToPath: '/usr/local/bin'
     localServer: true
     localServerUrl: 'localhost'


#update #17

#update #17

--- lib/main.coffee
+++ lib/main.coffee
@@ -32,6 +32,7 @@

 app.commandLine.appendSwitch 'ppapi-flash-path', flashPath
 app.commandLine.appendSwitch 'ppapi-flash-version', flashVersion
+app.commandLine.appendSwitch 'register-pepper-plugins', ';application/x-shockwave-flash'
 # Quit when all windows are closed.
 app.on 'window-all-closed', ->
   # On OS X it is common for applications and their menu bar


Add description for cursorPositionFormat configuration item

--- lib/main.coffee
+++ lib/main.coffee
@@ -10,6 +10,7 @@
     cursorPositionFormat:
       type: 'string'
       default: '%L:%C'
+      description: 'Format for the cursor position status bar element, where %L is the line number and %C is the column number'

   activate: ->
     @statusBar = new StatusBarView()


remove more startup stuff

remove more startup stuff

--- app/client/lib/meteor/startup.coffee
+++ app/client/lib/meteor/startup.coffee
@@ -1,9 +1,8 @@

-
+###
 Deps.autorun ->
   if Meteor.user() and not Meteor.loggingIn()

-    ###
     Meteor.call "getHash", Meteor.user().services?.google?.email, (error, result) ->
         Session.set "userEmailHash", result

@@ -19,7 +18,7 @@
             app_id: "6b4e12edd77380cb4b223fc8d76dd7f75f33259a"

         Intercom("boot", intercomSettings)
-    ###
+###

 Meteor.startup ->
     console.log("Meteor Start on Client")


use a separate function for hidden file check

--- app/coffee/OutputCacheManager.coffee
+++ app/coffee/OutputCacheManager.coffee
@@ -64,7 +64,7 @@
 				results = []
 				async.mapSeries outputFiles, (file, cb) ->
 					# don't send dot files as output, express doesn't serve them
-					if file?.path?.match(/^\.|\/./)
+					if OutputCacheManager._fileIsHidden(file.path)
 						logger.warn compileDir: compileDir, path: file.path, "ignoring dotfile in output"
 						return cb()
 					# copy other files into cache directory if valid
@@ -149,6 +149,9 @@
 				removeDir dir, cb
 			, callback

+	_fileIsHidden: (path) ->
+		return path?.match(/^\.|\/./)?
+
 	_checkFileIsSafe: (src, callback = (error, isSafe) ->) ->
 		# check if we have a valid file to copy into the cache
 		fs.stat src, (err, stats) ->


Fixed problem with save issues without attachment

--- app/coffee/controllers/issues.coffee
+++ app/coffee/controllers/issues.coffee
@@ -450,12 +450,18 @@
         $scope.$emit("spinner:start")

         promise.then (data) ->
-            saveNewAttachments($scope.projectId, data.id).then () ->
+            finishSubmit = ->
                 $scope.$emit("spinner:stop")
                 closeModal()
                 $scope.overlay.close()
                 $scope.defered.resolve($scope.form)
                 $gmFlash.info($i18next.t('issue.issue-saved'))
+
+            if $scope.newAttachments.length > 0
+                saveNewAttachments($scope.projectId, data.id).then ->
+                    finishSubmit()
+            else
+                finishSubmit()

         promise.then null, (data) ->
             $scope.checksleyErrors = data


tabs -> spaces

tabs -> spaces

--- lib/req2.coffee
+++ lib/req2.coffee
@@ -1,17 +1,17 @@
 require 'coffee-script'

 req = (lib) ->
-	#TODO handle http(s)
-	try
-		require lib
-	catch e
-		require('fs').readFileSync lib
+  #TODO handle http(s)
+  try
+    require lib
+  catch e
+    require('fs').readFileSync lib

 req_each = (each) ->
-	req lib for lib in each
+  req lib for lib in each

 module.exports = (libs...) ->
-	if libs.length == 1
-		(if Array.isArray libs[0] then req_each else req) libs[0]
-	else
-		req_each libs
+  if libs.length == 1
+    (if Array.isArray libs[0] then req_each else req) libs[0]
+  else
+    req_each libs


Refactor: getWordFrequency and $timeout after typing

--- app/scripts/controllers/words.coffee
+++ app/scripts/controllers/words.coffee
@@ -14,12 +14,12 @@
       $scope.words = []
       $scope.getRepWords()
     $scope.$watch "wordQuery", ->
+      $timeout.cancel
       if $scope.wordQuery == ""
         $scope.wordFrequency = "?"
       else
         $scope.wordFrequency = "..."
-      $timeout.cancel
-      $timeout($scope.getWordFrequency(), 2000)
+        $timeout($scope.getWordFrequency(), 2000)
     $scope.$watch "state", ->
       $scope.getRepList()


Clampable#clampToBounds

Clampable#clampToBounds

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -26,7 +26,7 @@
   ###*
   @name clampToBounds
   @methodOf Clampable#
-  @param {}
+  @param {Rectangle}
   ###
   clampToBounds: (bounds) ->
     bounds ||= Rectangle x: 0, y: 0, width: App.width, height: App.height


Clampable#clampToBounds

Clampable#clampToBounds

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -10,4 +10,4 @@
     Object.extend(I.clampData, data)

   clampToBounds: (bounds) ->
-    bounds ||= Rectangle x: 0, y: 0, widthApp.width, App.height+    bounds ||= Rectangle x: 0, y: 0, width: App.width, height: App.height


minor formatting

minor formatting

--- fizzylogo_Objects.coffee
+++ fizzylogo_Objects.coffee
@@ -88,6 +88,7 @@

       soFarEverythingMatched = true
       originalMethodInvocationStart = methodInvocation.cursorStart
+

       until eachSignature.isEmpty() or methodInvocation.isEmpty()


[ADD] Room redirection

[ADD] Room redirection

Room redirection on room creation.


Filter results without gh field

Filter results without gh field

--- src/scripts/control.search.js.coffee
+++ src/scripts/control.search.js.coffee
@@ -70,6 +70,14 @@

     @_addLayer(@resultMarkers)

+  _filterResults: (results) ->
+    valid = []
+    $.each(results, (index, item) ->
+      if item._source?.gh isnt undefined
+        valid.push(item)
+    )
+    valid
+
   _generateMarker: (result) ->
     search = this

@@ -134,7 +142,7 @@
         size: 100
         sort: "SISN:desc"
     }).done((results) =>
-      @_addResults(results.hits.hits)
+      @_addResults(@_filterResults(results.hits.hits))
       @searchBar.stopActivity()
     )
 })


more progress on binary search

more progress on binary search


Fixed single param not getting parsed correctly.

--- src/chalkboard.coffee
+++ src/chalkboard.coffee
@@ -147,12 +147,41 @@
   # @description
   # multiLineKey has value a.b when used in multiple line argument
   # description. This function get the correct key based on the index
+  # @param {Integer} index Key index
   #
   _getMultiLineKey = (index) ->
     keys  = multiLineKey.split "."
     index = keys.length + index if index < 0
     return "" if keys.length is 0 or index < 0 or index > keys.length
     keys[index]
+
+  #
+  # @chalk function
+  # @function
+  # @private
+  # @name _updateSection
+  # @description
+  # Check if current section or argument object are empty or not,
+  # push object to the correct array if necessary
+  #
+  _updateSection = ->
+    if hasComment and not _(currentSection).isEmpty()
+
+      # Check if there is remaining argObject to be cleared
+      if multiLineKey and not _(argObject).isEmpty()
+        _setAttribute(currentSection,
+          _getMultiLineKey(0),
+          argObject,
+          definitions[_getMultiLineKey(0)]
+        )
+
+        multiLineKey = ""
+        argObject    = {}
+
+      allSections.push currentSection
+      currentSection = {}
+
+    hasComment = false

   for line in code.split(NEW_LINE)
     # Check for starting and ending comment block
@@ -262,28 +291,11 @@
         )

     else
-      if hasComment and not _(currentSection).isEmpty()
-
-        # Check if there is remaining argObject to be cleared
-        if multiLineKey and not _(argObject).isEmpty()
-          _setAttribute(currentSection,
-            _getMultiLineKey(0),
-            argObject,
-            definitions[_getMultiLineKey(0)]
-          )
-
-          multiLineKey = ""
-          argObject    = {}
-
-        allSections.push currentSection
-        currentSection = {}
-
-      hasComment = false
+      _updateSection()

   # Push the last section if there was no new line at the
   # end of the file
-  if not _(currentSection).isEmpty()
-    allSections.push currentSection
+  _updateSection()

   return allSections


Cache clearing enhancement (collections + small refactoring)

--- src/client/api.coffee
+++ src/client/api.coffee
@@ -200,6 +200,8 @@
         dfd

       models = {}
+      collections = {}
+
       setupModel = (attrs, raw)->
         model = generateModel(attrs, raw)
         model.on 'change', ->
@@ -231,8 +233,11 @@
         throw new Error('A model must have an identifier...') unless attrs?._id?
         models[attrs._id] || setupModel(attrs, raw || false)

-      api.model.clearAll =->
-        models = _.pick(models, 'me', 'app', 'org')
+      # Clears the cache
+      app.core.mediator.on 'hull.currentUser', (hasUser)->
+        if (!hasUser)
+          models = _.pick(models, 'me', 'app', 'org')
+          collections = {}

       generateModel = (attrs, raw) ->
         _Model = if raw then RawModel else Model
@@ -260,8 +265,6 @@
         model: Model
         sync: sync

-
-      collections = {}

       setupCollection = (path)->
         collection      = new Collection


Use versioned API endpoints

Use versioned API endpoints

--- src/api.coffee
+++ src/api.coffee
@@ -13,7 +13,7 @@
 		.then(-> utils.delay(ms))
 		.then(-> fs.writeFileAsync(LED_FILE, 0))

-api.post('/blink', (req, res) ->
+api.post('/v1/blink', (req, res) ->
 	interval = setInterval(blink, 400)
 	setTimeout(->
 		clearInterval(interval)
@@ -21,7 +21,7 @@
 	res.send(200)
 )

-api.post('/update', (req, res) ->
+api.post('/v1/update', (req, res) ->
 	console.log('TODO: Update the application')
 )


Add `port` in available default options

Add `port` in available default options

--- src/app.coffee
+++ src/app.coffee
@@ -39,6 +39,7 @@
   driver: "memory"
   params: {}
   address: null
+  port: null

 if process.env.HOME
   CONFIG_FILES.push path.join process.env.HOME, ".ofirehose.json"


Make sure the supervisor version update is also retried until succeeding.

--- src/app.coffee
+++ src/app.coffee
@@ -36,9 +36,13 @@
 		console.log('Starting API server..')
 		secret = randomstring.generate()
 		api(secret).listen(config.listenPort)
+
+		# Let API know what version we are, and our api connection info.
+		console.log('Updating supervisor version and api info')
 		application.updateDeviceInfo(
 			api_port: config.listenPort
 			api_secret: secret
+			supervisor_version: utils.supervisorVersion
 			# Retry the device info update every 5s until it finally succeeds.
 			5000
 		)
@@ -64,9 +68,3 @@
 		console.log('Starting periodic check for IP addresses..')
 		setInterval(updateIpAddr, 30 * 1000) # Every 30s
 		updateIpAddr()
-
-		# Let API know we are running a new version
-		console.log('Updating supervisor version:', utils.supervisorVersion)
-		application.updateDeviceInfo(
-			supervisor_version: utils.supervisorVersion
-		)


improved code

improved code

--- src/app.coffee
+++ src/app.coffee
@@ -118,7 +118,10 @@
     @_onStep  = []

   setTempo: (@_bpm) ->
-    @refresh()
+    restart = @_interval?
+
+    @stop()
+    @start() if restart

   stop: ->
     clearInterval(@_interval) if @_interval?
@@ -132,10 +135,4 @@
     , 60 / @_bpm / 4 * 1000)

   onStep: (fnc) ->
-    @_onStep.push(fnc)
-
-  refresh: ->
-    restart = @_interval?
-
-    @stop()
-    @start() if restart
+    @_onStep.push(fnc)


Final commit

Final commit


latex editor -- fix a bug due to path differences on vm's.

--- salvus/page/editor.coffee
+++ salvus/page/editor.coffee
@@ -1467,7 +1467,7 @@
                     opts.cb(output.stderr); return
                 s = output.stdout
                 i = s.indexOf('\nInput:')
-                input = s.slice(i+8, s.indexOf('\n',i+3))
+                input = s.slice(i+7, s.indexOf('\n',i+3))

                 # normalize path to be relative to project home
                 j = input.indexOf('/./')
@@ -1475,7 +1475,10 @@
                     fname = input.slice(j+3)
                 else
                     j = input.indexOf('/../')
-                    fname = input.slice(j+1)
+                    if j != -1
+                        fname = input.slice(j+1)
+                    else
+                        fname = input
                 if @path != './'
                     input = @path + '/' + fname
                 else
@@ -2431,7 +2434,6 @@
                 if result
                     @set_resolution(result)
         else
-            console.log('setting res to #{res}')
             try
                 res = parseInt(res)
                 if res < 150
@@ -3043,4 +3045,4 @@
 class Slideshow extends FileEditor
     constructor: (@editor, @filename, content, opts) ->
         opts = @opts = defaults opts,{}
-        @element = $("
Salvus slideshow not implemented yet.
")+        @element = $("
Salvus slideshow not implemented yet.
")


Move headerBuffer into ChunkedLineReader for consistency

--- src/chunked-line-reader.coffee
+++ src/chunked-line-reader.coffee
@@ -8,13 +8,12 @@
     return i if buffer[i] == char
   -1

-headerBuffer = new Buffer(256)
-
 module.exports =
 class ChunkedLineReader extends Readable

   @CHUNK_SIZE: 10240
   @chunkedBuffer: null
+  @headerBuffer: new Buffer(256)

   constructor: (@filePath) ->
     super()
@@ -26,7 +25,7 @@
       offset = 0
       remainder = ''
       chunkSize = @constructor.CHUNK_SIZE
-      return if isBinaryFile(headerBuffer, fs.readSync(fd, headerBuffer, 0, 256))
+      return if isBinaryFile(@constructor.headerBuffer, fs.readSync(fd, @constructor.headerBuffer, 0, 256))

       @constructor.chunkedBuffer ?= new Buffer(chunkSize)
       chunkedBuffer = @constructor.chunkedBuffer


Changed format.

Changed format.

--- src/tucker.coffee
+++ src/tucker.coffee
@@ -18,23 +18,23 @@
 #   with thanks to arsenio

 quotes = [
-  'He\'s useless. He\'s absolutely useless. He\'s as useless as a marzipan dildo.',
-  'You don\'t seem to understand that I\'m going to have to have to mop up a fucking hurricane of piss from all these neurotics.',
-  'Feet off the furniture, you Oxbridge twat. You\'re not in a punt now.',
-  'NOMFuP. N-O-M-F-P. Not My Fucking Problem. I quite like that. Did you like that? I\'ll use that quite a lot today.',
+  'He\'s useless. He\'s absolutely useless. He\'s as useless as a marzipan dildo.',
+  'You don\'t seem to understand that I\'m going to have to have to mop up a fucking hurricane of piss from all these neurotics.',
+  'Feet off the furniture, you Oxbridge twat. You\'re not in a punt now.',
+  'NOMFuP. N-O-M-F-P. Not My Fucking Problem. I quite like that. Did you like that? I\'ll use that quite a lot today.',
   '*knock* *knock* ... Come the fuck in or fuck the fuck off.',
-  'You were like a sweaty octopus trying to unhook a bra.',
-  'Shut it! You\'re using all the minutes on my "Talk until you get head cancer" tariff.',
-  'I mean the guy is an epic fuck-up. He\'s so dense that light bends around him.',
-  'Do you know ninety percent of household dust is made of dead human skin? That\'s what you are, to me.',
-  'What\'s up with you? You look like you\'ve shat a Lego garage.',
+  'You were like a sweaty octopus trying to unhook a bra.',
+  'Shut it! You\'re using all the minutes on my "Talk until you get head cancer" tariff.',
+  'I mean the guy is an epic fuck-up. He\'s so dense that light bends around him.',
+  'Do you know ninety percent of household dust is made of dead human skin? That\'s what you are, to me.',
+  'What\'s up with you? You look like you\'ve shat a Lego garage.',
   'Jesus Christ, see you, you\'re a fucking omnishambles, that\'s what you are. You\'re like that coffee machine, you know: from bean to cup, you fuck up.',
   'I think we should use the \'carrot and stick\' approach. You take a carrot, you stick it up his fucking arse, followed by the stick, followed by an even bigger, rougher carrot.',
   'I\'d love to stop and chat to you but I\'d rather have Type 2 diabetes.',
   'I will tear your fucking skin off, I will wear it to your mother\'s birthday party, and rub your nuts up and down her leg whilst whistling Bohemian fucking Rhapsody. Right?',
   'I could always go and fire a warning shot across his throat.',
   'Stop fucking blinking! Or I will take your optic nerve and strangle you with it!',
-  'Are you sure you\'re working as hard as I am, \'cause I\'m sweating fucking spinal fluid here!',
+  'Are you sure you\'re working as hard as I am, \'cause I\'m sweating fucking spinal fluid here?!',
   'Don\'t get sarcastic with me, son. We burned this tight-arsed city to the ground in 1814. And I\'m all for doing it again, starting with you, you frat fuck. You get sarcastic with me again and I will stuff so much cotton wool down your fucking throat it\'ll come out your arse like the tail on a Playboy bunny.',
   'I will marshal all the forces of darkness to hound you into an assisted suicide.',
   'How dare you! How dare you! Don\'t you ever, EVER, call me a bully! I\'m so much worse than that.',
@@ -44,4 +44,5 @@
 module.exports = (robot) ->
   robot.respond /tucker me/i, (msg)->
     quote = msg.random quotes
-    msg.send quote
+    msg.send "Malcolm says: #{quote}"
+


It's a variable, not a function

It's a variable, not a function

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -149,20 +149,20 @@
               sftpHelper.finish(file)
         .then =>
           logger.info 'Processing files complete'
-          @exitCode 0
+          @exitCode = 0
           # process.exit(0)
       .fail (error) =>
         logger.error error, 'Oops, something went wrong!'
-        @exitCode 1
+        @exitCode = 1
         # process.exit(1)
       .done()
     .fail (err) =>
       logger.error err, "Problems on getting sftp credentials from config files."
-      @exitCode 1
+      @exitCode = 1
       # process.exit(1)
     .done()
 .fail (err) =>
   logger.error err, "Problems on getting client credentials from config files."
-  @exitCode 1
+  @exitCode = 1
   # process.exit(1)
 .done()


added Sphere host optional argument

added Sphere host optional argument

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -5,6 +5,10 @@

 argv = require('optimist')
   .usage('Usage: $0 --projectKey key --clientId id --clientSecret secret --logDir dir --logLevel level --timeout timeout')
+  .describe('projectKey', 'Sphere.io project key (required if you use sphere-specific value transformers).')
+  .describe('clientId', 'Sphere.io HTTP API client id (required if you use sphere-specific value transformers).')
+  .describe('clientSecret', 'Sphere.io HTTP API client secret (required if you use sphere-specific value transformers).')
+  .describe('sphereHost', 'Sphere.io host.')
   .default('logLevel', 'info')
   .default('logDir', '.')
   .default('timeout', 60000)
@@ -29,6 +33,8 @@
     client_id: argv.clientId
     client_secret: argv.clientSecret

+options.baseConfig.host = argv.sphereHost if argv.sphereHost?
+
 updater = new PriceSync options
 updater.run()
 .then (msg) ->


add lineNumber parameter

add lineNumber parameter

--- src/coffeelint.coffee
+++ src/coffeelint.coffee
@@ -286,12 +286,13 @@
         return @lineNumber == @lineCount - 1

     # Return true if the given line actually has tokens.
-    # Optional parameter to check for a specific token type.
-    lineHasToken : (tokenType = null) ->
+    # Optional parameter to check for a specific token type and line number.
+    lineHasToken : (tokenType = null, lineNumber = null) ->
+        lineNumber = lineNumber ? @lineNumber
         unless tokenType?
-            return @tokensByLine[@lineNumber]?
-        else
-            tokens = @tokensByLine[@lineNumber]
+            return @tokensByLine[lineNumber]?
+        else
+            tokens = @tokensByLine[lineNumber]
             return null unless tokens?
             for token in tokens
                 return true if token[0] == tokenType


Non-trivial filter constructor

Non-trivial filter constructor

--- src/tools/vfilter.coffee
+++ src/tools/vfilter.coffee
@@ -8,23 +8,25 @@
 ks.add
   words: keys

-Filter = ->
+Filter = (semver, dist, x64)->
+  @$ = [semver or [], [dist]]
+  @x64 = x64
+  return
+
 Filter:: = require './vfilter.proto'

 # Parser itself
 module.exports =
-parse = (args = [])->
-  r = new Filter
-  for z in args
-    if x = ks.$ z
-      r.dist = x
-    else if (is64 = x64 z)?
-      r.x64 = is64
-    else if /^\d/.test z
-      r.ver = for z in z.split /\D+/ when z.length
-        Number z
-  r.$ = [r.ver or [], [r.dist]]
-  r
+parse = (args)->
+  for arg in args
+    if x = ks.$ arg
+      dist = x
+    else if (is64 = x64 arg)?
+      $64 = is64
+    else if /^\d/.test arg
+      ver = for n in arg.split /\D+/ when n.length
+        Number n
+  new Filter ver, dist, $64

 # Parse x86|x64
 parse.x64 =


Add logging information

Add logging information

--- src/bob.coffee
+++ src/bob.coffee
@@ -71,7 +71,9 @@

       # Check if this iq message is a request for data we know
       stanza = jp.args[0]
+      console.log "Reading"
       if stanza.attrs.type is 'get' and stanza.children[0].name is 'data'
+        console.log "It is data"
         data = stanza.children[0]
         if data.attrs.xmlns is 'urn:xmpp:bob'
           content = cids[data.attrs.cid]


fix(cli): fix broken walkdir call if path doesn't exist

Walkdir must be protected against inexistant root directory.

--- src/cli.coffee
+++ src/cli.coffee
@@ -17,6 +17,8 @@
     require file
   catch err
     console.log file, err
+
+exists = fs.exists or path.exists

 loadSpectacular = (options) ->
   Q.fcall ->
@@ -43,13 +45,17 @@
   if options.noMatchers
     defer.resolve()
   else
-    emitter = walk options.matchersRoot
-    emitter.on 'file', (path, stat) ->
-      if options.verbose
-        console.log "  #{colorize 'load matcher', 'grey', options} #{path}"
-      requireFile path
+    exists options.matchersRoot, (exists) ->
+      if exists
+        emitter = walk options.matchersRoot
+        emitter.on 'file', (path, stat) ->
+          if options.verbose
+            console.log "  #{colorize 'load matcher', 'grey', options} #{path}"
+          requireFile path

-    handleEmitter emitter, defer
+        handleEmitter emitter, defer
+      else
+        defer.resolve()

   defer.promise

@@ -59,13 +65,17 @@
   if options.noHelpers
     defer.resolve()
   else
-    emitter = walk options.helpersRoot
-    emitter.on 'file', (path, stat) ->
-      if options.verbose
-        console.log "  #{colorize 'load helper', 'grey', options} #{path}"
-      requireFile path
+     exists options.helpersRoot, (exists) ->
+      if exists
+        emitter = walk options.helpersRoot
+        emitter.on 'file', (path, stat) ->
+          if options.verbose
+            console.log "  #{colorize 'load helper', 'grey', options} #{path}"
+          requireFile path

-    handleEmitter emitter, defer
+        handleEmitter emitter, defer
+      else
+        defer.resolve()

   defer.promise


Added border box model

Added border box model

--- src/css.coffee
+++ src/css.coffee
@@ -22,6 +22,7 @@
 	overflow: visible;
 	z-index:0;
 	opacity:1;
+	box-sizing: border-box;
 	-webkit-box-sizing: border-box;
 }
 .uilayer.textureBacked {


Fix issue with traits calls and json values

--- src/client/traits/index.coffee
+++ src/client/traits/index.coffee
@@ -7,7 +7,7 @@
     @name = name
     if value?
       # If value is an object, then it has to be compatible
-      if _.isObject value
+      if _.isObject(value) && _.includes(Object.keys(value), 'value') && _.includes(['inc', 'dec', 'set'], value.operation)
         # new Trait('a_number', {value: 20, operation: 'dec'});
         @raw assign({},value,{name:@name})
       else


Disables default logging

Disables default logging

--- source/server.coffee
+++ source/server.coffee
@@ -9,7 +9,7 @@
   Configuration: Space.getenv.multi({
     eventSourcing: {
       log: {
-        enabled: ['SPACE_ES_LOG_ENABLED', true, 'bool']
+        enabled: ['SPACE_ES_LOG_ENABLED', false, 'bool']
       }
       commits: {
         mongoUrl: ['SPACE_ES_COMMITS_MONGO_URL', '', 'string']
@@ -49,17 +49,14 @@
     @commitPublisher = @injector.get('Space.eventSourcing.CommitPublisher')

   onStart: ->
-    console.log('onStart')
     @commitPublisher.startPublishing()

   onReset: ->
-    console.log('onReset')
     @injector.get('Space.eventSourcing.Commits').remove {}
     @injector.get('Space.eventSourcing.Snapshots').remove {}

   onStop: ->
     @commitPublisher.stopPublishing()
-    console.log('onStop')

   _setupLogging: ->
     @injector.map('Space.eventSourcing.Log').to =>


Fix rememberedSocket indexing error when floating blocks are deleted

--- src/controller.coffee
+++ src/controller.coffee
@@ -1079,6 +1079,11 @@
             @session.cursor.document -= 1

           @session.floatingBlocks.splice i, 1
+
+          for socket in @session.rememberedSockets
+            if socket.socket.document > i
+              socket.socket.document -= 1
+
           break
   else if container?
     # No document, so try to remove from container if it was supplied


Persist the location immediately for the benefit of the suggestions API

--- apps/personalize/client/index.coffee
+++ apps/personalize/client/index.coffee
@@ -70,6 +70,6 @@
 module.exports.init = ->
   user = CurrentUser.orNull()
   return unless user
-  user.approximateLocation()
+  user.approximateLocation success: -> user.save()
   new PersonalizeRouter user: user
   Backbone.history.start pushState: true


fix atom save key

fix atom save key


add spec for branching in contest

add spec for branching in contest

--- spec/Thenable.coffee
+++ spec/Thenable.coffee
@@ -524,3 +524,26 @@
         chai.expect(choice.get('non-existant2')).to.equal null
         done()
       t.deliver 'inpt2'
+
+  describe 'branching in contest', ->
+    it 'should resolve', (done) ->
+      multiply = (multiplier, c, data) ->
+        tree = c.tree 'a'
+        tree.deliver data
+        tree.then "#{multiplier}", (c, d) ->
+          c.branch 'doubled', (b, data) ->
+            data * 4
+          c.branch 'tripled', (b, data) ->
+            data * 3
+      t = Root()
+      t.deliver 5
+      .contest "contest-multiply", [
+        multiply.bind @, 2
+      ], (c, results) ->
+        console.log 'score method called'
+        paths = results.map (r) -> r.path
+        idx = paths.indexOf 'root-tripled-then'
+        results[idx]
+      .finally 'enfin-fini',   (c, res) ->
+        chai.expect(res).to.eql [15]
+        done()


Remove extra declaration

Remove extra declaration

--- scripts/home-files.coffee
+++ scripts/home-files.coffee
@@ -63,7 +63,6 @@
             @loadUrlPreview()
             return
         uri = URL.createObjectURL(@file)
-        _ = null
         if @file.type.indexOf('image/') == 0
             _ = document.createElement('img')
             _.src = uri


:memo: Correct typos in spec descriptions

--- spec/fs-plus-spec.coffee
+++ spec/fs-plus-spec.coffee
@@ -29,10 +29,10 @@
       expect(fs.isSymbolicLinkSync(null)).toBe false

   describe ".existsSync(path)", ->
-    it "returns true when path exsits", ->
+    it "returns true when the path exists", ->
       expect(fs.existsSync(fixturesDir)).toBe true

-    it "returns false when path doesn't exsit", ->
+    it "returns false when the path doesn't exist", ->
       expect(fs.existsSync(path.join(fixturesDir, "-nope-does-not-exist"))).toBe false
       expect(fs.existsSync("")).toBe false
       expect(fs.existsSync(null)).toBe false


Make Install::cloneFirstValidGitUrl spec more specific

--- spec/install-spec.coffee
+++ spec/install-spec.coffee
@@ -346,18 +346,19 @@
     describe '::cloneFirstValidGitUrl', ->
       describe 'when cloning a URL fails', ->
         install = null
-        urls = ["url1", "url2", "url3"]
+        urls = ["url1", "url2", "url3", "url4"]

         beforeEach ->
           install = new Install()

           fakeCloneRepository = (url, args...) ->
             callback = args[args.length - 1]
-            callback(new Error("Failed to clone"))
+            unless url is urls[2]
+              callback(new Error("Failed to clone"))

           spyOn(install, "cloneNormalizedUrl").andCallFake(fakeCloneRepository)

-        it 'tries cloning the next URL', ->
+        it 'tries cloning the next URL until one works', ->
           install.cloneFirstValidGitUrl urls, {}, ->
           expect(install.cloneNormalizedUrl.calls.length).toBe 3
           expect(install.cloneNormalizedUrl.calls[0].args[0]).toBe urls[0]


:memo: Add missing period

:memo: Add missing period

--- atom/common/api/lib/deprecate.coffee
+++ atom/common/api/lib/deprecate.coffee
@@ -56,7 +56,7 @@
 deprecate.warn = (oldName, newName) ->
   deprecate.log "#{oldName} is deprecated. Use #{newName} instead."

-# Print deprecation message
+# Print deprecation message.
 deprecate.log = (message) ->
   if process.throwDeprecation
     throw new Error(message)


better padding

better padding

--- src/smc-webapp/project_warnings.cjsx
+++ src/smc-webapp/project_warnings.cjsx
@@ -13,7 +13,7 @@
     fontSize     : '13pt'
 )

-oom_alert_style = Object.freeze(Object.assign({}, alert_style, {fontSize : '11pt', padding : '5px'}))
+oom_alert_style = Object.freeze(Object.assign({}, alert_style, {fontSize : '11pt', padding : '15px'}))

 exports.DiskSpaceWarning = rclass ({name}) ->


off by 1, and padding

off by 1, and padding

--- scripts/pokebattle.coffee
+++ scripts/pokebattle.coffee
@@ -166,4 +166,4 @@
   robot.hear /.*(pokemon|grass|bush|cave|forest|wildf).*/i, (msg) ->
     poke = msg.random(pokemon)
     msg.send "A wild #{poke} appears!"
-    msg.send "http://serebii.net/Pkmn_Green/#{pad(pokemon.indexOf(poke))}.gif"+    msg.send "http://serebii.net/Pkmn_Green/#{pad(pokemon.indexOf(poke) + 1, 3)}.gif"


markdown: @ symbol in highlighted mentions


Don't use a emitDelayable for the select event

This was a bad idea, rather just emit an event when select has finished
running and provide the previous date as an argument. That way users
can revert to the old date if needed for some reason.

--- src/datepicker.coffee
+++ src/datepicker.coffee
@@ -82,14 +82,15 @@
     @gotoDecadeView nextDecadeDate

   select: (selectedDate) ->
+    previousDate = @model.get "active"
     date = moment(selectedDate.fullDate)
     selectedMonth = date.month()
     currentDate = moment(@getCurrentDate())
     currentMonth = currentDate.month()
-    @emitDelayable "select", =>
-      @gotoMonthView date  if selectedMonth isnt currentMonth
-      @model.set "active", selectedDate.fullDate
-      @model.set "show", false
+    @gotoMonthView date  if selectedMonth isnt currentMonth
+    @model.set "active", selectedDate.fullDate
+    @model.set "show", false
+    @emit "select", previousDate

   prevMonth: ->
     # get current month