Order line nodes by screen row

Order line nodes by screen row

--- src/lines-tile-component.coffee
+++ src/lines-tile-component.coffee
@@ -107,12 +107,23 @@

     WrapperDiv.innerHTML = newLinesHTML
     newLineNodes = _.toArray(WrapperDiv.children)
-    for id, i in newLineIds
-      lineNode = newLineNodes[i]
-      @lineNodesByLineId[id] = lineNode
-      @domNode.appendChild(lineNode)
+    newLineNodes = _.sortBy(newLineNodes, @screenRowForNode)
+
+    while newLineNode = newLineNodes.shift()
+      oldLineNodes = _.rest(@domNode.children) # skips highlights node
+      while oldLineNode = oldLineNodes.shift()
+        break if @screenRowForNode(newLineNode) < @screenRowForNode(oldLineNode)
+
+      lineId = @lineIdsByScreenRow[newLineNode.dataset.screenRow]
+      @lineNodesByLineId[lineId] = newLineNode
+      if oldLineNode?
+        @domNode.insertBefore(newLineNode, oldLineNode)
+      else
+        @domNode.appendChild(newLineNode)

     return
+
+  screenRowForNode: (node) -> parseInt(node.dataset.screenRow)

   buildLineHTML: (id) ->
     {width} = @newState
@@ -124,7 +135,7 @@
         classes += decorationClass + ' '
     classes += 'line'

-    lineHTML = "
"
+    lineHTML = "
"

     if text is ""
       lineHTML += @buildEmptyLineInnerHTML(id)
@@ -283,9 +294,6 @@
     newLineState = @newTileState.lines[id]

     lineNode = @lineNodesByLineId[id]
-
-    if @newState.width isnt @oldState.width
-      lineNode.style.width = @newState.width + 'px'

     newDecorationClasses = newLineState.decorationClasses
     oldDecorationClasses = oldLineState.decorationClasses


Prevent 'Connecting to LearnLearn' text in terminal

--- lib/views/terminal.coffee
+++ lib/views/terminal.coffee
@@ -47,7 +47,9 @@
     @openBackgroundColor = atom.config.get('learn-ide.terminalBackgroundColor')

   displayDisconnected: ->
+    @displayingDisconnect = true
     @terminalWrapper.off 'data'
+    @terminalWrapper.reset()
     @terminalWrapper.element.style.color = '#666'
     @terminalWrapper.cursorHidden = true
     @terminalWrapper.write('Unable to connect to Learn\r')
@@ -63,6 +65,9 @@
       @terminal.send(data)

     @terminal.on 'message', (message) =>
+      if @displayingDisconnect
+        @terminalWrapper.reset()
+        @displayingDisconnect = false
       @terminalWrapper.write(message)

     @terminal.on 'close', () =>


SimplePane

SimplePane

- Fixed parameter "title".

--- src/elements/Pane/SimplePane.coffee
+++ src/elements/Pane/SimplePane.coffee
@@ -68,11 +68,13 @@
 		if @_title
 			assert(not @_header_left, "new SimplePane", "opts.header_left conflicts with opts.title", opts: @opts)

-		if @forceHeader() or not (isUndef(@_header_left) and isUndef(@_header_center) and isUndef(@_header_right))
-			@__pane_header = new PaneHeader()
+		if @forceHeader() or
+			not (isUndef(@_header_left) and isUndef(@_header_center) and isUndef(@_header_right)) or
+			@_title
+				@__pane_header = new PaneHeader()

-			@_top =
-				content: @__pane_header
+				@_top =
+					content: @__pane_header

 		if @forceFooter() or not (isUndef(@_footer_left) and isUndef(@_footer_right))
 			@__pane_footer = new PaneFooter()


Should support console.dir

Should support console.dir

--- lib/zombie/console.coffee
+++ lib/zombie/console.coffee
@@ -2,8 +2,8 @@
 # console event for each output.

-{ format } = require("util")
-Hooks      = require("./hooks")
+{ format, inspect } = require("util")
+Hooks               = require("./hooks")

 class Console
@@ -35,6 +35,10 @@
   group: ->
   groupCollapsed: ->
   groupEnd: ->
+
+  dir: (object)->
+    @browser.emit("console", "log", inspect(object))
+    return

   info: ->
     @browser.emit("console", "info", format(arguments...))


adding semicolon

adding semicolon

--- src/dialects/sql-formatter.coffee
+++ src/dialects/sql-formatter.coffee
@@ -516,6 +516,7 @@

         output = @addOutputColumns(ret, stmt.outputColumns)
         if output?
+            ret.unshift(';')
             ret.unshift(output.table)
             ret.push(output.clause)


refactored for using mock factory

refactored for using mock factory

--- spec/javascripts/controllers/createEmployeeController_spec.coffee
+++ spec/javascripts/controllers/createEmployeeController_spec.coffee
@@ -1,77 +1,76 @@
-describe 'module cafeTownsend', ->
+describe 'CreateEmployeeController', ->

   beforeEach module('cafeTownsend')
+  beforeEach module('test')

-  describe '- CreateEmployeeController', ->
+  beforeEach inject ($rootScope, $controller, MockFactory) ->

-    beforeEach inject ($rootScope, $controller, $location) ->
-      # routes
-      @location = $location
-      @location.path '/employees/new'
-      # scope
-      @scope = $rootScope.$new()
+    @mockFactory = MockFactory
+    @deferred = @mockFactory.deferred

-      # controller factory
-      @createController = ->
-        controller = $controller "CreateEmployeeController",
-          $scope: @scope
+    @location = @mockFactory.location()
+    @sessionService = @mockFactory.sessionService()
+    @selectedEmployee = @mockFactory.selectedEmployee()
+    @viewState = @mockFactory.viewState()

-    afterEach ->
-      @scope = undefined
+    @scope = $rootScope.$new()

-    it 'is injectable', ->
-      controller = @createController()
-      expect(controller).not.to.be(undefined)
+    # controller factory
+    @createController = ->
+      $controller "CreateEmployeeController",
+        $scope: @scope
+        $location: @location
+        SessionService: @sessionService
+        SelectedEmployee: @selectedEmployee
+        ViewState: @viewState

-    describe 'initialize()', ->
-      it 'updates the view state', inject((ViewState) ->
-        @createController()
-        expect(ViewState.current).to.be('create')
-      )
+  afterEach ->

-      it 'set isCreateForm to true', ->
-        @createController()
-        expect(@scope.isCreateForm).to.be.ok()

-      it 'routes back to login page if an user is not authorized', inject((SessionService) ->
-        stub = sinon.stub(SessionService, 'authorized').returns false
-        @createController()
-        expect(@location.path()).to.equal('/login')
-        stub.restore()
-      )
+  it 'is injectable', ->
+    controller = @createController()
+    expect(controller).not.to.be(undefined)

-      it 'creates a selected employee if an user is authorized', inject((SelectedEmployee, SessionService) ->
-        stub = sinon.stub(SessionService, 'authorized').returns true
-        @createController()
-        expect(SelectedEmployee.instance).not.to.be(undefined)
-        stub.restore()
-      )
+  describe 'initialize()', ->
+    it 'updates the view state', ->
+      @createController()
+      expect(@viewState.current).to.be('create')

-      it 'adds the selected employee to scope if an user is authorized', inject((SelectedEmployee, SessionService) ->
-        stub = sinon.stub(SessionService, 'authorized').returns true
-        @createController()
-        expect(@scope.selectedEmployee).not.to.be(undefined)
-        stub.restore()
-      )
+    it 'set isCreateForm to true', ->
+      @createController()
+      expect(@scope.isCreateForm).to.be.ok()

-    describe 'scope', ->
-      it 'browseToOverview() updates the url', ->
-        @createController()
-        @scope.browseToOverview()
-        expect(@location.path()).to.be('/employees')
+    it 'routes back to login page if an user is not authorized', ->
+      @sessionService.authorized.returns false
+      @createController()
+      expect(@location.path.calledWith('/login')).to.be.ok()

-      it 'browseToOverview() disposes the selected employee', inject((SelectedEmployee) ->
-        @createController()
-        @scope.browseToOverview()
-        expect(SelectedEmployee.instance).to.be(undefined)
-      )
+    it 'creates a selected employee if an user is authorized', ->
+      @sessionService.authorized.returns true
+      @createController()
+      expect(@selectedEmployee.instance).not.to.be(undefined)

-      it 'submit() creates an employee',inject((SessionService, SelectedEmployee) ->
-        stub = sinon.stub(SessionService, 'authorized').returns true
-        @createController()
-        spy = sinon.spy(SelectedEmployee.instance, 'create')
-        @scope.submit()
-        expect(spy.calledOnce).to.be.ok()
-        stub.restore()
-        spy.restore()
-      )
+    it 'adds the selected employee to scope if an user is authorized', ->
+      @sessionService.authorized.returns true
+      @createController()
+      expect(@scope.selectedEmployee).not.to.be(undefined)
+
+  describe 'scope', ->
+    it 'browseToOverview() updates the url', ->
+      @createController()
+      @scope.browseToOverview()
+      expect(@location.path.calledWith('/employees')).to.be.ok()
+
+    it 'browseToOverview() disposes the selected employee', inject((SelectedEmployee) ->
+      @createController()
+      @scope.browseToOverview()
+      expect(SelectedEmployee.instance).to.be(undefined)
+    )
+
+    it 'submit() creates an employee', ->
+      @sessionService.authorized.returns true
+      @createController()
+      spy = sinon.spy(@selectedEmployee.instance, 'create')
+      @scope.submit()
+      expect(spy.calledOnce).to.be.ok()
+      spy.restore()


Bug fix

Bug fix

--- test/lib/generate_models.coffee
+++ test/lib/generate_models.coffee
@@ -124,7 +124,7 @@
         reverses: -> ['hasMany', Reverse]
       }, BASE_SCHEMA)
       sync: SYNC(Owner)
-  ()
+  )()

   #############################
   # Other


added some helper methods into recurly wrapper which can be used by our one time scripts

--- services/web/app/coffee/Features/Subscription/RecurlyWrapper.coffee
+++ services/web/app/coffee/Features/Subscription/RecurlyWrapper.coffee
@@ -49,6 +49,16 @@

 			callback null, signature

+
+	getSubscriptions: (accountId, callback)->
+		@apiRequest({
+			url: "accounts/#{accountId}/subscriptions"
+		}, (error, response, body) =>
+			return callback(error) if error?
+			@_parseXml body, callback
+		)
+
+
 	getSubscription: (subscriptionId, options, callback) ->
 		callback = options unless callback?
 		options ||= {}
@@ -79,6 +89,16 @@
 					callback null, recurlySubscription
 		)

+	getAccounts: (callback)->
+		@apiRequest({
+			url: "accounts"
+			qs:
+				per_page:2000
+		}, (error, response, body) =>
+			return callback(error) if error?
+			@_parseXml body, callback
+		)
+
 	getAccount: (accountId, callback) ->
 		@apiRequest({
 			url: "accounts/#{accountId}"
@@ -86,7 +106,16 @@
 			return callback(error) if error?
 			@_parseAccountXml body, callback
 		)
-
+
+	getBillingInfo: (accountId, callback)->
+		@apiRequest({
+			url: "accounts/#{accountId}/billing_info"
+		}, (error, response, body) =>
+			return callback(error) if error?
+			@_parseXml body, callback
+		)
+
+
 	updateSubscription: (subscriptionId, options, callback) ->
 		logger.log subscriptionId:subscriptionId, options:options, "telling recurly to update subscription"
 		requestBody = """
@@ -102,6 +131,37 @@
 		}, (error, response, responseBody) =>
 			return callback(error) if error?
 			@_parseSubscriptionXml responseBody, callback
+		)
+
+	createFixedAmmountCoupon: (coupon_code, name, currencyCode, discount_in_cents, callback)->
+		requestBody = """
+			<coupon>
+				<coupon_code>#{coupon_code}</coupon_code>
+				<name>#{name}</name>
+				<discount_type>dollars</discount_type>
+				<discount_in_cents>
+					<#{currencyCode}>#{discount_in_cents}</#{currencyCode}>
+				</discount_in_cents>
+			</coupon>
+		"""
+		logger.log coupon_code:coupon_code, requestBody:requestBody, "creating coupon"
+		@apiRequest({
+			url    : "coupons"
+			method : "post"
+			body   : requestBody
+		}, (error, response, responseBody) =>
+			if error?
+				logger.err err:error, coupon_code:coupon_code, "error creating coupon"
+			callback(error)
+		)
+
+
+	lookupCoupon: (coupon_code, callback)->
+		@apiRequest({
+			url: "coupons/#{coupon_code}"
+		}, (error, response, body) =>
+			return callback(error) if error?
+			@_parseXml body, callback
 		)

 	cancelSubscription: (subscriptionId, callback) ->


null check response.outputFiles

null check response.outputFiles

--- services/web/public/coffee/ide/pdf/controllers/PdfController.coffee
+++ services/web/public/coffee/ide/pdf/controllers/PdfController.coffee
@@ -51,6 +51,9 @@

 			IGNORE_FILES = ["output.fls", "output.fdb_latexmk"]
 			$scope.pdf.outputFiles = []
+
+			if !response.outputFiles?
+				return
 			for file in response.outputFiles
 				if IGNORE_FILES.indexOf(file.path) == -1
 					# Turn 'output.blg' into 'blg file'.


activity: send message loaded events to initial channel

--- client/activity/lib/flux/actions/realtime/actioncreators.coffee
+++ client/activity/lib/flux/actions/realtime/actioncreators.coffee
@@ -15,7 +15,12 @@

     channel.on 'MessageAdded', (message) ->
       bindMessageEvents message
-      dispatch actions.LOAD_MESSAGE_SUCCESS, { channel, message, channelId: channel.id }
+
+      _channel = kd.singletons.socialapi.retrieveCachedItemById message.initialChannelId
+      dispatch actions.LOAD_MESSAGE_SUCCESS,
+        channel   : _channel
+        channelId : _channel.id
+        message   : message

     channel.on 'MessageRemoved', (message) ->
       dispatch actions.REMOVE_MESSAGE_SUCCESS, { messageId: message.id }


Accept channel invitation if channel id exists

--- client/app/lib/activity/sidebar/sidebarmachinesharepopup.coffee
+++ client/app/lib/activity/sidebar/sidebarmachinesharepopup.coffee
@@ -169,8 +169,11 @@

       { channelId } = @getOptions()

-      kd.singletons.socialapi.channel.acceptInvite { channelId }, (err) =>
-        return showError err  if err
+      if channelId
+        kd.singletons.socialapi.channel.acceptInvite { channelId }, (err) =>
+          return showError err  if err
+          callback()
+      else
         callback()


Add the button filter

Add the button filter

--- backbone.tableview.coffee
+++ backbone.tableview.coffee
@@ -125,6 +125,13 @@
     # Creates a filter from a filter config definition
     createFilter: (name, filter) =>
         switch filter.type
+            when "button"
+                return new ButtonFilter
+                    id: name
+                    init: filter.init or "false"
+                    toggle: filter.toggle or "true"
+                    filterClass: filter.className or ""
+                    setData: @setData
             when "input"
                 return new InputFilter
                     id: name
@@ -247,3 +254,19 @@

     update: (e) =>
         @setData @id, @options.get e.currentTarget.value
+
+class ButtonFilter extends Filter
+    template: _.template """
+        <button type="button" class="filter btn <%= filterClass %>" data-toggle="button"><%= name %></button>
+    """
+    events:
+        "click .filter": "update"
+
+    initialize: ->
+        super
+        @values = [@options.init, @options.toggle]
+        @current = 0
+
+    update: =>
+        @current = 1 - @current
+        @setData @id, @values[@current]


Add parameters to collection.fecth method

--- app/assets/javascripts/action_cable_notifications/collection.coffee
+++ app/assets/javascripts/action_cable_notifications/collection.coffee
@@ -10,8 +10,8 @@
   # Public methods
   #######################################

-  fetch: () ->
-    @channel?.perform?('fetch') if @sync
+  fetch: (options={}) ->
+    @channel?.perform?('fetch',options) if @sync

   where: (selector={}) ->
     _.filter(@data, selector)


Just use the prototype for inheritance...

WTF

--- app/assets/javascripts/exo/views/autocomplete_token_field.js.coffee
+++ app/assets/javascripts/exo/views/autocomplete_token_field.js.coffee
@@ -4,9 +4,15 @@
   class exports.AutocompleteTokenField extends Exo.Views.TokenField
     resultsPopoverClass: Exo.Views.CollectionListPopover
     showPopoverOnEmpty: false
+
     minInputValueLength: 1
+
+    # Allow tokens for queries not in the collection. Useful for creating.
     allowFallbackTokens: true
     showAllOnDownArrow: false
+
+    # Attribute on models to search.
+    filterAttribute: "name"

     initialize: (options = {}) ->
       super
@@ -28,9 +34,6 @@
         _.extend {
           displayAttr: @_itemDisplayText(model)
         }, model.attributes
-
-      # Attribute to filter models by
-      @filterAttribute = options.filterAttribute || "name"

       @resultsPopover.on "item:selected", (model) ->
         model = if _.isString(model) then @_buildFallbackToken(model) else model


[fix] Delay FS watcher to avoid adding new files when they just got downloaded

--- backend/filesystem.coffee
+++ backend/filesystem.coffee
@@ -42,8 +42,10 @@
         filesystem.watchingLocked = true
         callbackOrig = callback
         callback = (err, res) ->
-            filesystem.watchingLocked = false
-            callbackOrig err, res
+            setTimeout ->
+                filesystem.watchingLocked = false
+                callbackOrig err, res
+            , 500

     switch task.operation
         when 'post'


better doc

better doc

--- library/exposure/inventory.coffee
+++ library/exposure/inventory.coffee
@@ -95,7 +95,7 @@
     # in order for the cache to work. Please see `plumbs` module
     # for more info on that. Also, depends on the spin off engine.
     # Please see the `lru-cache` package for more relevant info.
-    @cache: @memoryCache 25, 1000 * 60 * 60 # milliseconds
+    @cache: @memoryCache 25, 1000 * 60 * 60 # TTL, milliseconds

     # Define an API endpoint in the current API service. Endpoint
     # is declared using the class directives with the name of one


Close window without send message

Close window without send message

--- app/assets/javascripts/rocketchat.js.coffee
+++ app/assets/javascripts/rocketchat.js.coffee
@@ -73,9 +73,9 @@
         if _regex.test(value)
           _click_class = value
       )
-
       _modal_class = _click_class.replace("-rc", "-modal-rc")
-      if $(".js-rocket-chat-room").length > 0
+      _checkbox = $(".#{_modal_class} input[type='checkbox']");
+      if $(".js-rocket-chat-room").length > 0 and _checkbox.is(":checked")
         $.ajax
           url: $(@).data('href')
           method: 'POST'
@@ -90,11 +90,14 @@
           error: (respond)->
             _error = respond.responseJSON['error']
             toastr.error(_error, 'Error')
+      else
+        $(".#{_modal_class}").modal('hide')
+
   , " .js-open-to-active-rc, .js-open-to-rejected-rc, .js-open-to-nothing-rc," +
       ".js-rejected-to-active-rc, .js-rejected-to-nothing-rc, .js-proposal-to-active-rc, .js-proposal-to-deleted-rc," +
       ".js-proposal-to-nothing-rc, .js-active-to-nothing-rc, .js-active-send-contract-rc, .js-active-to-finished-rc," +
       ".js-active-to-canceled-rc, .js-finished-to-active-rc, .js-finished-to-nothing-rc, .js-finished-to-active-rc," +
-      ".js-finished-to-nothing-rc, .js-retracted-to-active-rc, .js-retracted-to-nothing-rc"
+      ".js-retracted-to-active-rc, .js-retracted-to-nothing-rc"
   $(document).on
     click: (e)->
       e.preventDefault()


Fix missing path namespace

Fix missing path namespace

--- app/assets/javascripts/cmsimple/panels/image_library.coffee
+++ app/assets/javascripts/cmsimple/panels/image_library.coffee
@@ -7,7 +7,7 @@
   constructor: ()->
     super(null, 'insertMedia', title: 'Image Library', appendTo: '.mercury-toolbar-container', closeButton: true)
     @button = $('.mercury-insertMedia-button')
-    @loadContent JST['views/image_library']()
+    @loadContent JST['cmsimple/views/image_library']()

     # MK junk!
     @testActions()


Disable low res while fixing cross domain issues

--- app/assets/javascripts/wallpapers.js.coffee
+++ app/assets/javascripts/wallpapers.js.coffee
@@ -4,15 +4,15 @@
     $('img[data-highres-src]').each ->
       $this = $(this)
       highres_src = $this.data('highres-src')
-      prevent_default_handler = (e) ->
-        e.preventDefault()
-        alert 'Please wait, the full size image is still loading.'
+#      prevent_default_handler = (e) ->
+#        e.preventDefault()
+#        alert 'Please wait, the full size image is still loading.'

-      $this.bind 'contextmenu', prevent_default_handler
+#      $this.bind 'contextmenu', prevent_default_handler

-      $.get highres_src, ->
-        $this.attr 'src', highres_src
-        $this.unbind 'contextmenu', prevent_default_handler
+#      $.get highres_src, ->
+      $this.attr 'src', highres_src
+#        $this.unbind 'contextmenu', prevent_default_handler

     # Handle favourite
     $('.btn-favourite').on 'ajax:success', (e, data) ->


cross browser way to set link text

cross browser way to set link text

--- src/modules/link-tooltip.coffee
+++ src/modules/link-tooltip.coffee
@@ -13,7 +13,7 @@
     @editor.selection.format('link', @tooltipInput.value, { source: 'user' })
     formats = @savedRange.getFormats()
     if formats['link']?
-      @tooltipLink.innerText = @tooltipLink.href = formats['link']
+      @tooltipLink.textContent = @tooltipLink.href = formats['link']
       @toolbar.emit(Scribe.Toolbar.events.FORMAT, 'link', formats['link'])
     @editor.setSelection(null, true)
   Scribe.DOM.removeClass(@tooltip, 'editing')


make sure that we don't keep erroneous timeouts lying around

and don't add a timeout when one is already running. The one running will always end earlier (since the timeout time is constant), so we don't need the second one

--- js-library/app/js/util/attention_span.coffee
+++ js-library/app/js/util/attention_span.coffee
@@ -8,27 +8,31 @@
     @options.wait_for_neglection ?= 0

   attend: ->
-    clearTimeout @losing_attention_timeout
-    @gaining_attention_timeout = setTimeout =>
+    @clearTimeout 'losing_attention_timeout'
+    @gaining_attention_timeout ?= setTimeout =>
       @gain_attention()
     , @options.wait_for_attention

   neglect: ->
-    clearTimeout @gaining_attention_timeout
-    @losing_attention_timeout = setTimeout =>
-      @loose_attention()
+    @clearTimeout 'gaining_attention_timeout'
+    @losing_attention_timeout ?= setTimeout =>
+      @lose_attention()
     , @options.wait_for_neglection

   has_attention: -> @_has_attention

-    clearTimeout @gaining_attention_timeout
-    clearTimeout @losing_attention_timeout
   lose_attention: ->
+    @clearTimeout 'gaining_attention_timeout'
+    @clearTimeout 'losing_attention_timeout'
     @_has_attention = false
     @options.lost_attention?()

   gain_attention: ->
-    clearTimeout @gaining_attention_timeout
-    clearTimeout @losing_attention_timeout
+    @clearTimeout 'gaining_attention_timeout'
+    @clearTimeout 'losing_attention_timeout'
     @_has_attention = true
     @options.gained_attention?()
+
+  clearTimeout: (name) ->
+    clearTimeout this[name]
+    delete this[name]


more tests for Model.combine

more tests for Model.combine

--- test/bacon.jquery.spec.coffee
+++ test/bacon.jquery.spec.coffee
@@ -189,6 +189,25 @@
       doors: 2
     }])
     expect(collect(cylinders)).to.deep.equal([8])
+  it "supports deep nesting", ->
+    cylinders = bjb.Model(12)
+    seats = bjb.Model(4)
+    car = bjb.Model.combine {
+      engine: { cylinders},
+      interior: {
+        seats: { count: seats }
+      }
+    }
+    seats.set(5)
+    expect(collect(cylinders)).to.deep.equal([12])
+    expect(collect(car)).to.deep.equal([{
+      engine: { cylinders: 12 }
+      interior: {
+        seats: {
+          count: 5
+        }
+      }
+    }])
   it "skips duplicates correctly", ->
     a = bjb.Model("a")
     b = bjb.Model("b")


Update helper method to user Ember.Handlebars.helper

--- app/assets/javascripts/spree_outlet/helpers/date_helper.js.coffee
+++ app/assets/javascripts/spree_outlet/helpers/date_helper.js.coffee
@@ -1,4 +1,4 @@
-Ember.Handlebars.registerBoundHelper('date', (dateString) ->
+Ember.Handlebars.helper('date', (dateString) ->
   if dateString && Ember.typeOf(dateString) == 'string'
     date = new Date(dateString.toString())
     date.toLocaleDateString()


Fix scope to allow auto-complete styled-components to be used in a pure file. Not likely but who knows! Also fix typo's in comments [ci skip]

--- lib/auto-complete-styled-components.coffee
+++ lib/auto-complete-styled-components.coffee
@@ -1,7 +1,7 @@
 # This code was based upon https://github.com/atom/autocomplete-css but has been modified to allow it to be used
 # for styled-componenets. The completions.json file used to auto complete is a copy of the one used by the atom
-# package. That package, provided as an Atom base pacakge, has tools to update the completions.json file from the web.
-# See that package for more info and just copy the completions.json to this files directory whern a refresh is needed.
+# package. That package, provided as an Atom base package, has tools to update the completions.json file from the web.
+# See that package for more info and just copy the completions.json to this files directory when a refresh is needed.

 fs = require 'fs'
 path = require 'path'
@@ -16,7 +16,7 @@
 cssDocsURL = "https://developer.mozilla.org/en-US/docs/Web/CSS"

 module.exports =
-  selector: '.source.inside-js.css.styled, source.css.styled'
+  selector: '.source.inside-js.css.styled, .source.css.styled'
   disableForSelector: ".source.inside-js.css.styled .comment, .source.inside-js.css.styled .string, .source.inside-js .css.styled.entity.quasi.element.js, .source.css.styled .comment, .source.css.styled .string, .source.css.styled .css.styled.entity.quasi.element.js"

   filterSuggestions: true


ActivityAppController: Fixed overriding flags object of activityController.

--- client/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/app/Applications/Activity.kdapplication/AppController.coffee
@@ -143,20 +143,18 @@
       #to-do add isExempt control.
       #@isExempt (exempt)=>
       #if exempt or @getFilter() isnt activityTypes
-      groupObj = KD.getSingleton('groupsController').getCurrentGroup()
-
-      options =
-        to     : options.to or Date.now()
-        group  :
-          slug : groupObj?.slug or "koding"
-          id   : groupObj.getId()
-        limit  : 20
-        facets : @getActivityFilter()
-
-      if KD.getSingleton('activityController').flags?.showExempt?
-        options.withExempt = KD.getSingleton('activityController').flags.showExempt
-      else
-        options.withExempt = false
+      groupObj     = KD.getSingleton("groupsController").getCurrentGroup()
+      options      =
+        to         : options.to or Date.now()
+        group      :
+          slug     : groupObj?.slug or "koding"
+          id       : groupObj.getId()
+        limit      : 20
+        facets     : @getActivityFilter()
+        withExempt : no
+
+      if KD.getSingleton("activityController").flags.showExempt
+        options.withExempt = yes

       eventSuffix = "#{@getFeedFilter()}_#{@getActivityFilter()}"


Script deprecated. Provide warning and fail fast.

--- src/scripts/beeradvocate.coffee
+++ src/scripts/beeradvocate.coffee
@@ -17,13 +17,16 @@
 #   whyjustin

 module.exports = (robot) ->
+    robot.logger.warning "The beeradvocate script is deprecated and will not work (github/hubot-scripts#1436)."
+
     robot.respond /beer (a|advocate)( me)?/i, (msg) ->
-        msg.http("http://beeradvocate.com/beer/")
-            .get() (err, res, body) ->
-                if (res.statusCode == 200)
-                    reg = /
(.+?)<\/a><\/h6>/i
-                    results = body.match(reg)
-                    if (results != null && results.length > 3)
-                        msg.send results[3]
-                        msg.send 'http://beeradvocate.com/beer/profile/' + results[1] + '/' + results[2]
-                        msg.send 'http://beeradvocate.com/im/thumb.php?im=beers/' + results[2] + '.jpg'
+        msg.send "I'm sorry but beeradvocate is deprecated and will not work."
+        # msg.http("http://beeradvocate.com/beer/")
+        #     .get() (err, res, body) ->
+        #         if (res.statusCode == 200)
+        #             reg = /
(.+?)<\/a><\/h6>/i
+        #             results = body.match(reg)
+        #             if (results != null && results.length > 3)
+        #                 msg.send results[3]
+        #                 msg.send 'http://beeradvocate.com/beer/profile/' + results[1] + '/' + results[2]
+        #                 msg.send 'http://beeradvocate.com/im/thumb.php?im=beers/' + results[2] + '.jpg'


Update status on any change

Update status on any change

--- apps/import/components/import_bookmarks/import_status_view.coffee
+++ apps/import/components/import_bookmarks/import_status_view.coffee
@@ -29,7 +29,7 @@
     @blocks = new Blocks()

     @listenTo @collection, 'model:selected', @render
-    @listenTo @status, 'change:connecting', @render
+    @listenTo @status, 'change', @render

   initConnectBlocks: ->
     @status.set connecting: true
@@ -56,17 +56,30 @@
     blocks = @blocks
     selectedChannel = @selectedChannel
     block = new Block source: link.get('href')
+    existingConnections = link.get('connections') or []
     blocks.create block.toJSON(),
       url: "#{sd.API_URL}/channels/#{selectedChannel.get('slug')}/blocks"
       success: (block) ->
-        link.set selected: false
+        connections = existingConnections.concat [
+          {
+            title: selectedChannel.get('title')
+            status: selectedChannel.get('status')
+            slug: selectedChannel.get('slug')
+            user_slug: selectedChannel.get('user').slug
+          }
+        ]
+        link.set
+          selected: false
+          connections: connections
         link.collection.trigger 'model:selected'
         dfd.resolve()
     dfd.promise

-
-  showSuccess: ->
-    console.log('success')
+  showSuccess: =>
+    @status.set
+      selecting: false
+      connecting: false
+    @selectedChannel.reset()

   showError: (e) ->
     console.log('error', e, e.stack)


Inline simple updateStatus method

Inline simple updateStatus method

--- lib/file-view.coffee
+++ lib/file-view.coffee
@@ -20,11 +20,9 @@
         when 'binary'     then @fileName.addClass('icon-file-binary')
         when 'text'       then @fileName.addClass('icon-file-text')

-    @subscribe @file.$status.onValue (status) => @updateStatus(status)
-
-  updateStatus: (status) ->
-    @removeClass('status-ignored status-modified status-added')
-    @addClass("status-#{status}") if status?
+    @subscribe @file.$status.onValue (status) =>
+      @removeClass('status-ignored status-modified status-added')
+      @addClass("status-#{status}") if status?

   getPath: ->
     @file.getPath()


webapp/chat: tell project-relative images in chat to be prefixed with the base url

--- src/smc-webapp/misc_page.coffee
+++ src/smc-webapp/misc_page.coffee
@@ -160,7 +160,8 @@
                 src = y.attr('src')
                 if src.indexOf('://') != -1
                     continue
-                new_src = "/#{opts.project_id}/raw/#{opts.file_path}/#{src}"
+                {join} = require('path')
+                new_src = join('/', window.smc_base_url, opts.project_id, 'raw', opts.file_path, src)
                 y.attr('src', new_src)

         return e


Make getters like properties

Make getters like properties

--- src/smc-webapp/smc-react.coffee
+++ src/smc-webapp/smc-react.coffee
@@ -124,18 +124,18 @@
             bound_state_importers[name] = func.bind(@)

         selectors = generate_selectors(bound_own_functions, bound_state_importers, @)
-        Object.assign(@, selectors)
-
-        ###
+
+        # Object.assign(@, selectors)
+
         # Bind selectors as properties on this store
         prop_map = {}
-        for name, selector of selectors
+        underscore.map selectors, (selector, name) =>
             prop_map[name] =
                 get        : -> selector(@getState())
                 enumerable : true

         Object.defineProperties(@, prop_map)
-        ###
+

     _handle_store_change: (state) =>
         if state != @_last_state
@@ -535,8 +535,8 @@
                 # All store properties are functions which take the entire store state
                 # This enforces Stores describing all of their possible state
                 if store_name == 'page'
-                    selector = redux.getStore(store_name)[prop]
-                    val = selector(state)
+                    val = redux.getStore(store_name)[prop]
+                    #val = selector(state)
                 else
                     val = state.getIn([store_name, prop])
                 if type.category == "IMMUTABLE"


Fix #1

Fix #1

--- lib/hard-wrap.coffee
+++ lib/hard-wrap.coffee
@@ -56,6 +56,8 @@
         if range.isEmpty()
           range = editor.languageMode.
             rowRangeForParagraphAtBufferRow(range.getRows()[0])
+          if not range?
+            continue # nothing to do here

         wrapColumn = @getWrapColumn(range, editor)
         reflowedText = @reflow(editor.getTextInBufferRange(range), {wrapColumn})


η-reduce FTW!

η-reduce FTW!

--- test/integration/login.coffee
+++ test/integration/login.coffee
@@ -59,9 +59,7 @@
         wd40.fill '#username', 'ickletest', ->
           wd40.fill '#password', 'toottoot', ->
             wd40.click '#login', ->
-              setTimeout ->
-                done()
-              , 500
+              setTimeout done, 500

       it 'shows my name', (done) ->
         # change "does not show my name" below as well if you change this


Fixed : in one more place.

Fixed : in one more place.

--- lib/jsMegaHal.coffee
+++ lib/jsMegaHal.coffee
@@ -15,7 +15,7 @@
 ###
 class jsMegaHal
 	#the regex to check the validity of a character
-	wordRegex: /[^a-zA-Z0-9,'\u00C0-\u017F]+/
+	wordRegex: /[^a-zA-Z0-9:,'\u00C0-\u017F]+/

 	#the regex to split sentences by -- remove all \r\n
 	sentenceRegex: /[!?\.]/


Remove log and cleanup code style

Remove log and cleanup code style

--- imports/utils.coffee
+++ imports/utils.coffee
@@ -127,7 +127,7 @@
   WGST: '-0200'
   WGT: '-0300'

-export regexEscape = (s)->
+export regexEscape = (s) ->
   # Based on bobince's regex escape function.
   # source: http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript/3561711#3561711
   s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
@@ -147,11 +147,11 @@
   term = params.term?.trim()
   if not term
     return callback(results: [])
-  Meteor.call 'geonameLookup', term, (error, response)->
+  Meteor.call 'geonameLookup', term, (error, response) ->
     if error
       return callback(error)
     callback(
-      results: response.data.result.map((d)->
+      results: response.data.result.map((d) ->
         if d.synonym != d.label
           text = d.synonym + " | " + d.label
         else
@@ -169,7 +169,7 @@

 # Parse text into an array of sentences separated by
 # periods, colons, semi-colons, or double linebreaks.
-export parseSents = (text)->
+export parseSents = (text) ->
   idx = 0
   sents = []
   sentStart = 0
@@ -201,12 +201,12 @@
   # Split annotations with multiple offsets
   # and sort by offset.
   annotationsWithSingleOffsets = []
-  annotationsWithOffsets.forEach (annotation)->
-    annotation.textOffsets.forEach (textOffset)->
+  annotationsWithOffsets.forEach (annotation) ->
+    annotation.textOffsets.forEach (textOffset) ->
       splitAnnotation = Object.create(annotation)
       splitAnnotation.textOffsets = [textOffset]
       annotationsWithSingleOffsets.push(splitAnnotation)
-  annotationsWithOffsets = _.sortBy(annotationsWithSingleOffsets, (annotation)->
+  annotationsWithOffsets = _.sortBy(annotationsWithSingleOffsets, (annotation) ->
     annotation.textOffsets[0][0]
   )
   annotationIdx = 0
@@ -239,7 +239,7 @@
         territories[territories.length - 1].territoryEnd = sentEnd
   return territories

-export createIncidentReportsFromEnhancements = (enhancements, options)->
+export createIncidentReportsFromEnhancements = (enhancements, options) ->
   { countAnnotations, acceptByDefault, articleId, publishDate } = options
   if not publishDate
     publishDate = new Date()
@@ -248,11 +248,11 @@
   locationAnnotations = features.filter (f) -> f.type == 'location'
   datetimeAnnotations = features.filter (f) -> f.type == 'datetime'
   diseaseAnnotations = features.filter (f) ->
-    f.type == 'resolvedKeyword' and f.resolutions.some((r)->
+    f.type == 'resolvedKeyword' and f.resolutions.some((r) ->
       r.entity.type == 'disease'
     )
   speciesAnnotations = features.filter (f) ->
-    f.type == 'resolvedKeyword' and f.resolutions.some((r)->
+    f.type == 'resolvedKeyword' and f.resolutions.some((r) ->
       r.entity.type == 'species'
     )
   if not countAnnotations
@@ -296,7 +296,6 @@
   # Only include the sentence the word appears in for species territories since
   # the species is implicitly human in most of the articles we're analyzing.
   speciesTerritories = getTerritories(speciesAnnotations, sents, sentenceOnly: true)
-  console.log speciesTerritories
   countAnnotations.forEach (countAnnotation) =>
     [start, end] = countAnnotation.textOffsets[0]
     locationTerritory = _.find locTerritories, ({territoryStart, territoryEnd}) ->
@@ -312,7 +311,7 @@
       .pluck('geoname')
       .groupBy('id')
       .values()
-      .map((x)-> x[0])
+      .map((x) -> x[0])
       .value()
     incident =
       locations: locations
@@ -367,11 +366,11 @@
         incident.status = 'suspected'
     incident.articleId = articleId
     # The disease field is set to the last disease mentioned.
-    diseaseTerritory.annotations.forEach (annotation)->
+    diseaseTerritory.annotations.forEach (annotation) ->
       incident.resolvedDisease =
         id: annotation.resolutions[0].entity.id
         text: annotation.resolutions[0].entity.label
-    speciesTerritory.annotations.forEach (annotation)->
+    speciesTerritory.annotations.forEach (annotation) ->
       incident.species =
         id: annotation.resolutions[0].entity.id
         text: annotation.resolutions[0].entity.label
@@ -450,12 +449,12 @@
     $toTopButton.addClass('off-canvas')
 , 50

-export pluralize = (word, count, showCount=true)->
+export pluralize = (word, count, showCount=true) ->
   if Number(count) isnt 1
     word += "s"
   if showCount then "#{count} #{word}" else word

-export formatDateRange = (dateRange, readable)->
+export formatDateRange = (dateRange, readable) ->
   dateRange ?= ''
   start = moment.utc(dateRange.start)
   end = moment.utc(dateRange.end)


Add San Francisco to list of cities on /collect

--- components/commercial_filter/filters/location/location_map.coffee
+++ components/commercial_filter/filters/location/location_map.coffee
@@ -5,5 +5,6 @@
     'Los Angeles, CA, USA',
     'Paris, France',
     'Berlin, Germany',
+    'San Francisco, CA, USA'
     'Hong Kong, Hong Kong'
   ]


Clearer name

Clearer name

--- core/app/assets/javascripts/lib/prevent_scroll_propagation.coffee
+++ core/app/assets/javascripts/lib/prevent_scroll_propagation.coffee
@@ -1,6 +1,6 @@
 #= require jquery.mousewheel

-shouldHandleScrolling = ($el) ->
+weShouldHandleScrolling = ($el) ->
   # There isn't anything to scroll, and we only show a scrollbar when there is
   return false if $el[0].scrollHeight <= $el.innerHeight() && $el.css('overflow-y') == 'auto'

@@ -20,7 +20,7 @@
     $(this).on 'mousewheel', (event, delta) ->
       $el = $(event.delegateTarget)

-      return unless shouldHandleScrolling($el)
+      return unless weShouldHandleScrolling($el)

       event.stopPropagation() # allow nesting of scrollable containers
       event.preventDefault() if preventScroll($el, delta)


Added container box

Added container box

--- core/app/backbone/views/sub_comments/sub_comments_add_view.coffee
+++ core/app/backbone/views/sub_comments/sub_comments_add_view.coffee
@@ -69,18 +69,20 @@

   template:
     text: """
-

-        Your comment could not be posted, please try again.
-        x
-

+

+

+          Your comment could not be posted, please try again.
+          x
+

-

-

+

+

-
-

-        <button class="evidence-sub-comments-button btn btn-primary pull-right js-submit">Comment</button>
+
+

+          <button class="evidence-sub-comments-button btn btn-primary pull-right js-submit">Comment</button>
+

     """


Generate context for HTML response

Generate context for HTML response

--- lib/presenter.coffee
+++ lib/presenter.coffee
@@ -1,4 +1,12 @@
 module.exports =
+  formatAsHTML: (predictions) ->
+    return [false, "Error: No predictions available"] unless predictions.length > 0
+    response = {}
+    response.predictions = []
+    HTMLformatHeader(predictions[0], response)
+    (HTMLformatPrediction(p, response) for p in predictions)
+    [true, response]
+
   formatAsSMS: (predictions) ->
     return [false, "Error: No predictions available"] unless predictions.length > 0
     response = []
@@ -12,5 +20,21 @@
 SMSformatPrediction = (prediction, response) ->
   response.push "In #{prediction.prediction.minutes}m: #{trimStopName prediction.stop.stopName}"

+HTMLformatHeader = (prediction, response) ->
+  response.routeNumber = prediction.route.number
+  response.routeDirection = prediction.route.direction
+
+HTMLformatPrediction = (prediction, response) ->
+  returnValue =
+    stopName: prediction.stop.stopName
+    estimate: prediction.prediction.minutes
+    percentComplete: calculatePercentComplete(prediction.prediction.minutes)
+  console.log "prediction: ", returnValue
+  response.predictions.push returnValue
+
+calculatePercentComplete = (minutes) ->
+  return 0 if minutes > 10
+  100 - (minutes/10) * 100
+
 trimStopName = (stopName) ->
   stopName.replace(/(?:^.*&\s)(\w*)/gim, "$1")


Wait for orders being loaded in bulk order manage

The bulk order management page tried to wait for orders being loaded.
But instead of receiving a request object with an a promise to wait for
the page received a simple array without promise. As a result, the page
didn't wait for orders being loaded.

When loading of orders took longer than loading of line items they or at
least not all of them were enriched with distributors and order cycles
and the line items were missing some orders. That lead to random spec
failures.

--- app/assets/javascripts/admin/resources/services/orders.js.coffee
+++ app/assets/javascripts/admin/resources/services/orders.js.coffee
@@ -9,7 +9,7 @@
       request = OrderResource.index params, (data) =>
         @load(data)
         (callback || angular.noop)(data)
-      RequestMonitor.load(request.$promise)
+      @all.$promise = request.$promise
       @all

     load: (data) ->


Show the alerts in the start page when there are subscribe job alerts, but no refresh feed job alerts.

--- app/assets/javascripts/ng-controllers/ng-FeedbunchCtrl.js.coffee
+++ app/assets/javascripts/ng-controllers/ng-FeedbunchCtrl.js.coffee
@@ -300,10 +300,13 @@
   # Return true if there are job states for which an alert should be displayed in the start page; false otherwise.
   #--------------------------------------------
   $scope.show_job_state_alerts = ->
-    if $rootScope.refresh_feed_job_states? && $rootScope.refresh_feed_job_states?.length > 0
-      return true
-    else
-      return false
+    show_alerts = false
+    if ($rootScope.refresh_feed_job_states? && $rootScope.refresh_feed_job_states?.length > 0)
+      show_alerts = true
+    else if ($rootScope.subscribe_job_states? && $rootScope.subscribe_job_states?.length > 0)
+      show_alerts = true
+
+    return show_alerts

   #--------------------------------------------
   # Permanently dismiss a refresh feed job alert from the start page


compileFile

compileFile

--- ccss.coffee
+++ ccss.coffee
@@ -1,3 +1,5 @@
+fs = require 'fs'
+
 @compile = (rules) ->
   css = ''

@@ -23,3 +25,9 @@
     css += @compile nested

   css
+
+@compileFile = (infile, outfile) ->
+  rules = require process.cwd() + '/' + infile
+  css = @compile rules
+  outfile or= infile.replace /coffee$/, 'css'
+  fs.writeFileSync outfile, css


jobProxy should retain the `this' of the player.

--- application/chrome/content/wesabe/download/CompoundPlayer.coffee
+++ application/chrome/content/wesabe/download/CompoundPlayer.coffee
@@ -44,15 +44,15 @@
           # no more players to try, report the last failure
           @job.fail(status, result)

-      succeed: ->
+      succeed: =>
         @job.succeed.apply(@job, arguments)

       timer: @job.timer

-      nextGoal: ->
+      nextGoal: =>
         @job.nextGoal.apply(@job, arguments)

-      suspend: ->
+      suspend: =>
         @job.suspend.apply(@job, arguments)

       options: @job.options


Revert "Use same keyword detection as Atom's"

This reverts commit db6ee6319469b78c7278649543ca350298f8fe4a.

--- lib/show-todo.coffee
+++ lib/show-todo.coffee
@@ -12,11 +12,11 @@
   configDefaults:
     findTheseRegexes: [
       'FIXMEs'
-      '/\WFIXME\W(.+$)/g'
+      '/FIXME:(.+$)/g'
       'TODOs' #title
-      '/\WTODO\W(.+$)/g'
+      '/TODO:(.+$)/g'
       'CHANGEDs'
-      '/\WCHANGED\W(.+$)/g'
+      '/CHANGED:(.+$)/g'
     ]

   activate: (state) ->


remove isCcap requirement for pages results - issue #1897 (#1953)

--- src/scripts/models/content.coffee
+++ src/scripts/models/content.coffee
@@ -49,7 +49,7 @@

     defaultPage: ->
       result = 1
-      if @isBook() and @isCcap()
+      if @isBook()
         result += 1 while @getPage(result).get('title').match(/Preface/)
       return result


Verbose for profile creation

Verbose for profile creation

--- lib/spark-dev.coffee
+++ lib/spark-dev.coffee
@@ -120,6 +120,7 @@
     proFile = path.join settings.ensureFolder(), 'profile.json'
     if !fs.existsSync(proFile)
       fs.writeFileSync proFile, '{}'
+      console.log '!Created profile ' + proFile

     if typeof(jasmine) == 'undefined'
       # Don't watch settings during tests
@@ -234,6 +235,7 @@
     settings.whichProfile()
     settingsFile = settings.findOverridesFile()
     if !fs.existsSync(settingsFile)
+      console.log '!Created ' + settingsFile
       fs.writeFileSync settingsFile, '{}'

     @configSubscription ?= @PathWatcher.watch settingsFile, (eventType) =>


Fixes regex to only grab an IP address

Fixes regex to only grab an IP address

--- src/scripts/reputation-links.coffee
+++ src/scripts/reputation-links.coffee
@@ -15,7 +15,7 @@
 #   Scott J Roberts - @sroberts

 module.exports = (robot) ->
-  robot.respond /reputation ip (.*)/i, (msg) ->
+  robot.respond /reputation ip (d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/i, (msg) ->
     target_ip = msg.match[1].toLowerCase()

     reputation_links = """#{target_ip} IP Reputation:


去除打包后模板多余空格

去除打包后模板多余空格

--- build/webpack.base.coffee
+++ build/webpack.base.coffee
@@ -62,3 +62,4 @@
         'ie 9',
         '> 1%'
       ]
+    html: conservativeCollapse: false


concat to @reveal _ the length of the current spelling word

--- cf/spell.coffee
+++ cf/spell.coffee
@@ -22,6 +22,8 @@
   random_question = (data) ->
     choice = Math.floor(Math.random() * data['words'].length)
     @current = data['words'][choice]['name']
+    [1..@current.length].forEach ->
+      @reveal.concat("_")
     return data['words'][choice]

   update_question = (data) ->


:art: Fix unnecessary far arrow lint error

--- lib/tree-view.coffee
+++ lib/tree-view.coffee
@@ -816,7 +816,7 @@
     e.originalEvent.dataTransfer.setDragImage(fileNameElement[0], 0, 0)
     e.originalEvent.dataTransfer.setData("initialPath", initialPath)

-    window.requestAnimationFrame =>
+    window.requestAnimationFrame ->
       fileNameElement.remove()

   # Handle entry dragover event; reset default dragover actions


Don't call deprecated APIs in specs

Don't call deprecated APIs in specs

--- spec/bookmarks-view-spec.coffee
+++ spec/bookmarks-view-spec.coffee
@@ -7,13 +7,15 @@
     spyOn(window, 'setImmediate').andCallFake (fn) -> fn()
     atom.workspaceView = new WorkspaceView
     atom.workspace = atom.workspaceView.model
-    atom.workspaceView.openSync('sample.js')
-    atom.workspaceView.enableKeymap()
+
+    waitsForPromise ->
+      atom.workspace.open('sample.js')

     waitsForPromise ->
       atom.packages.activatePackage('bookmarks')

     runs ->
+      atom.workspaceView.enableKeymap()
       atom.workspaceView.attachToDom()
       editorView = atom.workspaceView.getActiveView()
       {editor} = editorView


longer sage_server startup timeout for kucalc & sage-8.0

--- src/smc-project/sage_session.coffee
+++ src/smc-project/sage_session.coffee
@@ -25,7 +25,7 @@
 # connection requests, after we restart it.  It can
 # take a while, since it pre-imports the sage library
 # at startup, before forking.
-SAGE_SERVER_MAX_STARTUP_TIME_S = 30
+SAGE_SERVER_MAX_STARTUP_TIME_S = 60

 _restarting_sage_server = false
 _restarted_sage_server  = 0   # time when we last restarted it


next round of fixes

next round of fixes

--- src/smc-webapp/project_store.coffee
+++ src/smc-webapp/project_store.coffee
@@ -34,8 +34,6 @@
 {webapp_client} = require('./webapp_client')
 {project_tasks} = require('./project_tasks')
 {types, defaults, required} = misc
-
-misc_page = require('./misc_page')

 {Actions, rtypes, computed, depends, project_redux_name, Table, redux}  = require('./smc-react')

@@ -165,7 +163,7 @@
         @_last_history_state = local_url
         {set_url} = require('./history')
         set_url(@_url_in_project(local_url))
-        misc_page.analytics_pageview(window.location.pathname)
+        require('./misc_page').analytics_pageview(window.location.pathname)

     move_file_tab: (opts) =>
         {old_index, new_index, open_files_order} = defaults opts,
@@ -372,7 +370,7 @@
             url  = (window.app_base_url ? '') + @_url_in_project('files/' + opts.path)
             url += '?session=' + misc.uuid().slice(0,8)
             url += '&fullscreen=default'
-            misc_page.open_popup_window(url, {width: 800, height: 640})
+            require('./misc_page').open_popup_window(url, {width: 800, height: 640})
             return

         @_ensure_project_is_open (err) =>
@@ -1334,7 +1332,7 @@
                         count  : if opts.paths.length > 3 then opts.paths.length

     download_file: (opts) =>
-        {download_file, open_new_tab} = misc_page
+        {download_file, open_new_tab} = require('./misc_page')
         opts = defaults opts,
             path    : required
             log     : false


fixed windows paths for cordova merges

fixed windows paths for cordova merges

--- src/steroids/GruntDefaults.coffee
+++ src/steroids/GruntDefaults.coffee
@@ -285,6 +285,7 @@
     if mergesExist
       # android
       for filePath in grunt.file.expand(path.join(androidMergesDirectory, "*")) when fs.lstatSync(filePath).isFile()
+        filePath = path.normalize(filePath) # fix windows path syntax
         grunt.log.writeln colorize.ansify(" #yellow[Copying Android Merges:]")

         # setup proper paths and filenames to steroids android comptible syntax: index.html to index.android.html
@@ -303,7 +304,8 @@
         fs.writeFileSync filePathInDistWithAndroidExtensionPrefix, fs.readFileSync(filePath)

       # ios
-      for filePath in grunt.file.expand(path.join(iosMergesDirectory, "*")) when fs.lstatSync(filePath).isDirectory()
+      for filePath in grunt.file.expand(path.join(iosMergesDirectory, "*")) when fs.lstatSync(filePath).isFile()
+        filePath = path.normalize(filePath) # fix windows path syntax
         grunt.log.writeln colorize.ansify(" #yellow[Copying iOS Merges:]")

         # setup proper paths for file copy
@@ -311,7 +313,7 @@

         grunt.log.writeln colorize.ansify("  #{filePath.replace(iosMergesDirectory+'/', '')} -> dist#{filePathInDist.replace(distDirectory, '')}")

-        if fs.existsSync filePathInDistWithAndroidExtensionPrefix
+        if fs.existsSync filePathInDist
           grunt.log.writeln colorize.ansify("   #red[Overwriting:] #reset[dist#{filePathInDist.replace(distDirectory, '')}]")

         fs.writeFileSync filePathInDist, fs.readFileSync(filePath)


Change layout name in custom to actual name

--- spec/keymap-manager-spec.coffee
+++ spec/keymap-manager-spec.coffee
@@ -702,7 +702,7 @@
       it "uses the US layout equivalent when the command key is held down", ->
         mockProcessPlatform('darwin')
         stub(KeyboardLayout, 'getCurrentKeymap', -> require('./helpers/keymaps/mac-dvorak-qwerty-cmd'))
-        stub(KeyboardLayout, 'getCurrentKeyboardLayout', -> 'DVORAK-QWERTYCMD')
+        stub(KeyboardLayout, 'getCurrentKeyboardLayout', -> 'org.unknown.keylayout.DVORAK-QWERTYCMD')
         assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent({key: 'l', code: 'KeyP', altKey: true})), 'alt-l')
         assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent({key: 'l', code: 'KeyP', ctrlKey: true, altKey: true})), 'ctrl-alt-l')
         assert.equal(keymapManager.keystrokeForKeyboardEvent(buildKeydownEvent({key: 'l', code: 'KeyP', metaKey: true})), 'cmd-p')


cleanup as prep

cleanup as prep

--- spec/motion-general-spec.coffee
+++ spec/motion-general-spec.coffee
@@ -1491,8 +1491,9 @@
             text: referenceText
             cursor: referenceCursorPosition

-  describe "the gg keybinding", ->
-    beforeEach ->
+  describe "the gg keybinding with stayOnVerticalMotion = false", ->
+    beforeEach ->
+      settings.set('stayOnVerticalMotion', false)
       set
         text: """
            1abc
@@ -1573,8 +1574,9 @@
         ensure 'v 2 g _',
           selectedText: "  2  \n 3abc"

-  describe "the G keybinding", ->
-    beforeEach ->
+  describe "the G keybinding (stayOnVerticalMotion = false)", ->
+    beforeEach ->
+      settings.set('stayOnVerticalMotion', false)
       set
         text_: """
         1
@@ -1611,9 +1613,11 @@
       it "100%", -> ensure '1 0 0 %', cursor: [999, 0]
       it "120%", -> ensure '1 2 0 %', cursor: [999, 0]

-  describe "the H, M, L keybinding", ->
+  describe "the H, M, L keybinding( stayOnVerticalMotio = false )", ->
     [eel] = []
     beforeEach ->
+      settings.set('stayOnVerticalMotion', false)
+
       eel = editorElement
       set
         text: """
@@ -1750,26 +1754,35 @@
       ensure '` `', cursor: [1, 5]

   describe "jump command update ` and ' mark", ->
-    ensureMark = (_keystroke, option) ->
-      keystroke(_keystroke)
-      ensure cursor: option.cursor
-      ensure mark: "`": option.mark
-      ensure mark: "'": option.mark
+    ensureJumpMark = (value) ->
+      ensure mark: "`": value
+      ensure mark: "'": value

     ensureJumpAndBack = (keystroke, option) ->
-      initial = editor.getCursorBufferPosition()
-      ensureMark keystroke, cursor: option.cursor, mark: initial
-      afterMove = editor.getCursorBufferPosition()
-      expect(initial.isEqual(afterMove)).toBe(false)
-      ensureMark "` `", cursor: initial, mark: option.cursor
+      afterMove = option.cursor
+      beforeMove = editor.getCursorBufferPosition()
+
+      ensure keystroke, cursor: afterMove
+      ensureJumpMark(beforeMove)
+
+      expect(beforeMove.isEqual(afterMove)).toBe(false)
+
+      ensure "` `", cursor: beforeMove
+      ensureJumpMark(afterMove)

     ensureJumpAndBackLinewise = (keystroke, option) ->
-      initial = editor.getCursorBufferPosition()
-      expect(initial.column).not.toBe(0)
-      ensureMark keystroke, cursor: option.cursor, mark: initial
-      afterMove = editor.getCursorBufferPosition()
-      expect(initial.isEqual(afterMove)).toBe(false)
-      ensureMark "' '", cursor: [initial.row, 0], mark: option.cursor
+      afterMove = option.cursor
+      beforeMove = editor.getCursorBufferPosition()
+
+      expect(beforeMove.column).not.toBe(0)
+
+      ensure keystroke, cursor: afterMove
+      ensureJumpMark(beforeMove)
+
+      expect(beforeMove.isEqual(afterMove)).toBe(false)
+
+      ensure "' '", cursor: [beforeMove.row, 0]
+      ensureJumpMark(afterMove)

     beforeEach ->
       for mark in "`'"


:fire: garbage

:fire: garbage

--- lib/vim-state.coffee
+++ lib/vim-state.coffee
@@ -85,9 +85,6 @@
       @activate('insert')
     else
       @activate('normal')
-
-  isNewInput: ->
-    @input instanceof Input

   # BlockwiseSelections
   # -------------------------


`setTimeout` broken information has been removed

--- cake/bundle/result.coffee
+++ cake/bundle/result.coffee
@@ -37,20 +37,6 @@
 	# standard polyfills
 	setImmediate = setTimeout
 	console.assert = console.assert.bind console
-
-	# informations
-	`
-	setTimeout = (function(){
-		var _super = setTimeout;
-
-		return function(){
-			console.warn("Using \`setTimeout()\` is not recommended; " +
-			             "use \`setImmediate()\` instead");
-
-			_super.apply(null, arguments);
-		};
-	})();
-	`

 	# used as `require`
 	getModule = (paths, name) ->


Add robustness.

Add robustness.

Sentry issue 2096.

--- src/views/new-search-results.coffee
+++ src/views/new-search-results.coffee
@@ -228,7 +228,7 @@
             @lengths[key] = arr.length
             return arr unless size
             arr.slice 0, size
-        onScroll: (ev) => @expandedView.onScroll(ev)
+        onScroll: (ev) => @expandedView?.onScroll(ev)
         disableAutoFocus: ->
             @autoFocusDisabled = true
         initialize: ({@collection, @fullCollection, @collectionType, @resultType, @onlyResultType, @selectedServices}) ->


added basic version of the dateinput, currently german only

--- lib/assets/javascripts/rails-jquery-dateinput/dateinput.js.coffee
+++ lib/assets/javascripts/rails-jquery-dateinput/dateinput.js.coffee
@@ -1,2 +1,39 @@
-$('document').ready ->
-  alert 1+$.tools.dateinput.conf.format = 'dd.mm.yyyy'
+$.tools.dateinput.localize 'de',
+  months:      'Januar,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember',
+  shortMonths: 'Jan,Feb,Mär,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez',
+  days:        'Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag',
+  shortDays:   'So,Mo,Di,Mi,Do,Fr,Sa'
+$.tools.dateinput.conf.lang = 'de';
+
+$(document).ready ->
+
+  $('div.date, div.datetime').each ->
+    year = month = day = null
+    $(@).find("select").each ->
+      switch $(@).attr('id').split('_').pop()
+        when '1i'
+          year = $(@)
+          year.hide()
+        when '2i'
+          month = $(@)
+          month.hide()
+        when '3i'
+          day = $(@)
+          day.hide()
+
+    current_date = new Date year.val(), month.val() - 1, day.val()
+    dateinput = $("<input type='date'>").dateinput
+      value: current_date
+      firstDay: 1
+      max: $(@).data('max')
+      min: $(@).data('min')
+
+    # Without this, the field is initially blank
+    dateinput.val dateinput.data().dateinput.getValue($.tools.dateinput.conf.format)
+
+    $(@).find('select:first').before dateinput
+    dateinput.data("dateinput").change ->
+      day.val this.getValue().getDate()
+      month.val this.getValue().getMonth() + 1
+      year.val this.getValue().getFullYear()


<debug> Adding forgotten attributes for driver creation.

--- server/controllers/driver.coffee
+++ server/controllers/driver.coffee
@@ -58,8 +58,8 @@
 				return cleanUp()

 			data =
-				path : file
-
+				path : file.path
+				originalFilename : file.originalFilename
 			Driver.create data, (err, driver) ->
 				if err?
 					if err == 'Driver already added'


Exception pane handles partial context exceptions.

--- picoCTF-web/web/coffee/management-exceptions.coffee
+++ picoCTF-web/web/coffee/management-exceptions.coffee
@@ -22,25 +22,34 @@
     newExceptions = _.reject @state.exceptions, (item) -> item == exception
     @setState {exceptions: newExceptions}

-  createInfoDisplay: (exception) ->
-    request = exception.request
-    user = exception.user
-
-

-
Exception:

-
{exception.trace}

-      <Col xs={6}>
+  createRequestInfo: (request) ->
+    if request
+

Browser information

Version: {request.browser} {request.browser_version}

Platform: {request.platform}

Address: {request.ip}

-      </Col>
-      <Col xs={6}>
+

+    else
+
No request information available.

+
+  createUserInfo: (user) ->
+    if user
+

User information

Username: {user.username}

Email: {user.email}

Team: {user.team_name}

-      </Col>
+

+    else
+
No user information available.

+
+  createInfoDisplay: (exception) ->
+

+
Exception:

+
{exception.trace}

+      <Col xs={6}> {@createRequestInfo(exception.request)} </Col>
+      <Col xs={6}> {@createUserInfo(exception.user)} </Col>

   createExceptionItem: (exception, i) ->


display total entries

display total entries

--- lib/carte/client/views/list.cjsx
+++ lib/carte/client/views/list.cjsx
@@ -41,7 +41,7 @@

       {if !@props.card

-

+

               {
                 for menuItem in config.menu_items
@@ -56,7 +56,15 @@

-

+

+            {
+              if @props.cards.pagination
+
+                  {@props.cards.pagination.total_entries}
+
+            }
+

+

             {
               if @props.cards.query.order == 'random'


Update json_form.js.coffee

Update json_form.js.coffee

--- vendor/assets/javascripts/middleware/component/json_form.js.coffee
+++ vendor/assets/javascripts/middleware/component/json_form.js.coffee
@@ -20,7 +20,7 @@
     @submitButton.on "click", =>
       @form.trigger("submit.rails")

-    @form.find("input").keypress (e) ->
+    @form.find("input").keypress (e) =>
       if e.which == 13
         @form.trigger("submit.rails")
         e.preventDefault()
@@ -43,4 +43,4 @@
   updateForm: (event, json) =>

   cancelForm:  =>
-    @container.remove()+    @container.remove()


Color carbon imbalance when available CO is zero

--- app/assets/javascripts/lib/views/table_views/carbon_balance_table_view.coffee
+++ app/assets/javascripts/lib/views/table_views/carbon_balance_table_view.coffee
@@ -12,7 +12,7 @@

       [selfVal, compVal] = @cell_balance_values(gqueryKey, cellEl.data('graph'))

-      if selfVal && compVal && selfVal > compVal
+      if selfVal? && compVal? && selfVal > compVal
         cellEl.addClass('warning')
       else
         cellEl.removeClass('warning')


File documentation

File documentation

--- lib/layervault/nodes/file.coffee
+++ lib/layervault/nodes/file.coffee
@@ -4,16 +4,34 @@

 Revision = require './revision'

+# Represents a single LayerVault File
 module.exports = class File extends Node
   relations:
     revisions: Revision

+  # Retrieves information about the file at this path.
+  #
+  # @param [Function] cb The finished callback.
   get: (cb) -> @api.get @nodePath, {}, @buildRelations(cb)

+  # Creates a file or a new revision at this path. Must be given
+  # a path to a file on disk and a mime-type for the file.
+  #
+  # @param [Object] options Configuration options for the file.
+  # @option options [String] localPath Path to the file on disk.
+  # @option options [String] contentType The mime-type of the file.
+  # @param [Function] cb The finished callback.
   create: (options, cb) ->
     service = new UploadService(@, options)
     service.perform cb.bind(@)

+  # Deletes the file at this path. Requires the MD5 of the latest version so
+  # that the server can validate it's deleting the right version.
+  #
+  # @param [Object] opts Configuration options. Can supply MD5 or path to the file.
+  # @option options [String] md5 The md5 of this file.
+  # @option options [String] localPath The path to this file on disk. The MD5 will be calculated.
+  # @param [Function] cb The finished callback.
   delete: (opts, cb) ->
     if opts.md5?
       md5 = opts.md5
@@ -25,17 +43,55 @@

     @api.delete @nodePath, { md5: md5 }, cb.bind(@)

-  move: (to, cb) -> @api.post("#{@nodePath}/move", { to: to }, cb.bind(@))
+  # Moves this file to a new location in LayerVault. Must give the new folder path, but can optionally give
+  # a new file name as well.
+  #
+  # @param [Object] opts The configuration options
+  # @option opts [String] to (Required) The path of the folder where the file should reside. Relative to the organization root.
+  # @option opts [String] new_file_name (Optional) The new file name for this file.
+  # @param [Function] cb The finished callback.
+  move: (opts, cb) -> @api.post("#{@nodePath}/move", opts, cb.bind(@))
+
+  # @see File#move
   rename: @move

+  # Retrieves all revisions for this file.
+  #
+  # @param [Function] cb The finished callback.
   revisions: (cb) -> @api.get("#{@nodePath}/revisions", {}, @buildRelationsArray('revisions', @relations.revisions, cb))
+
+  # Retrieves the latest preview for this file.
+  #
+  # @overload preview(cb)
+  #   Fetches the preview in its original state.
+  #   @param [Function] cb The finished callback.
+  #
+  # @overload preview(opts, cb)
+  #   Fetches the preview and sends transformations to Imgix.
+  #   @param [Object] opts Hash of options to pass to Imgix for formatting the preview.
+  #   @param [Function] cb The finished callback.
   preview: (args...) ->
     [opts, cb] = @parsePreviewOptions(args)
     @api.get("#{@nodePath}/preview", opts, cb.bind(@))

+  # Retrieves all of the previews for the latest revision of this file.
+  #
+  # @overload previews(cb)
+  #   Fetches the preview in its original state.
+  #   @param [Function] cb The finished callback.
+  #
+  # @overload previews(opts, cb)
+  #   Fetches the preview and sends transformations to Imgix.
+  #   @param [Object] opts Hash of options to pass to Imgix for formatting the preview.
+  #   @param [Function] cb The finished callback.
   previews: (args...) ->
     [opts, cb] = @parsePreviewOptions(args)
     @api.get("#{@nodePath}/previews", opts, cb.bind(@))

+  # Retrieves all feedback items left on this File.
+  #
+  # @param [Function] cb The finished callback.
   feedbackItems: (cb) -> @api.get "#{@nodePath}/feedback_items", {}, cb.bind(@)
+
+  # @see File#feedbackItems
   feedback: @feedbackItems


Testing --split option

Testing --split option

--- tests/unit/polvo/heavy.coffee
+++ tests/unit/polvo/heavy.coffee
@@ -100,8 +100,45 @@
     delete_config()
     delete_package()

-
-  it 'should release project without any surprises', ->
+  it 'should compile app using --split without any surprises', ->
+    errors = outs = 0
+    # checker = /✓ public\/app\.(js|css).+$/m
+    checker = ///
+      (
+        ✓ public/__split__/polvo/tests/fixtures/
+        (
+          basic/mapped/src/lib.js
+          | basic/src/app/app.js
+          | basic/src/app/vendor-hold.js
+          | basic/src/templates/_header.js
+          | basic/src/templates/top.js
+          | basic/vendors/another.vendor.js
+          | basic/vendors/some.vendor.js
+        ).+
+      )?
+      |(✓ public/app.js)
+      |(✓ public/app.css)
+    ///
+
+    options = compile: true, base: fix_path, split: true
+    stdio =
+      nocolor: true
+      err:(msg) -> errors++
+      out:(msg) ->
+        outs++
+        checker.test(msg).should.be.true
+
+    write_config()
+    write_package()
+
+    compile = polvo options, stdio
+    outs.should.equal 9
+    errors.should.equal 0
+
+    delete_config()
+    delete_package()
+
+  it 'should release app without any surprises', ->
     errors = outs = 0
     checker = /✓ public\/app\.(js|css).+$/m

@@ -120,8 +157,45 @@
     delete_config()
     delete_package()

-
-  it 'should release and serve project without any surprises', (done)->
+  it 'should release app using --split without any surprises', ->
+    errors = outs = 0
+    checker = ///
+      (
+        ✓ public/__split__/polvo/tests/fixtures/
+        (
+          basic/mapped/src/lib.js
+          | basic/src/app/app.js
+          | basic/src/app/vendor-hold.js
+          | basic/src/templates/_header.js
+          | basic/src/templates/top.js
+          | basic/vendors/another.vendor.js
+          | basic/vendors/some.vendor.js
+        ).+
+      )?
+      |(✓ public/app.js)
+      |(✓ public/app.css)
+    ///
+
+    options = release: true, base: fix_path, split: true
+    stdio =
+      nocolor: true
+      err:(msg) -> errors++
+      out:(msg) ->
+        outs++
+        checker.test(msg).should.be.true
+
+    write_config()
+    write_package()
+
+    compile = polvo options, stdio
+    outs.should.equal 9
+    errors.should.equal 0
+
+    delete_config()
+    delete_package()
+
+
+  it 'should release and serve app without any surprises', (done)->

     errors = outs = 0
     checkers = [


Be defensive about the regex

Be defensive about the regex

Closes #373

--- lib/project/results-model.coffee
+++ lib/project/results-model.coffee
@@ -217,7 +217,7 @@
       @emitter.emit 'did-remove-result', {filePath}

   onContentsModified: (editor) =>
-    return unless @active
+    return unless @active and @regex
     return unless editor.getPath()

     matches = []


i'm an idiot

i'm an idiot

--- modules/player/hud.coffee
+++ modules/player/hud.coffee
@@ -100,7 +100,7 @@
         { name: 'Position in queue:', value: "##{pos}", inline: true }
       ]
       footer:
-        icon_url: msg.author.avatarURL
+        icon_url: aby.avatarURL
         text: "Requested by #{@getDisplayName aby}"
     fstr = @parseFilters(item.filters)
     reply.description = "**Filters**: #{fstr}" if fstr
@@ -120,7 +120,7 @@
         { name: 'Length:', value: "#{@parseTime item.duration} + \n ", inline: true }
       ]
       footer:
-        icon_url: msg.author.avatarURL
+        icon_url: aby.avatarURL
         text: "Removed by #{@getDisplayName aby}"
     fstr = @parseFilters(item.filters)
     reply.description = "**Filters**: #{fstr}" if fstr
@@ -135,7 +135,7 @@
       color: 0x42A7F4
       description: "Added a playlist of **#{length}** items to the queue!"
       footer:
-        icon_url: msg.author.avatarURL
+        icon_url: aby.avatarURL
         text: "Requested by #{@getDisplayName aby}"

   swapItems: (guild, aby, items, indexes)=>


staticAvatarURL

staticAvatarURL

--- modules/player/hud.coffee
+++ modules/player/hud.coffee
@@ -86,7 +86,7 @@
         { name: 'Position in queue:', value: "##{pos}", inline: true }
       ]
       footer:
-        icon_url: item.requestedBy.avatarURL
+        icon_url: item.requestedBy.staticAvatarURL
         text: "Requested by #{item.requestedBy.name}"
     if item.filters and item.filters.length
       reply.description = "**Filters**: #{@util.displayFilters(item.filters)}"
@@ -119,7 +119,7 @@
       ]
     if removedBy
       reply.footer =
-        icon_url: removedBy.avatarURL
+        icon_url: removedBy.staticAvatarURL
         text: "Removed by #{removedBy.name}"
     if item.filters and item.filters.length
       reply.description = "**Filters**: #{@util.displayFilters(item.filters)}"
@@ -130,7 +130,7 @@
       color: 0x42A7F4
       description: "Added a playlist of **#{length}** items to the queue!"
       footer:
-        icon_url: user.avatarURL
+        icon_url: user.staticAvatarURL
         text: "Requested by #{user.name}"

   nowPlayingEmbed: (item)=>
@@ -149,7 +149,7 @@
         url: item.thumbnail
       footer:
         text: "Requested by #{item.requestedBy.name}"
-        icon_url: item.requestedBy.avatarURL
+        icon_url: item.requestedBy.staticAvatarURL
       fields: [
         { inline: true, name: 'Length', value: @util.displayTime item.duration }
       ]


Ace: No need to create caret position element and fix getting options.

--- client/Ace/AppView.coffee
+++ client/Ace/AppView.coffee
@@ -32,9 +32,7 @@
     else
       @findAndReplaceView = new KDCustomHTMLView

-    @caretPosition = new KDCustomHTMLView
-
-    if @getOptions().createBottomBar
+    if @getOption 'createBottomBar'
       @caretPosition  = new KDCustomHTMLView
         tagName       : 'div'
         cssClass      : 'caret-position section'
@@ -199,7 +197,7 @@
     @_windowDidResize()

   pistachio:->
-    hasBottomBar = @getOptions 'createBottomBar'
+    hasBottomBar = @getOption 'createBottomBar'
     template     = """
       <div class="kdview editor-main">
         {{> @ace}}


Use correct case when requiring subscriber

--- src/app/tokenized-buffer.coffee
+++ src/app/tokenized-buffer.coffee
@@ -1,7 +1,7 @@
 _ = require 'underscore'
 ScreenLine = require 'screen-line'
 EventEmitter = require 'event-emitter'
-Subscriber = require 'Subscriber'
+Subscriber = require 'subscriber'
 Token = require 'token'
 Range = require 'range'
 Point = require 'point'


use buildKey for prefixing name and host

--- libraries/metrics/metrics.coffee
+++ libraries/metrics/metrics.coffee
@@ -20,8 +20,8 @@

 module.exports = Metrics =
 	initialize: (_name) ->
-		name = _name
-		collectDefaultMetrics({ timeout: 5000, prefix: name + "_" })
+		name = _name + "_"
+		collectDefaultMetrics({ timeout: 5000, prefix: name+"_"})

 	registerDestructor: (func) ->
 		destructors.push func
@@ -46,7 +46,7 @@
 		key = this.sanitizeKey(key)
 		if !counters[key]
 			counters[key] = new prom.Counter({
-		  		name: key,
+		  		name: buildKey(key),
 				help: key,
 				labelNames: ['name','host']
 			})
@@ -73,7 +73,7 @@
 		key = this.sanitizeKey(key)
 		if !gauges[key]
 			gauges[key] = new prom.Gauge({
-		  		name: key,
+		  		name: buildKey(key),
 				help: key,
 				labelNames: ['name','host']
 			})
@@ -84,7 +84,7 @@
 		key = this.sanitizeKey(key)
 		if !gauges[key]
 			gauges[key] = new prom.Gauge({
-		  		name: key,
+		  		name: buildKey(key),
 				help: key,
 				labelNames: ['name','host']
 			})


commenting out the "timeout"

commenting out the "timeout"

--- node_modules/bongo-client/src/bongo.coffee
+++ node_modules/bongo-client/src/bongo.coffee
@@ -204,7 +204,7 @@
       scrubber.scrub args, =>
         message = scrubber.toDnodeProtocol()
         message.method = method
-        message.timeout = @getTimeout(message)
+        # message.timeout = @getTimeout(message)
         messageString = JSON.stringify(message)
         @channel.emit 'client-message', messageString


Use proper command to clear selected position.

--- src/views/position-details.coffee
+++ src/views/position-details.coffee
@@ -109,8 +109,7 @@

         selfDestruct: (event) ->
             event.stopPropagation()
-            @selectedPosition.clear()
-
+            app.commands.execute 'clearSelectedPosition'

     class DivisionListItemView extends base.SMItemView
         events:


minor fix

minor fix

--- library/membrane/securing.coffee
+++ library/membrane/securing.coffee
@@ -118,7 +118,7 @@
     # is asynchronously wired in, so consult with `async` package.
     # Please be sure invoke the `next` arg to proceed, if relevant.
     ignition: (request, response, next) ->
-        str = (address) -> address?.address
+        str = (addr) -> addr?.address or null
         inbound = request.connection.address()
         assert server = @kernel.server.address()
         assert secure = @kernel.secure.address()


Change main op hook to "ignition" in the SslOnly

--- library/membrane/securing.coffee
+++ library/membrane/securing.coffee
@@ -112,12 +112,12 @@
     # mainly is used to exclude or account for abstract classes.
     @abstract yes

-    # A hook that will be called prior to invoking the API method
-    # implementation. Please refer to this prototype signature for
+    # A hook that will be called prior to firing up the processing
+    # of the service. Please refer to this prototype signature for
     # information on the parameters it accepts. Beware, this hook
     # is asynchronously wired in, so consult with `async` package.
     # Please be sure invoke the `next` arg to proceed, if relevant.
-    preprocess: (request, response, resource, domain, next) ->
+    ignition: (request, response, next) ->
         connection = request?.connection
         encrypted = connection?.encrypted
         return next() if _.isObject encrypted


add error marker removal on inputs

add error marker removal on inputs

--- library/semantic/controls.coffee
+++ library/semantic/controls.coffee
@@ -66,6 +66,7 @@
         assert _.isObject input = $ "<input>", type: "password"
         field = $("<div>", class: "field").appendTo @container
         wrap = $ "<div>", class: "icon input ui left labeled"
+        input.on "input", -> do -> field.removeClass "error"
         assert corner = $ "<div>", class: "ui corner label"
         assert asterisk = $ "<i>", class: "icon asterisk"
         assert icon = $ "<i>", class: "icon #{icon}" if icon
@@ -85,6 +86,7 @@
         assert _.isObject label = $ "<label>", class: "label"
         field = $("<div>", class: "field").appendTo @container
         wrap = $ "<div>", class: "icon input ui left labeled"
+        input.on "input", -> do -> field.removeClass "error"
         assert corner = $ "<div>", class: "ui corner label"
         assert asterisk = $ "<i>", class: "icon asterisk"
         assert icon = $ "<i>", class: "icon #{icon}" if icon
@@ -105,6 +107,7 @@
         assert _.isObject input = $ "<input>", type: "checkbox"
         field = $("<div>", class: "field").appendTo @container
         wrap = $ "<div>", class: what; field.addClass "inline"
+        input.on "input", -> do -> field.removeClass "error"
         try $(field).data "identity", identity.toString()
         field.addClass try identity.toString() if identity
         input.appendTo wrap; field.append wrap.append label
@@ -121,6 +124,7 @@
         assert _.isObject label = $ "<label>", class: "label"
         field = $("<div>", class: "field").appendTo @container
         wrap = $ "<div>", class: "icon input ui left labeled"
+        input.on "input", -> do -> field.removeClass "error"
         assert icon = $ "<i>", class: "icon #{icon}" if icon
         assert input.attr placeholder: synopsis.toString()
         try $(field).data "identity", identity.toString()


Clean up syntax

Clean up syntax

--- app/assets/javascripts/admin/controllers/enterprises_dashboard_controller.js.coffee
+++ app/assets/javascripts/admin/controllers/enterprises_dashboard_controller.js.coffee
@@ -1,5 +1,2 @@
-angular.module("ofn.admin").controller "enterprisesDashboardCtrl", [
-  "$scope"
-  ($scope) ->
-    $scope.activeTab = "hubs"
-]+angular.module("ofn.admin").controller "enterprisesDashboardCtrl", ($scope) ->
+  $scope.activeTab = "hubs"


Lint style.

Lint style.

--- client/publication.coffee
+++ client/publication.coffee
@@ -831,7 +831,7 @@

 Template.annotationsControl.inside = ->
   Group.documents.find
-   _id:
+    _id:
       $in: getAnnotationDefaults().groups
   ,
     sort: [


Moved event to correct template

Moved event to correct template

--- client/views/admin.coffee
+++ client/views/admin.coffee
@@ -7,6 +7,15 @@
 Template.admin.events
   "click .servt tr": ->
     Router.go Router.routes["adminServer"].path {id: @_id}
+  "click .plbSdn": ->
+    id = @_id
+    if !confirm 'Are you sure you want to disband this perfectly decent lobby?'
+      $.pnotify
+        title: "Didn't Think So"
+        text: "They seem just fine, don't worry."
+        type: "success"
+      return
+    Meteor.call "shutdownLobby", id, showNiceNot

 Template.adminServer.resolvLob = ->
   lobbies.findOne({_id: @lobby})
@@ -22,16 +31,8 @@
       title: "Command Sent"
       text: "Your command has completed without errors."
       type: "success"
+
 Template.adminServer.events
-  "click .plbSdn": ->
-    id = @_id
-    if !confirm 'Are you sure you want to disband this perfectly decent lobby?'
-      $.pnotify
-        title: "Didn't Think So"
-        text: "They seem just fine, don't worry."
-        type: "success"
-      return
-    Meteor.call "shutdownLobby", id, showNiceNot
   "click .sdBtn": ->
     id = @_id
     if !confirm 'Are you sure you want to shut down '+@ip+"?"


serveral adjustements

serveral adjustements

--- cnab/test/DevUtils.coffee
+++ cnab/test/DevUtils.coffee
@@ -1,13 +1,38 @@
 _ = require 'lodash'
 expect = require 'expect.js'
 DevUtils = require '../src/DevUtils'
+fs = require 'fs'
+
+FILE_HEADER = 'ArquivoHeader'
+FILE_TRAILING = 'ArquivoTrailing'
+LOT_HEADER = 'LoteHeader'
+LOT_TRAILING = 'LoteTrailing'
+DETAIL = 'Detail'
+DETAIL2 = 'Detail2'
+FILE_SECTIONS = [FILE_HEADER, LOT_HEADER, DETAIL, DETAIL2, LOT_TRAILING, FILE_TRAILING]

 bank = 'Bradesco'
 type = 'Pagamento'

 validator = new DevUtils bank, type
-validator.validate()
-validator.getRequired()
+# validator.validate()
+# validator.getRequired()
+
+fileString = fs.readFileSync '/home/andre/remessa'
+fileData = fileString.toString()
+process.stdout.write '### '
+console.log fileData
+process.stdout.write ' ###'
+
+console.log '\n>>>>> extracted fields\n'
+extractedFields = validator.extract FILE_SECTIONS, fileData
+
+console.log '\n>>>>> fields length validation'
+validator.validateFieldsLength extractedFields
+
+console.log '\n>>>>> file length validation\n'
+expect(fileData.length).to.be FILE_SECTIONS.length * 240 + FILE_SECTIONS.length - 1
+

 # coffeelint: enable=no_trailing_whitespace
 # validator.extract sections, string


[misc] Router: prefix the publicId with 'P.' for easy differentiation

--- services/real-time/app/coffee/Router.coffee
+++ services/real-time/app/coffee/Router.coffee
@@ -68,7 +68,7 @@
 				return

 			# send positive confirmation that the client has a valid connection
-			client.publicId = base64id.generateId()
+			client.publicId = 'P.' + base64id.generateId()
 			client.emit("connectionAccepted", null, client.publicId)

 			metrics.inc('socket-io.connection')


Don't open modal windows when clicking disabled elements

Checking if the element is disabled using the class 'disabled'.
Had to also check after the binding because some elements are disabled
via javascript after they are loaded, so they don't have the class
'disabled' when binding, only when they get clicked.

refs #1279

--- app/assets/javascripts/app/application/confirmation_dialog.js.coffee
+++ app/assets/javascripts/app/application/confirmation_dialog.js.coffee
@@ -7,10 +7,13 @@

   # Binds the events for all links with confirmation set.
   @bind: ->
-    $('[data-confirm]').each ->
+    $('[data-confirm]:not(.disabled)').each ->
       $link = $(this)
+
       $link.off "click.mconfConfirmationDialog"
       $link.on "click.mconfConfirmationDialog", (e) ->
+        return if $link.hasClass('disabled') # #1279
+
         e.preventDefault()

         # first creates the dialog, will only create if it's not there yet


added connectWith for performance

added connectWith for performance

--- app/assets/javascripts/components/favorite-anime-container.js.coffee
+++ app/assets/javascripts/components/favorite-anime-container.js.coffee
@@ -7,8 +7,7 @@
     return !@get('isEditing')
   ).property('isEditing')

-  connectWith: ->
-    this.$().find('.grid-thumb')
+  connectWith: '.grid-thumb'

   updateSortOrder: (indexes)->
     list = @get("favorite_anime_list")


#183 Fix offset issues

#183 Fix offset issues

--- app/assets/javascripts/oxalis/model/volumetracing/volumelayer.coffee
+++ app/assets/javascripts/oxalis/model/volumetracing/volumelayer.coffee
@@ -25,8 +25,8 @@
       @minCoord = pos.slice()

     for i in [0..2]
-      @minCoord[i] = Math.min(@minCoord[i], Math.floor(pos[i]) - 1)
-      @maxCoord[i] = Math.max(@maxCoord[i], Math.ceil(pos[i]) + 1)
+      @minCoord[i] = Math.min(@minCoord[i], Math.floor(pos[i]) - 2)
+      @maxCoord[i] = Math.max(@maxCoord[i], Math.ceil(pos[i]) + 2)

   getSmoothedContourList : ->
@@ -44,9 +44,8 @@
     minCoord2d = @get2DCoordinate(@minCoord)
     maxCoord2d = @get2DCoordinate(@maxCoord)

-    # There should be a clear 1-pixel line at each side
-    width      = maxCoord2d[0] - minCoord2d[0] + 1 + 2
-    height     = maxCoord2d[1] - minCoord2d[1] + 1 + 2
+    width      = maxCoord2d[0] - minCoord2d[0] + 1
+    height     = maxCoord2d[1] - minCoord2d[1] + 1

     map = new Array(width)
     for x in [0...width]
@@ -57,7 +56,7 @@
     setMap = (x, y, value = true) ->

       x = Math.floor(x); y = Math.floor(y)
-      map[x - minCoord2d[0] + 1][y - minCoord2d[1] + 1] = value
+      map[x - minCoord2d[0]][y - minCoord2d[1]] = value

     # The approach is to initialize the map to true, then


...that's not right

...that's not right

--- resources/assets/coffee/_classes/store-supporter-tag-price.coffee
+++ resources/assets/coffee/_classes/store-supporter-tag-price.coffee
@@ -32,7 +32,7 @@
       when @_price < 20 then 6
       when @_price < 22 then 8
       when @_price < 24 then 9
-      when @_price < 25 then 10
+      when @_price < 26 then 10
       else
         Math.floor(@_price / 26.0 * 12)


Add storyboard icon to beatmap card

Add storyboard icon to beatmap card

--- resources/assets/coffee/react/_components/beatmapset-panel.coffee
+++ resources/assets/coffee/react/_components/beatmapset-panel.coffee
@@ -102,9 +102,12 @@
             src: beatmapset.covers.card
           div className: 'beatmapset-panel__image-overlay'
           div className: 'beatmapset-panel__status-container',
-            if beatmapset.video or beatmapset.storyboard
+            if beatmapset.video
               div className: 'beatmapset-panel__video-icon',
                 i className: 'fas fa-film fa-fw'
+            if beatmapset.storyboard
+              div className: 'beatmapset-panel__storyboard-icon',
+                i className: 'fas fa-image fa-fw'
             div className: 'beatmapset-status', beatmapset.status

           div className: 'beatmapset-panel__title-artist-box',


[Client][Activity] Change function name and the way it assigns createdAts

--- client/Social/Activity/AppController.coffee
+++ client/Social/Activity/AppController.coffee
@@ -176,7 +176,7 @@
       if @getFeedFilter() is "Public"
         @once "publicFeedFetched_#{eventSuffix}", (messages)=>
           reset()
-          @extractCacheTimeStamps messages
+          @extractMessageTimeStamps messages
           @listController.listActivities messages
           callback messages

@@ -184,7 +184,7 @@
       else
         @once "followingFeedFetched_#{eventSuffix}", (activities)=>
           reset()
-          @extractCacheTimeStamps messages
+          @extractMessageTimeStamps messages
           @listController.listActivities messages
           callback messages

@@ -225,8 +225,11 @@
       @reachedEndOfActivities = yes

   # Store first & last cache activity timestamp.
-  extractCacheTimeStamps: (cache)->
-    @setLastTimestamps (new Date cache.from).getTime(), (new Date cache.to).getTime()
+  extractMessageTimeStamps: (messages)->
+    return  if messages.length is 0
+    from = new Date(messages.last.meta.createdAt).getTime()
+    to   = new Date(messages.first.meta.createdAt).getTime()
+    @setLastTimestamps to, from #from, to

   # Store first & last activity timestamp.
   extractTeasersTimeStamps:(teasers)->


client/app: remove isManagedVMStack util

Signed-off-by: Umut Sirin <4055abbc0e40a1254e715b952ccd414607e0b365@gmail.com>

--- client/app/lib/util/isManagedVMStack.coffee
+++ client/app/lib/util/isManagedVMStack.coffee
@@ -1,6 +0,0 @@
-# This module is intended to provide a single place to edit in case
-# Managed VMs stack implementation is changed in the future.
-
-MANAGED_VMS = 'Managed VMs'
-
-module.exports = (stack) -> stack.title is MANAGED_VMS


Fix translation of application description, refs #619

--- client/app/views/popover_description.coffee
+++ client/app/views/popover_description.coffee
@@ -52,8 +52,13 @@

         @body.html ""

-        description = t @model.get "description"
-        @header.parent().append "
 #{description}
"
+        description = @model.get 'description'
+        localeKey = "#{@model.get 'name'} description"
+        localeDesc = t localeKey
+        if localeDesc is localeKey
+            # description is not translated
+            localeDesc = t description
+        @header.parent().append "
 #{localeDesc}
"

         permissions = @model.get("permissions")
         if not permissions? or Object.keys(permissions).length is 0


filter out typing messages

filter out typing messages

--- client/views/app/chatWindowDashboard.coffee
+++ client/views/app/chatWindowDashboard.coffee
@@ -26,11 +26,11 @@
 		console.log 'chatWindowDashboard.helpers messages' if window.rocketDebug
 		window.lastMessageWindow[this._id] = undefined
 		window.lastMessageWindowHistory[this._id] = undefined
-		return ChatMessage.find { rid: this._id }, { sort: { ts: 1 } }
+		return ChatMessage.find { rid: this._id, t: { '$ne': 't' } }, { sort: { ts: 1 } }

 	messagesHistory: ->
 		console.log 'chatWindowDashboard.helpers messagesHistory' if window.rocketDebug
-		return ChatMessageHistory.find { rid: this._id }, { sort: { ts: 1 } }
+		return ChatMessageHistory.find { rid: this._id, t: { '$ne': 't' }  }, { sort: { ts: 1 } }

 	hasMore: ->
 		console.log 'chatWindowDashboard.helpers hasMore' if window.rocketDebug
@@ -58,17 +58,16 @@

 	usersTyping: ->
 		console.log 'chatWindowDashboard.helpers usersTyping' if window.rocketDebug
-		messages = ChatMessage.find { rid: this._id }, { sort: { ts: 1 } }
+		messages = ChatMessage.find { rid: this._id, t: 't' }, { sort: { ts: 1 } }
 		usernames = []
 		selfTyping = false
 		messages.forEach (message) ->
-			if message.t is 't'
-				if message.u._id is Meteor.userId()
-					selfTyping = true
-				else
-					username = message.u.username
-					if username?
-						usernames.push username
+			if message.u._id is Meteor.userId()
+				selfTyping = true
+			else
+				username = message.u.username
+				if username?
+					usernames.push username

 		if usernames.length is 0
 			return


[export] fix person export for unknown players

--- src/coffee/export-single.coffee
+++ src/coffee/export-single.coffee
@@ -34,7 +34,7 @@
                 else
                     nameRegexes.each (re) ->
                         matches = false
-                        if matches = entry.name.match re
+                        if matches = data.name.match re
                             data.nickname = matches[1].compact()
                             data.name = data.name.remove(re).compact()


bugfix: ignore transition action if method not exists

--- src/coffee_state_machine.coffee
+++ src/coffee_state_machine.coffee
@@ -257,7 +257,7 @@
                 for hook in trans_hooks when trans_hooks_called.indexOf(hook) is -1
                     if typeof hook is 'function'
                         hook.apply obj, [old_state, current_state]
-                    else if typeof hook is 'string'
+                    else if typeof hook is 'string' and 'function' is typeof obj[hook]
                         obj[hook](old_state, current_state)
                     trans_hooks_called.push(hook)


Fixed CascadingSelectsView to use more robust jquery

--- app/assets/javascripts/backbone/views/cascading_selects_view.js.coffee
+++ app/assets/javascripts/backbone/views/cascading_selects_view.js.coffee
@@ -16,7 +16,7 @@
   # Gets the next select box after the given one.
   # Returns false if not found.
   next_select: (select) ->
-    next = select.parent().next().find('select')
+    next = select.closest('div').next().find('select')
     next.length > 0 && next || false

   # Clears all selects after and including the given one.


remove unused code, tweak active node styling.

--- scripts/bungie-data-helper.coffee
+++ scripts/bungie-data-helper.coffee
@@ -1,11 +1,11 @@
 request = require('request')

 class DataHelper
-  'fetchDefs': ->
-    @fetchStatDefs (error, response, body) =>
-      @statDefs = JSON.parse(body)
-    @fetchVendorDefs (error, response, body) =>
-      @vendorDefs = JSON.parse(body)
+  # 'fetchDefs': ->
+  #   @fetchStatDefs (error, response, body) =>
+  #     @statDefs = JSON.parse(body)
+  #   @fetchVendorDefs (error, response, body) =>
+  #     @vendorDefs = JSON.parse(body)

   'serializeFromApi': (response) ->
     damageColor =
@@ -33,8 +33,8 @@
     nodeDefs: response.definitions.talentGrids[item.talentGridHash].nodes
     damageType: damageTypeName

-  'parseItemsForAttachment': (items) ->
-    items.map (item) => @parseItemAttachment(item)
+  # 'parseItemsForAttachment': (items) ->
+  #   items.map (item) => @parseItemAttachment(item)

   'parseItemAttachment': (item) ->
     name = "#{item.itemName}"
@@ -76,16 +76,16 @@
     return orderedNodes

   # creates fields for perks and their descriptions
-  'buildFields': (nodes, nodeDefs) ->
-    displayNodes = nodes.map (node) ->
-      step = nodeDefs[node.nodeIndex].steps[node.stepIndex]
-      description = step.nodeStepDescription.replace(/(\r\n|\n|\r)/gm," ").replace("  "," ")
-
-      title: step.nodeStepName
-      value: description
-      short: true
-
-    displayNodes.filter (x) -> x
+  # 'buildFields': (nodes, nodeDefs) ->
+  #   displayNodes = nodes.map (node) ->
+  #     step = nodeDefs[node.nodeIndex].steps[node.stepIndex]
+  #     description = step.nodeStepDescription.replace(/(\r\n|\n|\r)/gm," ").replace("  "," ")
+  #
+  #     title: step.nodeStepName
+  #     value: description
+  #     short: true
+  #
+  #   displayNodes.filter (x) -> x

   'buildText': (nodes, nodeDefs) ->
     getName = (node) ->
@@ -98,27 +98,27 @@
       column = nodeDefs[node.nodeIndex].column
       name = step.nodeStepName
       if node.isActivated
-        name = '_*' + step.nodeStepName + '*_'
+        name = "*#{step.nodeStepName}*"
       text[column] = "" unless text[column]
       text[column]+= name + " | "

     setText node for node in nodes
     return text

-  'fetchVendorDefs': (callback) ->
-    options =
-      method: 'GET'
-      url: 'http://destiny.plumbing/raw/mobileWorldContent/en/DestinyStatDefinition.json'
-      gzip: true
-
-    request(options, callback)
-
-  'fetchStatDefs': (callback) ->
-    options =
-      method: 'GET'
-      url: 'http://destiny.plumbing/raw/mobileWorldContent/en/DestinyStatDefinition.json'
-      gzip: true
-
-    request(options, callback)
+  # 'fetchVendorDefs': (callback) ->
+  #   options =
+  #     method: 'GET'
+  #     url: 'http://destiny.plumbing/raw/mobileWorldContent/en/DestinyStatDefinition.json'
+  #     gzip: true
+  #
+  #   request(options, callback)
+  #
+  # 'fetchStatDefs': (callback) ->
+  #   options =
+  #     method: 'GET'
+  #     url: 'http://destiny.plumbing/raw/mobileWorldContent/en/DestinyStatDefinition.json'
+  #     gzip: true
+  #
+  #   request(options, callback)

 module.exports = DataHelper


groups: removed highlighting logging

groups: removed highlighting logging

--- client/app/Applications/Groups.kdapplication/Views/readmeview.coffee
+++ client/app/Applications/Groups.kdapplication/Views/readmeview.coffee
@@ -66,7 +66,6 @@

   highlightCode:=>
     @$(".has-markdown pre").each (i,element)=>
-      log '!',element
       hljs.highlightBlock element