Replace actions for callbacks in collections Fix binding of upstream function in collections

--- app/assets/javascripts/action_cable_notifications/collection.coffee
+++ app/assets/javascripts/action_cable_notifications/collection.coffee
@@ -21,7 +21,7 @@
   connectionChanged = () ->
     if @channel.isConnected()
       _.each(@commandsCache, (cmd) ->
-        if upstream(cmd.command, cmd.params)
+        if upstream.call(this, cmd.command, cmd.params)
           cmd.performed = true
       )

@@ -31,9 +31,11 @@
       # Fetch data from upstream server when connection is resumed
       @fetch()

+    @callbacks?.connectionChanged?.call(this)
+
   # Public methods
   #######################################
-  constructor: (@store, @name, @tableName, @actions) ->
+  constructor: (@store, @name, @tableName, @callbacks) ->
     # Data storage array
     @data = []
     # Channel used to sync with upstream collection
@@ -45,13 +47,7 @@
     # Stores records that needs to be tracked when inserted into the collection
     @trackedRecords = []

-    # Bind private methods to class instance
-    ########################################################
-    upstream = upstream.bind(this)
-
-  initialize: () ->
-    if @actions?.initialize?
-      @actions.initialize.call(this)
+    @callbacks?.initialize?.call(this)

   # Sync collection to ActionCable Channel
   syncToChannel: (@channel) ->
@@ -63,90 +59,83 @@

   # Fetch records from upstream
   fetch: (params) ->
-    upstream("fetch", params)
+    upstream.call(this, "fetch", params)

   # Filter records from the current collection
   where: (selector={}) ->
-    if @actions?.where?
-      @actions.where.call(this, selector)
+    if @callbacks?.where?
+      @callbacks.where.call(this, selector)
     else
       _.filter(@data, selector)

   # Find a record
   find: (selector={}, options={}) ->
-    if @actions?.find?
-      @actions.find.call(this, selector, options)
+    record = _.find(@data, selector)
+
+    if !record and options.track
+      if selector.id
+        trackedRecord = _.find(@trackedRecords, {id: selector.id})
+        if trackedRecord
+          trackedRecord
+        else
+          trackedRecord = selector
+          @trackedRecords.push trackedRecord
+          trackedRecord
+      else
+        console.warn("[find] Id must be specified to track records")
     else
-      record = _.find(@data, selector)
-
-      if !record and options.track
-        if selector.id
-          trackedRecord = _.find(@trackedRecords, {id: selector.id})
-          if trackedRecord
-            trackedRecord
-          else
-            trackedRecord = selector
-            @trackedRecords.push trackedRecord
-            trackedRecord
-        else
-          console.warn("[find] Id must be specified to track records")
-      else
-        record
+      record

   # Creates a new record
   create: (fields={}) ->
-    if @actions?.create?
-      @actions.create.call(this, fields)
-    else
-      record = _.find(@data, {id: fields.id})
-      if record
-        console.warn("[create] Not expected to find an existing record with id #{fields.id}")
-        return
+    record = _.find(@data, {id: fields.id})
+    if record
+      console.warn("[create] Not expected to find an existing record with id #{fields.id}")
+      return

-      # Search in tracked records
-      recordIndex = _.findIndex(@trackedRecords, {id: fields.id})
-      if recordIndex>=0
-        fields = _.extend( @trackedRecords[recordIndex], fields )
-        @trackedRecords.splice(recordIndex, 1)
+    # Search in tracked records
+    recordIndex = _.findIndex(@trackedRecords, {id: fields.id})
+    if recordIndex>=0
+      fields = _.extend( @trackedRecords[recordIndex], fields )
+      @trackedRecords.splice(recordIndex, 1)

-      @data.push (fields) unless @sync
+    if !@sync
+      @data.push (fields)
+      @callbacks?.create?.call(this, fields)

-      upstream("create", {fields: fields})
-      fields
+    upstream.call(this, "create", {fields: fields})
+    fields

   # Update an existing record
   update: (selector={}, fields={}, options={}) ->
-    if @actions?.update?
-      @actions.update.call(this, selector, fields, options)
+    record = _.find(@data, selector)
+    if !record
+      if options.upsert
+        @create(fields)
+      else
+        console.warn("[update] Couldn't find a matching record:", selector)
     else
-      record = _.find(@data, selector)
-      if !record
-        if options.upsert
-          @create(fields)
-        else
-          console.warn("[update] Couldn't find a matching record:", selector)
-      else
-        _.extend(record, fields) unless @sync
-        upstream("update", {id: record.id, fields: fields})
-        record
+      if !@sync
+        @callbacks?.update?.call(this, selector, fields, options)
+        _.extend(record, fields)
+
+      upstream.call(this, "update", {id: record.id, fields: fields})
+      record

   # Update an existing record or inserts a new one if there is no match
   upsert: (selector={}, fields) ->
-    if @actions?.upsert?
-      @actions.upsert.call(this, selector, fields)
-    else
-      @update(selector, fields, {upsert: true})
+    @update(selector, fields, {upsert: true})

   # Destroy an existing record
   destroy: (selector={}) ->
-    if @actions?.destroy?
-      @actions.destroy.call(this, selector)
+    index = _.findIndex(@data, selector)
+    if index < 0
+      console.warn("[destroy] Couldn't find a matching record:", selector)
     else
-      index = _.findIndex(@data, selector)
-      if index < 0
-        console.warn("[destroy] Couldn't find a matching record:", selector)
-      else
-        record = @data[index]
-        @data.splice(index, 1) unless @sync
-        upstream("destroy", {id: record.id})
-        record
+      record = @data[index]
+      if !@sync
+        @data.splice(index, 1)
+        @callbacks.destroy.call(this, selector)
+
+      upstream.call(this, "destroy", {id: record.id})
+      record


removed substring of the first char

removed substring of the first char

--- app/assets/javascripts/type_station/editables/link_finder.js.coffee
+++ app/assets/javascripts/type_station/editables/link_finder.js.coffee
@@ -16,7 +16,7 @@
               data: {path: term}
               success: (data, status) ->
                 callback(data.pages)
-          replace: (page) -> page.path.substring(1)
+          replace: (page) -> page.path#.substring(1)
           template: (page) -> "#{page.title} (#{page.path})"
         }
       ],


Remove unnecessary class

Remove unnecessary class

--- resources/assets/coffee/react/_components/friend-button.coffee
+++ resources/assets/coffee/react/_components/friend-button.coffee
@@ -115,11 +115,11 @@
       title: if @state.friend then osu.trans('friends.buttons.remove') else osu.trans('friends.buttons.add')
       disabled: @state.loading
       if @state.loading
-        el Icon, name: 'refresh', modifiers: ['fw', 'spin']
+        el Icon, name: 'refresh', modifiers: ['spin']
       else
         if @state.friend
           if @state.hover
-            el Icon, name: 'user-times', modifiers: ['fw']
+            el Icon, name: 'user-times'
           else
             if @state.friend.mutual
               [
@@ -127,9 +127,9 @@
                 el Icon, name: 'user', key: 2
               ]
             else
-              el Icon, name: 'user', modifiers: ['fw']
+              el Icon, name: 'user'
         else
-          el Icon, name: 'user-plus', modifiers: ['fw']
+          el Icon, name: 'user-plus'

   isVisible: =>


use vertical instead of bracket

use vertical instead of bracket

--- parts/bottom-alert.cjsx
+++ parts/bottom-alert.cjsx
@@ -9,7 +9,7 @@
           </Alert>
         else if @props.formationNum != 0
           <Alert>
-            {"「#{@props.result}」「#{@props.formation}」「#{@props.intercept}」「#{@props.seiku}」"}
+            {"#{@props.result} | #{@props.formation} | #{@props.intercept} | #{@props.seiku}"}
           </Alert>
       }
     </div>


Add on/off to Events.wrap

Add on/off to Events.wrap

Closes https://github.com/motif/company/issues/1177

--- framer/DOMEventManager.coffee
+++ framer/DOMEventManager.coffee
@@ -21,6 +21,10 @@
 	addEventListener: @::addListener
 	removeEventListener: @::removeListener

+	# Keep the Node API working
+	on: @::addListener
+	off: @::removeListener
+
 class exports.DOMEventManager

 	constructor: (element) ->


update msg creating logic to check if new msg exists in collection

--- www/js/controllers/msg.coffee
+++ www/js/controllers/msg.coffee
@@ -61,33 +61,41 @@
 						$scope.$broadcast('scroll.infiniteScrollComplete')
 				return @
 			creating: ->
-				_.last(collection.models)?.$isNew()
+				_.find collection.models, (msg) ->
+					msg.$isNew()
 			addFile: (files) ->
 				if files?.length != 0
-					$scope.addMsg().then (msg) ->
-						msg.local = files[0]
-						msg.file =
-							url: if files[0] instanceof MediaFile then files[0].localURL else URL.createObjectURL files[0]
+					$scope.addMsg
+						local: files[0]
+						file:
+							url: files[0].localURL || URL.createObjectURL files[0]
 							name: files[0].name
 							type: files[0].type
 							base: files[0].name
 							ext: path.extname files[0].name
-						msg.file_inode = contentType: files[0].type
-						$scope.$apply 'collection.models'
-			addMsg: ->
-				msg = new resource.Msg type: type, to: chat.jid, body: ''
+						file_inode: contentType: files[0].type
+			addMsg: (attrs = {}) ->
+				_.defaults attrs,
+					type: type
+					to: chat.jid
+					body: ''
+				msg = new resource.Msg attrs
 				Promise
 					.try ->
 						socket = io.socket?._raw
 						if socket?.connected
 							Promise.resolve()
 						else
-							socket?.once 'connect', Promise.resolve
-							socket?.once 'error', Promise.reject
+							new Promise (resolve, reject) ->
+								socket?.once 'connect', resolve
+								socket?.once 'error', reject
 					.then ->
+						# send attachment if it is audio file
+						if /^blob/.test(msg.file?.url) and /^audio/.test(msg.file?.type)
+							return msg.$save().catch $log.error
 						collection.add msg
+						$scope.$apply 'collection.models'
 						$ionicScrollDelegate.scrollTop true
-						msg
 					.catch $log.error
 			recording: false
 			copy: (msg) ->
@@ -150,7 +158,8 @@
 					.catch $log.error
 				$scope.cancel(msg)
 			cancel: (msg) ->
-				$scope.collection.models.pop()
+				_.remove $scope.collection.models, (msg) ->
+					msg.$isNew()
 			getfile: ->
 				file = new resource.Attachment _.pick msg, 'id', 'file'
 				switch device.platform


EnvironmentMachineContainer: remove old data fetchers

--- client/Environments/views/scene/environmentmachinecontainer.coffee
+++ client/Environments/views/scene/environmentmachinecontainer.coffee
@@ -1,19 +1,4 @@
 class EnvironmentMachineContainer extends EnvironmentContainer
-
-  # EnvironmentDataProvider.addProvider "vms", ->
-
-  #   new Promise (resolve, reject)->
-
-  #     KD.remote.api.ComputeProvider.fetchExisting
-  #       provider : "koding"
-  #     , (err, vms)->
-
-  #       log "vms", vms
-  #       if err or vms.length is 0
-  #         warn "Failed to fetch VMs", err  if err
-  #         return resolve []
-
-  #       resolve vms

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

@@ -27,33 +12,3 @@

     @on 'PlusButtonClicked', =>
       ComputeController.UI.showProvidersModal @getData()
-
-  # loadItems:->
-
-  #   new Promise (resolve, reject)=>
-
-  #     vmc = KD.getSingleton 'vmController'
-
-  #     {entryPoint} = KD.config
-  #     cmd = if entryPoint then 'fetchGroupVMs' else 'fetchVmNames'
-
-  #     vmc.fetchGroupVMs yes, (err, vms)=>
-
-  #       @removeAllItems()
-
-  #       if err or vms.length is 0
-  #         warn "Failed to fetch VMs", err  if err
-  #         return resolve()
-
-  #       vms.forEach (vm, index)=>
-  #         {hostnameAlias} = vm
-  #         @addItem {
-  #           title     : hostnameAlias
-  #           cpuUsage  : KD.utils.getRandomNumber 100
-  #           memUsage  : KD.utils.getRandomNumber 100
-  #           activated : yes
-  #           hostnameAlias
-  #           vm
-  #         }
-
-  #         if index is vms.length - 1 then resolve()


Fixed bug to format as paragraph

Fixed bug to format as paragraph

--- plugins/headings.coffee
+++ plugins/headings.coffee
@@ -17,10 +17,10 @@
             buttonset.append jQuery("<input id=\"#{id}\" type=\"radio\" /><label for=\"#{id}\" class=\"p_button\">#{label}</label>").button()
             buttonset.children("label").unbind('mouseout')
             button = jQuery "##{id}", buttonset
-            button.attr "hallo-command", "removeFormat"
+            button.attr "hallo-command", "formatBlock"
             button.bind "change", (event) ->
                 cmd = jQuery(this).attr "hallo-command"
-                widget.options.editable.execute cmd
+                widget.options.editable.execute cmd, "P"

             buttonize = (headerSize) =>
                 label = "H" + headerSize


client: home: machinelist markup fixes

client: home: machinelist markup fixes

--- client/home/lib/virtualmachines/components/machineslist/listitem.coffee
+++ client/home/lib/virtualmachines/components/machineslist/listitem.coffee
@@ -30,14 +30,14 @@
     return null  unless @props.shouldRenderDetails
     return null  unless @state.isDetailOpen

-

+
       <MachineDetails
         machine={@props.machine}
         shouldRenderSpecs={@props.shouldRenderSpecs}
         shouldRenderPower={@props.shouldRenderPower}
         shouldRenderAlwaysOn={@props.shouldRenderAlwaysOn}
         shouldRenderSharing={@props.shouldRenderSharing} />
-

+

   renderDetailToggle: ->
@@ -46,24 +46,22 @@

     toggleOpen = (machineId) => (event) => @setState { isDetailOpen: not @state.isDetailOpen }

-

-      <button className="MachinesListItem-detailToggleIcon" onClick={toggleOpen @props.machine.get 'id'}>></button>
+

+      <button onClick={toggleOpen @props.machine.get 'id'}></button>

   render: ->

-

-

-        {@props.machine.get 'label'}
-

-

-        {@props.machine.get 'ipAddress'}
-

-

-        {@props.stack.get 'title'}
-

-      {@renderDetailToggle()}
+

+
+
{@props.machine.get 'label'}

+
{@props.machine.get 'ipAddress'}

+

+          {@props.stack.get 'title'}
+

+        {@renderDetailToggle()}
+
       {@renderMachineDetails()}


Not registering anon modules

Not registering anon modules

--- src/core.coffee
+++ src/core.coffee
@@ -75,8 +75,11 @@
   listModules: -> allRegistered

   registerModule: (id, modules, callback) ->
-    allRegistered[id] = { dependencies: modules, resolved: false }
-    # om den redan finns registrerad så ska ett fel genereras
+
+    # if the module is anonymous, there's no need to register it
+    if id?
+      allRegistered[id] = { dependencies: modules, resolved: false }
+
     setImm ->
       checkAllRegistered()


Remove useless test

Remove useless test

--- test/option_parser.coffee
+++ test/option_parser.coffee
@@ -20,8 +20,3 @@
     args = ['--css', 'banana']
     assert.throws ->
       new OptionParser(args, Skeleton.OPTIONS)
-
-  it 'should remove an argument when it is parsed', ->
-    args = ['--js', 'coffee', '--css', 'stylus']
-    options = new OptionParser(args, Skeleton.OPTIONS)
-    args.length.should.equal 0


Popup detach option, to detach popup contents instead of destroying when popup is closed.

--- lib/Popup.coffee
+++ lib/Popup.coffee
@@ -4,6 +4,8 @@
 # of the popup, in the event of a second click on the associated element
 popupID = -1
 popupIDs = 1
+
+detachPopup = false

 # Keeps track of callback function to execute on closing the popup
 popupCloseCallback = null
@@ -17,6 +19,7 @@
     popupID = null
     $('#popup').removeAttr('id').stop().fadeOut 100, ->
       onClose() if onClose
+      $(this).children().detach() if detachPopup
       $(this).remove()

 # Displays a popup menu.
@@ -27,6 +30,7 @@
   ST.pushCancelFunction closePopup

   popupID = id
+  detachPopup = options.detach

   offset = element.offset()


Fucking docs for `Comic.archive(..)`

Fucking docs for `Comic.archive(..)`

--- lib/comic.coffee
+++ lib/comic.coffee
@@ -100,6 +100,13 @@

       cb(undefined, comics)

+  # Invoke callback as `cb(err, {archive: [Comic, ...], next: Comic, prev: Comic}...)`
+  # `err` will be set if an error is encountered.
+  #
+  # Every Comic except the first comic in the `archive:` list are shallow-loaded, and should _NOT_
+  # be expected to contain pointer information, only the `Comic#time` should be considered correct, and if
+  # any additional info is required it should be loaded with `Comic.at` using `Comic#time` on the shallow
+  # objects.
   @archive: (start, cb) ->
     # Select either the latest (if start is nonsense or missing)
     # or the Comic specifed at `start` to begin the archive page


Disable Emmet comments by default

Disable Emmet comments by default

--- lib/emmet.coffee
+++ lib/emmet.coffee
@@ -131,7 +131,7 @@
       default: true
     useEmmetComments:
       type: 'boolean'
-      default: true
+      default: false
       description: 'disable to use atom native commenting system'

   activate: (@state) ->


#179 link issue

#179 link issue

--- lib/hover.coffee
+++ lib/hover.coffee
@@ -19,6 +19,7 @@
       when @vimState.isMode('visual', 'linewise')
         swrap(@editor.getLastSelection()).getCharacterwiseHeadPosition()
       when @vimState.isMode('visual', 'blockwise')
+        # FIXME #179
         @vimState.getLastBlockwiseSelections()?.getHead().getHeadBufferPosition()
       else
         @editor.getCursorBufferPosition()


forgot to export things

forgot to export things

--- lib/index.coffee
+++ lib/index.coffee
@@ -66,10 +66,10 @@
 once = (f) ->
   do (k=undefined) ->
     -> if k? then k else (k = f())
-
+
 memoize = (f) ->
   do (cache={}) -> (args...) -> cache[args] ?= f args...

 export {noOp, identity, wrap, curry, _, substitute,
   partial, flip, compose, pipe, spread, unary, binary, ternary,
-  apply, negate, once, given, memoize}
+  apply, negate, once, tee, given, memoize}


remove console.log

remove console.log

--- pattern/pattern_convert.coffee
+++ pattern/pattern_convert.coffee
@@ -4,7 +4,6 @@
 class LiteralPatternConverter
 	constructor : (str)->
 		@_content = str
-		console.log(@_content)

 	format : (context)->
 		context.out += @_content


auto load the vehicles controllers

auto load the vehicles controllers

--- lib/controllers/vehicles_controller.coffee
+++ lib/controllers/vehicles_controller.coffee
@@ -1,4 +1,6 @@
 Sensor.VehiclesController = SC.ArrayProxy.extend
+  init: ->
+    @load()
   content: []
   date: SC.DateTime.create()
   liveDataset: ( ->


Bring the ROI blocker up and stop all mouse interaction through it

--- show-roi.coffee
+++ show-roi.coffee
@@ -34,7 +34,7 @@
     # Reverse the points so they're counterclockwise and knock out the clockwise outer shape.
     nestingPoints = roi[site].slice(0).reverse()

-    nestingOutline = classifyPage.subjectViewer.markingSurface.addShape 'path.nesting-area',
+    nestingOutline = classifyPage.subjectViewer.markingSurface.svg.addShape 'path.nesting-area',
       d: """
         M 0 0 L #{width + 0} 0 L #{width + 0} #{height + 0} L 0 #{height + 0}
         L 0 0
@@ -46,3 +46,5 @@

     nestingOutline.addEvent 'mousedown', stopPropagation
     nestingOutline.addEvent 'touchstart', stopPropagation
+    nestingOutline.addEvent 'mousemove', stopPropagation
+    nestingOutline.addEvent 'touchmove', stopPropagation


Fix typos when `runas` fails

Fix typos when `runas` fails

--- src/file.coffee
+++ src/file.coffee
@@ -403,8 +403,9 @@

       fs.removeSync(@getPath())
       return
-    catch err
-      if err.code is 'EACCES' and process.platform is 'darwin'
+    catch error
+      if error.code is 'EACCES' and process.platform is 'darwin'
+        runas ?= require 'runas'
         # Use sync to force completion of pending disk writes.
         if runas('/bin/sync', [], admin: true) isnt 0
           throw error


separate test_new_settings from save_specs

--- js/inner/project.coffee
+++ js/inner/project.coffee
@@ -315,19 +315,10 @@
     false # dont bubble the event up

   save_dependencies: (data, event) =>
-    # Comment this out until changing settings doesn't kick off a new build
-    # $.ajax
-    #   type: "PUT"
-    #   event: event
-    #   url: "/api/v1/project/#{@project_name()}/settings"
-    #   data: JSON.stringify
-    #     setup: @setup()
-    #     dependencies: @dependencies()
-    #     post_dependencies: @post_dependencies()
-    true # bubble up so that we move to the test step
-
-
-  save_specs: (data, event) =>
+    @save_specs data, event, =>
+      window.location.hash = "#tests"
+
+  save_specs: (data, event, callback) =>
     $.ajax
       type: "PUT"
       event: event
@@ -338,9 +329,22 @@
         post_dependencies: @post_dependencies()
         test: @test()
         extra: @extra()
+      success: () =>
+        if callback
+          callback.call(data, event)
+    false # dont bubble the event up
+
+  create_settings_build: (data, event) =>
+    $.ajax
+      type: "POST"
+      event: event
+      url: "/api/v1/project/#{@project_name()}/tree/#{@settings_branch()}"
       success: (data) =>
         VM.visit_local_url data.build_url
     false # dont bubble the event up
+
+  save_and_create_settings_build: (data, event) =>
+    @save_specs data, event, @create_settings_build

   set_heroku_deploy_user: (data, event) =>
     $.ajax


Use my.extend

Use my.extend

--- src/game.coffee
+++ src/game.coffee
@@ -23,8 +23,8 @@
 merge = (stock, custom) ->
   addons = {}
   extensible.map (key) ->
-    addons[key] = $.extend {}, stock[key], custom[key]
-  $.extend {}, stock, custom, addons
+    addons[key] = my.extend {}, stock[key], custom[key]
+  my.extend {}, stock, custom, addons

 find_game = (name) -> game_cache[name] or load_game(name)


Better code

Better code

--- src/game.coffee
+++ src/game.coffee
@@ -132,14 +132,10 @@

   neighborCoord: (x, y) ->
     result = []
-    result.push([x - 1, y - 1]) if @isValidPosition(x - 1, y - 1)
-    result.push([x - 0, y - 1]) if @isValidPosition(x - 0, y - 1)
-    result.push([x + 1, y - 1]) if @isValidPosition(x + 1, y - 1)
-    result.push([x - 1, y - 0]) if @isValidPosition(x - 1, y - 0)
-    result.push([x + 1, y - 0]) if @isValidPosition(x + 1, y - 0)
-    result.push([x - 1, y + 1]) if @isValidPosition(x - 1, y + 1)
-    result.push([x - 0, y + 1]) if @isValidPosition(x - 0, y + 1)
-    result.push([x + 1, y + 1]) if @isValidPosition(x + 1, y + 1)
+    for dx in [-1..1]
+      for dy in [-1..1]
+        if not (dx is 0 and dy is 0)
+          result.push [x + dx, y + dy] if @isValidPosition x + dx, y + dy
     return result


Add option to ignore signature

Add option to ignore signature

--- lib/saml2.coffee
+++ lib/saml2.coffee
@@ -325,7 +325,7 @@
 # Takes a dom of a saml_response, a private key used to decrypt it and the certificate of the identity provider that
 # issued it and will return a user object containing the attributes or an error if keys are incorrect or the response
 # is invalid.
-parse_authn_response = (saml_response, sp_private_key, idp_certificates, allow_unencrypted, cb) ->
+parse_authn_response = (saml_response, sp_private_key, idp_certificates, allow_unencrypted, ignore_signature, cb) ->
   user = {}
   decrypted_assertion = null

@@ -341,7 +341,7 @@
     (result, cb_wf) ->
       debug result
       decrypted_assertion = (new xmldom.DOMParser()).parseFromString(result)
-      unless _.some(idp_certificates, (cert) -> check_saml_signature result, cert)
+      unless ignore_signature || _.some(idp_certificates, (cert) -> check_saml_signature result, cert)
         return cb_wf new Error("SAML Assertion signature check failed! (checked #{idp_certificates.length} certificate(s))")
       cb_wf null
     (cb_wf) -> async.lift(get_name_id) decrypted_assertion, cb_wf
@@ -457,7 +457,7 @@
               unless check_status_success(saml_response)
                 cb_wf new SAMLError("SAML Response was not success!", { status: get_status(saml_response) })
               response.type = 'authn_response'
-              parse_authn_response saml_response, @private_key, identity_provider.certificates, options.allow_unencrypted_assertion, cb_wf
+              parse_authn_response saml_response, @private_key, identity_provider.certificates, options.allow_unencrypted_assertion, options.ignore_signature, cb_wf
             when saml_response.getElementsByTagNameNS(XMLNS.SAMLP, 'LogoutResponse').length is 1
               unless check_status_success(saml_response)
                 cb_wf new SAMLError("SAML Response was not success!", { status: get_status(saml_response) })


Setting expiration header for static assets.

--- lib/setup.coffee
+++ lib/setup.coffee
@@ -49,10 +49,11 @@
     app.use require '../apps/about'

     # Mount static middleware for sub apps, components, and project-wide
+    maxAge = 1000 * 60 * 60 * 24 * 365 # 1 year
     fs.readdirSync(path.resolve __dirname, '../apps').forEach (fld) ->
-        app.use express.static(path.resolve __dirname, "../apps/#{fld}/public")
+        app.use express.static(path.resolve(__dirname, "../apps/#{fld}/public"), {maxAge})
     fs.readdirSync(path.resolve __dirname, '../components').forEach (fld) ->
-        app.use express.static(path.resolve __dirname, "../components/#{fld}/public")
-    app.use express.static(path.resolve __dirname, '../public')
+        app.use express.static(path.resolve(__dirname, "../components/#{fld}/public"), {maxAge})
+    app.use express.static(path.resolve(__dirname, '../public'), {maxAge})

     app.use require './error-handler'


add hullAsyncInit and hull.ships.ready event

--- src/hull.coffee
+++ src/hull.coffee
@@ -55,7 +55,11 @@
   logger.log("Hull.js version \"#{hull.version}\" started")

   # Do Hull.embed(platform.deployments) automatically
-  embeds.embed(app.deployments,{},onEmbedComplete, onEmbedError) if hull.config().embed!=false and _.isArray(app?.deployments) and app.deployments.length>0
+  if hull.config().embed != false
+    if _.isArray(app?.deployments) and app.deployments.length>0
+      embeds.embed(app.deployments,{},onEmbedComplete, onEmbedError)
+    else
+      onEmbedComplete()

   hash = decodeHash()
   snippet = hash?.hull?.snippet
@@ -89,6 +93,7 @@
 onInitFailure = (err)-> throw err

 onEmbedComplete = ()->
+  EventBus.emit('hull.ships.ready');
   logger.log("Hull Embeds Completed successfully")

 onEmbedError = (err...)->
@@ -221,6 +226,12 @@
       autoStartConfig && autoStartConfig.autoStart && init(autoStartConfig)

   window.Hull = hull
+  setTimeout ->
+    window.hullAsyncInit(hull) if window?.hullAsyncInit and _.isFunction(window.hullAsyncInit)
+  , 0
 else
   logger.error "Hull Snippet found more than once (or you already have a global variable named window.Hull). Either way, we can't launch Hull more than once. We only use the first one in the page"
+
 module.exports = hull
+
+


:fire: logs

:fire: logs

--- lib/table.coffee
+++ lib/table.coffee
@@ -66,8 +66,7 @@
     @cachedContents = @getCacheContent()

   getCacheContent: ->
-    console.log res = @columns.concat(@rows).join('\n')
-    res
+    res = @columns.concat(@rows).join('\n')

   #    ######## ##     ## ######## ##    ## ########  ######
   #    ##       ##     ## ##       ###   ##    ##    ##    ##


thing documentation

thing documentation

--- lib/thing.coffee
+++ lib/thing.coffee
@@ -1,13 +1,22 @@
 class Thing
   constructor: (@name, @attributes, existingGid) ->
+    # key / value pairs of attributes
     @attributes ||= {}
+
+    # global Thing id
     @gid = existingGid || gid += 1
     registry.register this

+    # object (k/v) of children {Thing}
     @children = {}
+
+    # parent container {Thing}
     @parent = null
+
+    # other Things listening to me
     @listeners = {}

+    # use the class name for the object name if non given
     @name = "#{this.constructor.name}" unless @name

   # subclass children to provide custom description formats
@@ -55,6 +64,8 @@

   # generic child search
   search: (selector, args) =>
+    assert selector?, "selector required"
+
     args ||= {}
     searchThing this, selector, args

@@ -89,16 +100,13 @@
     "#{this.name}[#{this.constructor.name}]#{this.gid}"

   listenTo: (thing) ->
-#    debug "#{this} starts listening to #{thing}"
     @listeners[thing.gid] = thing

   ignore: (thing) ->
-#    debug "#{this} stops listening to #{thing}"
     delete @listeners[thing.gid]

   broadcast: (evt) ->
     for gid, thing of @listeners
-#      debug "#{this} routes an event of type #{evt.type} to #{thing}"
       thing.hear evt

   # subclass to implement behaviour


cleanup

cleanup

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -267,7 +267,11 @@

   # Inject projectName from filePath
   for item in _items
-    item.projectName = path.basename(atom.project.relativizePath(item.filePath)[0])
+    projectPath = atom.project.relativizePath(item.filePath)[0]
+    if projectPath?
+      item.projectName = path.basename(projectPath)
+    else
+      item.projectName = "( No project )"

   for projectName, itemsInProject of _.groupBy(_items, (item) -> item.projectName)
     header = "# #{projectName}"


change default linux path

change default linux path

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -28,7 +28,7 @@
   getDefaultAppFolder: ->
     switch p = os.platform()
       when "darwin" then "/Applications"
-      when "linux"  then "/usr/local"
+      when "linux"  then "/usr/local/bin"
       # when "win32"   then "i/dont/know/yet"
       else
         throw new Error("Platform: '#{p}' is not supported.")


Removed done callback.

Removed done callback.

--- tests/youtube-info.coffee
+++ tests/youtube-info.coffee
@@ -10,5 +10,5 @@
     room = helper.createRoom()
     room.user.say 'alice', 'https://www.youtube.com/watch?v=ePoi0_zSnYk'

-    it 'should be able to find title', (done) ->
+    it 'should be able to find title', ->
         assert room.messages.length > 0


Fuck tests. Production is the new test.

Fuck tests. Production is the new test.

--- tests/youtube-info.coffee
+++ tests/youtube-info.coffee
@@ -1,63 +1,14 @@
+assert = require 'assert'
+
 Helper = require('hubot-test-helper')
-
 helper = new Helper('../scripts/youtube-info.coffee')
-expect = require('chai').expect

 describe 'when user links', ->
   room = null

   beforeEach ->
     room = helper.createRoom()
-
-  context 'youtube.com url', ->
+    room.user.say 'alice', 'https://www.youtube.com/watch?v=ePoi0_zSnYk'

     it 'should be able to find title', (done) ->
-
-      @timeout(0)
-
-      room.user.say 'alice', 'https://www.youtube.com/watch?v=ePoi0_zSnYk'
-      setTimeout =>
-        expect(room.messages[1][1]).to.contain "Adele's Hello by the Movies"
-        console.log room.messages
-        done()
-      , 10000
-
-  context 'youtube.com url with additional values', ->
-
-    it 'should be able to find title', (done) ->
-
-      @timeout(0)
-
-      room.user.say 'alice', 'https://www.youtube.com/watch?v=iq9DLJfpHd0&feature=youtu.be&ab_channel=CatRe-Tailer'
-      setTimeout =>
-        expect(room.messages[1][1]).to.contain "Shia Surprise"
-        console.log room.messages
-        done()
-      , 10000
-
-  context 'youtu.be url', ->
-
-    it 'should be able to find title', (done) ->
-
-      @timeout(0)
-
-      room.user.say 'alice', 'https://youtu.be/HP66dH1yEZo'
-      setTimeout =>
-        expect(room.messages[1][1]).to.contain "R2D2 learns a new trick"
-        console.log room.messages
-        done()
-      , 10000
-
-  context 'youtu.be url with additional values', ->
-
-    it 'should be able to find title', (done) ->
-
-      @timeout(0)
-
-      room.user.say 'alice', 'https://youtu.be/oVnAVcbMoSM?t=39s'
-      setTimeout =>
-        expect(room.messages[1][1]).to.contain "GoPro fall at Garden of the Gods"
-        console.log room.messages
-        done()
-      , 10000
-
+        assert room.messages.length > 0


fixed typo

fixed typo

--- spec/lib/cell-spec.coffee
+++ spec/lib/cell-spec.coffee
@@ -20,6 +20,6 @@

     When -> @res = @cell.right()
     Then -> expect(@res.x).toBe 5
-    And -> expect(@resy).toBe 4
+    And -> expect(@res.y).toBe 4


Remove deprecations

Remove deprecations

--- spec/snippets-spec.coffee
+++ spec/snippets-spec.coffee
@@ -5,9 +5,9 @@
 describe "Snippets extension", ->
   [editorElement, editor] = []

-  simulateTabKeyEvent = ({shiftKey}={}) ->
-    event = keydownEvent('tab', {shiftKey, target: editorElement})
-    atom.keymaps.handleKeyboardEvent(event.originalEvent)
+  simulateTabKeyEvent = ({shift}={}) ->
+    event = atom.keymaps.constructor.buildKeydownEvent('tab', {shift, target: editorElement})
+    atom.keymaps.handleKeyboardEvent(event)

   beforeEach ->
     spyOn(Snippets, 'loadAll')
@@ -157,14 +157,14 @@
           expect(editor.getSelectedBufferRange()).toEqual [[2, 40], [2, 40]]

           # tab backwards
-          simulateTabKeyEvent(shiftKey: true)
+          simulateTabKeyEvent(shift: true)
           expect(editor.getSelectedBufferRange()).toEqual [[2, 14], [2, 17]] # should highlight text typed at tab stop

-          simulateTabKeyEvent(shiftKey: true)
+          simulateTabKeyEvent(shift: true)
           expect(editor.getSelectedBufferRange()).toEqual [[3, 15], [3, 15]]

           # shift-tab on first tab-stop does nothing
-          simulateTabKeyEvent(shiftKey: true)
+          simulateTabKeyEvent(shift: true)
           expect(editor.getCursorScreenPosition()).toEqual [3, 15]

           # tab through all tab stops, then tab on last stop to terminate snippet
@@ -213,7 +213,7 @@
             simulateTabKeyEvent()

             editor.moveRight()
-            simulateTabKeyEvent(shiftKey: true)
+            simulateTabKeyEvent(shift: true)
             expect(editor.getCursorBufferPosition()).toEqual [4, 15]

         describe "when the cursor is moved within the bounds of the current tab stop", ->
@@ -520,7 +520,7 @@
         atom.workspace.getActiveTextEditor()?

       runs ->
-        expect(atom.workspace.getActiveTextEditor().getUri()).toBe path.join(configDirPath, 'snippets.cson')
+        expect(atom.workspace.getActiveTextEditor().getURI()).toBe path.join(configDirPath, 'snippets.cson')

   describe "snippet insertion API", ->
     it "will automatically parse snippet definition and replace selection", ->


Add a retry to analytics requests

Add a retry to analytics requests

--- services/web/app/coffee/Features/Analytics/AnalyticsManager.coffee
+++ services/web/app/coffee/Features/Analytics/AnalyticsManager.coffee
@@ -6,10 +6,24 @@

 makeRequest = (opts, callback)->
+	retryTimings = [1, 2, 4, 8, 16, 32, 32, 32]
 	if settings.apis?.analytics?.url?
 		urlPath = opts.url
 		opts.url = "#{settings.apis.analytics.url}#{urlPath}"
-		request opts, callback
+		iteration = 0
+		_go = () ->
+			request opts, (err, response, data) ->
+				if err?
+					if iteration == retryTimings.length
+						logger.err {err, url: opts.url},
+							"Error in analytics request, retries failed"
+						return callback(err)
+					backoffSeconds = retryTimings[iteration]
+					iteration += 1
+					setTimeout(_go, backoffSeconds * 1000)
+				else
+					callback(null, response, data)
+		_go()
 	else
 		callback(new Errors.ServiceNotConfiguredError('Analytics service not configured'))


pull out ref book fix from dd7c0ab

pull out ref book fix from dd7c0ab

--- src/components/reference-book/exercise.cjsx
+++ src/components/reference-book/exercise.cjsx
@@ -21,7 +21,7 @@
     {exerciseAPIUrl} = @props
     {items} = ReferenceBookExerciseStore.get(exerciseAPIUrl)

-    unless items?.length
+    unless items?.length and items?[0]?.questions?[0]?
       # warning about missing exercise --
       # is there a need to show the reader anything?
       console.warn("WARNING: #{exerciseAPIUrl} appears to be missing.")


removed a console.log

removed a console.log

--- lib/block-cursor.coffee
+++ lib/block-cursor.coffee
@@ -60,7 +60,6 @@
     atom.themes.requireStylesheet @mainLessFile

   applyPulse: (enabled) ->
-    console.log enabled
     workspaceView = atom.views.getView atom.workspace
     if enabled
       workspaceView.classList.add 'block-cursor-pulse'


specify cwd

specify cwd

--- lib/clang-format.coffee
+++ lib/clang-format.coffee
@@ -1,5 +1,6 @@
 {CompositeDisposable} = require 'atom'
 {execSync} = require 'child_process'
+path = require 'path'

 module.exports =
 class ClangFormat
@@ -56,6 +57,9 @@
     # windows and node.js will try to write to it - whether it's there or not
     args = ("-#{k}=\"#{v}\"" for k, v of options).join ' '
     options = input: editor.getText(), stdio: ['pipe', 'pipe', 'ignore']
+
+    if file_path = editor.getPath()
+      options['cwd'] = path.dirname(file_path)

     try
       stdout = execSync("#{exe} #{args}", options).toString()


feat(subscription): manage subscription link in group settings tab

--- vue/src/shared/services/group_service.coffee
+++ vue/src/shared/services/group_service.coffee
@@ -5,10 +5,23 @@
 import AbilityService from '@/shared/services/ability_service'
 import LmoUrlService  from '@/shared/services/lmo_url_service'
 import openModal      from '@/shared/helpers/open_modal'
+import AppConfig      from '@/shared/services/app_config'

 export default new class GroupService
   actions: (group, vm) ->
     membership = group.membershipFor(Session.user())
+
+    change_volume:
+      name: 'group_page.options.email_settings'
+      icon: 'mdi-email'
+      canPerform: ->
+        AbilityService.canChangeGroupVolume(group)
+        perform: ->
+          openModal
+          component: 'ChangeVolumeForm'
+          props:
+            model: membership
+
     edit_group:
       name: 'group_page.options.edit_group'
       icon: 'mdi-settings'
@@ -19,6 +32,16 @@
           component: 'GroupForm'
           props:
             group: group.clone()
+
+    manage_subscription:
+      name: 'group_page.options.manage_subscription'
+      icon: 'mdi-rocket'
+      canPerform: ->
+        console.log 'Session.user().isAdminOf(group.parent())', Session.user().isAdminOf(group.parent())
+        console.log 'group.subscriptionPlan', group.subscriptionPlan
+        group.isParent() && Session.user().isAdminOf(group) && group.subscriptionPlan?
+      perform: ->
+        window.location = AppConfig.baseUrl + "upgrade"

     become_coordinator:
       name: 'group_page.options.become_coordinator'
@@ -31,16 +54,6 @@
         Records.memberships.makeAdmin(membership).then ->
           Flash.success "memberships_page.messages.make_admin_success", name: Session.user().name

-    change_volume:
-      name: 'group_page.options.email_settings'
-      icon: 'mdi-email'
-      canPerform: ->
-        AbilityService.canChangeGroupVolume(group)
-      perform: ->
-        openModal
-          component: 'ChangeVolumeForm'
-          props:
-            model: membership

     export_data:
       name: 'group_page.options.export_data'


Workspace: Write history events to history node.

--- client/landing/CollaborativeWorkspace/collaborativeworkspace.coffee
+++ client/landing/CollaborativeWorkspace/collaborativeworkspace.coffee
@@ -267,6 +267,7 @@
     data         = message: data  if typeof data is "string"
     data.message = data.message.replace "$0", KD.nick()

+    target.set data
     @emit "NewHistoryItemAdded", data

   broadcastMessage: (details) ->


Ups. Missing default value for routing.

Ups. Missing default value for routing.

--- client/base.coffee
+++ client/base.coffee
@@ -1,7 +1,7 @@
 @INITIAL_SEARCH_LIMIT = INITIAL_SEARCH_LIMIT = 5

 setSession = (session) ->
-  session = _.defaults session,
+  session = _.defaults session or {},
     indexActive: false
     currentSearchQuery: null
     currentSearchQueryCountPublications: 0


Try to fix problem with CORS and header X-Rocket-Chat-Version

--- packages/rocketchat-cors/cors.coffee
+++ packages/rocketchat-cors/cors.coffee
@@ -3,10 +3,12 @@
 WebApp.rawConnectHandlers.use (req, res, next) ->
 	res.setHeader("Access-Control-Allow-Origin", "*")
 	res.setHeader("X-Rocket-Chat-Version", VERSION)
+	res.setHeader("Access-Control-Expose-Headers",  "X-Rocket-Chat-Version");
 	return next()

 _staticFilesMiddleware = WebAppInternals.staticFilesMiddleware
 WebAppInternals._staticFilesMiddleware = (staticFiles, req, res, next) ->
 	res.setHeader("Access-Control-Allow-Origin", "*")
 	res.setHeader("X-Rocket-Chat-Version", VERSION)
+	res.setHeader("Access-Control-Expose-Headers",  "X-Rocket-Chat-Version");
 	_staticFilesMiddleware(staticFiles, req, res, next)


Fixed wrong username/password in basic authentication

--- auth.coffee
+++ auth.coffee
@@ -14,7 +14,7 @@

 exports.basic = (username, password) ->
-  "Basic #{new Buffer('Aladdin:open sesame').toString('base64')}"
+  "Basic #{new Buffer("#{username}:#{password}").toString('base64')}"

 exports.digest = (username, password, uri, httpMethod, body, authHeader) ->


Don't use class names directly.

Don't use class names directly.

They get minimized in production and things don't work anymore. This is
why we have Meta._name for example. In this case it is even better to
use directly a collection name.

--- client/lib/catalog.coffee
+++ client/lib/catalog.coffee
@@ -62,7 +62,7 @@
   @_searchResultHandle?.stop()
   @_searchResultHandle = Deps.autorun =>
     fields = {}
-    fields["count#{@data.documentClass.name}s"] = 1
+    fields["count#{ @data.documentClass.Meta.collection._name }"] = 1

     searchResultCursor = SearchResult.documents.find
       name: @data.subscription
@@ -73,9 +73,9 @@
     # Store how many results there are
     searchResultCursor.observe
       added: (document) =>
-        Session.set variables.count, document["count#{@data.documentClass.name}s"]
+        Session.set variables.count, document["count#{ @data.documentClass.Meta.collection._name }"]
       changed: (newDocument, oldDocument) =>
-        Session.set variables.count, newDocument["count#{@data.documentClass.name}s"]
+        Session.set variables.count, newDocument["count#{ @data.documentClass.Meta.collection._name }"]

 Template.catalog.destroyed = ->
   @_resetSignalHandle?.stop()


Wait for RM before starting NM

Wait for RM before starting NM

--- actions/hdp_yarn_nm.coffee
+++ actions/hdp_yarn_nm.coffee
@@ -2,14 +2,19 @@
 lifecycle = require './hdp/lifecycle'
 module.exports = []

+module.exports.push 'histi/actions/nc'
 module.exports.push 'histi/actions/hdp_yarn'

 module.exports.push (ctx) ->
+  require('./nc').configure ctx
   require('./hdp_yarn').configure ctx

 module.exports.push name: 'HDP YARN NM # Start', callback: (ctx, next) ->
-  lifecycle.nm_start ctx, (err, started) ->
-    next err, if started then ctx.OK else ctx.PASS
+  resourcemanager = ctx.hosts_with_module 'histi/actions/hdp_yarn_rm', 1
+  ctx.waitForConnection resourcemanager, 8088, (err) ->
+    return next err if err
+    lifecycle.nm_start ctx, (err, started) ->
+      next err, if started then ctx.OK else ctx.PASS

 module.exports.push name: 'HDP YARN NM # Test User', callback: (ctx, next) ->
   {test_user, hadoop_group} = ctx.config.hdp


Highlight correct piece on hover

Highlight correct piece on hover

--- src/main.coffee
+++ src/main.coffee
@@ -14,18 +14,54 @@
 		@size = new P.Size P.view.size.width, .7 * P.view.size.height

 	rectangle = new P.Rectangle 0, 0, P.view.size.width / 4, .7 * P.view.size.height / 4
-	pieceEdge = new P.Shape.Rectangle rectangle
+
+	###
+	Two pieces
+	###

-	pieceBackground = new P.Raster
-		source: '//hufkens.net/wp-content/uploads/2012/10/bumba-win8.png'
-		position: new P.Point P.view.center.x, .7 * P.view.center.y
+	pieces = []

-	pieceBackground.onLoad = () ->
-		@size = new P.Size P.view.size.width, .7 * P.view.size.height
+	for i in [0..1]
+		pieceEdge = new P.Shape.Rectangle rectangle
+		pieceEdge.set
+			strokeColor: 'black'
+			strokeWidth: 0
+			selected: true

-	pieceGroup = new P.Group pieceEdge, pieceBackground
-	pieceGroup.clipped = true
+		pieceBackground = new P.Raster
+			source: '//hufkens.net/wp-content/uploads/2012/10/bumba-win8.png'
+			position: new P.Point P.view.center.x, .7 * P.view.center.y

-	P.view.draw()
+		pieceBackground.onLoad = () ->
+			@size = new P.Size P.view.size.width, .7 * P.view.size.height
+
+		pieceGroup = new P.Group pieceEdge, pieceBackground, pieceEdge.clone()
+		pieceGroup.clipped = true
+		pieceGroup.position.x = i * rectangle.width / 2 + rectangle.width / 2
+		pieceGroup.strokeColor = 'black'
+
+		pieces.push
+			edge: pieceEdge
+			group: pieceGroup
+
+	tool = new P.Tool()
+	tool.onMouseMove = (event) ->
+		piece.group.strokeWidth = 0 for piece in pieces
+
+		possiblePieces = []
+
+		for piece in pieces
+			if piece.edge.contains event.point
+				possiblePieces.push piece
+
+		return unless possiblePieces.length
+
+		actualPiece = possiblePieces[0]
+
+		for i in [1...possiblePieces.length]
+			if possiblePieces[i].group.isAbove actualPiece.group
+				actualPiece = possiblePieces[i]
+
+		actualPiece.group.strokeWidth = 10

 )(paper)


Make atom work when there is no enough command line parameters.

--- src/main.coffee
+++ src/main.coffee
@@ -33,8 +33,8 @@

 parseCommandLine = ->
   args = optimist(process.argv[1..]).argv
-  executedFrom = args['executed-from']
   devMode = args['dev']
+  executedFrom = args['executed-from'] ? process.cwd()
   pathsToOpen = args._

   if args['resource-path']
@@ -147,7 +147,7 @@
   sendCommand: (command) ->
     atomWindow.sendCommand command for atomWindow in @windows when atomWindow.browserWindow.isFocused()

-  open: (pathToOpen) ->
+  open: (pathToOpen = '') ->
     pathToOpen = path.resolve(executedFrom, pathToOpen) if executedFrom

     atomWindow = new AtomWindow


refactor `data` -> `d`; always use `on_end` handler in `$()`


Reward system behavior improved (and some related bugs fixed).

--- src/main.coffee
+++ src/main.coffee
@@ -148,6 +148,15 @@
     componentDidUpdate: ->
         current_dialog = @state.dialog

+    componentWillReceiveProps: (next_props)->
+        log_reward = log.get_reward()
+        if @state.dialog == 2
+            if not log_reward
+                @setState {dialog:0}
+        else
+            selected_reward = log_reward
+
+
     componentWillMount: ->
         current_dialog = @state.dialog

@@ -186,7 +195,8 @@
         dialog: 0
         auto_highlight: true
     render: ->
-        selected_reward = Math.min selected_reward, log.get_reward()
+        log_reward = log.get_reward()
+        selected_reward = Math.max settings.reward_pack, Math.min(selected_reward, log_reward)
         auto_highlight = @state.auto_highlight and (auto_hide_time != Infinity)
         if not @state.writing_working_on
             working_on_value = log.last_task
@@ -255,12 +265,13 @@
                             log.new_entry {active: false, date: show_window_time}
                             hide_window()

-                    if log.get_reward()
+                    if log_reward
                         components.button
                             label: 'rest'
                             useHighlight: true
-                            title:"Available time:\n#{format_time log.get_reward()}"
+                            title:"Available time:\n#{format_time log_reward}"
                             onClick: =>
+                                selected_reward = Math.max settings.reward_pack, Math.min selected_reward, log_reward
                                 @setState dialog: 2

             ]
@@ -324,12 +335,10 @@
                     want to rest?
                     "
                 components.slider
-                    min: settings.reward_pack
-                    max: Math.max log.get_reward(), settings.reward_pack
-                    step: Math.min settings.reward_pack, log.get_reward()/4
+                    min: Math.min 1000, settings.reward_pack/5
+                    max: Math.max log_reward, settings.reward_pack
+                    step: Math.min 1000, settings.reward_pack/5
                     allowManualEdit: false
-                    disabled: log.get_reward() <= settings.reward_pack
-                    hideValue: false
                     formatValue: (v)->
                         format_time v
                     read: -> selected_reward


Load https Api

Load https Api

--- app/main.coffee
+++ app/main.coffee
@@ -36,7 +36,7 @@

 Api = require 'zooniverse/lib/api'
 api = if window.location.hostname is 'www.milkywayproject.org'
-  new Api project: 'milky_way', host: 'http://www.milkywayproject.org', path: '/_ouroboros_api/proxy'
+  new Api project: 'milky_way', host: 'https://www.milkywayproject.org', path: '/_ouroboros_api/proxy'
 else
   new Api project: 'milky_way'


adjust debugging

adjust debugging

--- integration/authn_test.coffee
+++ integration/authn_test.coffee
@@ -19,7 +19,7 @@
       it 'is denied', (done)->
         conjur_authn.connect('https://authn-ci-conjur.herokuapp.com').authenticate admin.login, 'foobar', (result, token)->
           winston.debug(g.inspect(result))
-          winston.debug(token)
+          winston.debug(g.inspect(token))
           assert.equal result, "POST https://authn-ci-conjur.herokuapp.com/users/#{admin.login}/authenticate failed : 401"
           assert !token
           done()


Displays deeply nested comments inline.

Displays deeply nested comments inline.

This just puts them in three traversal order rather than chronological order.
Not sure which makes the most sense, but I'll implement both ways.

--- lms/static/coffee/src/discussion/views/thread_response_view.coffee
+++ lms/static/coffee/src/discussion/views/thread_response_view.coffee
@@ -34,6 +34,9 @@
       view = new ResponseCommentView(model: comment)
       view.render()
       @$el.find(".comments li:last").before(view.el)
+      children = new Comments(comment.get('children'))
+      children.each @renderComment
+

     toggleVote: (event) ->
       event.preventDefault()


Add delay to connect retry

Add delay to connect retry

--- priv/coffeescript/app.coffee
+++ priv/coffeescript/app.coffee
@@ -30,6 +30,7 @@

     connect: () ->
       try
+
         @ws = new WebSocket('ws://' + @endPoint + '/chat')
         @ws.onopen = () =>
           console.log "Connected to #{@endPoint}"
@@ -44,7 +45,9 @@
             if @blacklist.length == endPoints.length
               @blacklist = []
             @endPoint = chooseRandomEndpoint @blacklist
-            @connect()
+            setTimeout () =>
+              @connect()
+            , 500

           @status = @ws.readyState


Default iron-router layout template fix

Default iron-router layout template fix

--- paginate.coffee
+++ paginate.coffee
@@ -68,15 +68,16 @@
   setRouter: ->
     if @router is "iron-router"
       pr = "#{@route}:n"
+      t = @routerTemplate
       Router.map ->
         @route "home",
             path: "/"
-            template: @routerTemplate
+            template: t
             onBeforeRun: ->
                 Session.set "paginate.currentPage", 1
         @route "page",
             path: pr
-            template: @routerTemplate
+            template: t
             onBeforeRun: ->
                 Session.set "paginate.currentPage", parseInt(@params.n)
   countPages: ->


Update atom config format

Update atom config format

--- atom.cson
+++ atom.cson
@@ -1,44 +1,45 @@
-'*':
-  'editor':
-    'fontFamily': 'Fira Mono OT'
-    'showIndentGuide': true
-    'tabLength': 2
-    'softWrap': true
-    'invisibles': {}
-    'zoomFontWhenCtrlScrolling': false
-  'core':
-    'disabledPackages': [
-      'language-objective-c'
-      'archive-view'
-      'autosave'
-      'bookmarks'
-      'language-clojure'
-      'language-perl'
-      'language-php'
-      'language-toml'
-      'snippets'
-      'welcome'
-      'spell-check'
+"*":
+  editor:
+    fontFamily: "Fira Mono OT"
+    showIndentGuide: true
+    tabLength: 2
+    softWrap: true
+    invisibles: {}
+    zoomFontWhenCtrlScrolling: false
+  core:
+    disabledPackages: [
+      "language-objective-c"
+      "archive-view"
+      "autosave"
+      "bookmarks"
+      "language-clojure"
+      "language-perl"
+      "language-php"
+      "language-toml"
+      "snippets"
+      "welcome"
+      "spell-check"
+      "deprecation-cop"
     ]
-    'themes': [
-      'seti-ui'
-      'seti-syntax'
+    themes: [
+      "seti-ui"
+      "seti-syntax"
     ]
-    'projectHome': '/home/ai/Dev'
-    'autoHideMenuBar': true
-  'exception-reporting':
-    'userId': '51ccaaae-04bc-1ed3-3445-f9bd1a2f3a71'
-  'welcome':
-    'showOnStartup': false
-  'markdown-preview':
-    'breakOnSingleNewline': true
-  'spell-check': {}
-'.js.source':
-  'editor':
-    'tabLength': 4
-'.css.source':
-  'editor':
-    'tabLength': 4
-'.html.source':
-  'editor':
-    'tabLength': 4
+    projectHome: "/home/ai/Dev"
+    autoHideMenuBar: true
+  "exception-reporting":
+    userId: "51ccaaae-04bc-1ed3-3445-f9bd1a2f3a71"
+  welcome:
+    showOnStartup: false
+  "markdown-preview":
+    breakOnSingleNewline: true
+  "spell-check": {}
+".html.source":
+  editor:
+    tabLength: 4
+".css.source":
+  editor:
+    tabLength: 4
+".js.source":
+  editor:
+    tabLength: 4


Improved UX for destroy confirm dialog.

Improved UX for destroy confirm dialog.

--- app/assets/javascripts/app/controllers/_application_controller_generic.coffee
+++ app/assets/javascripts/app/controllers/_application_controller_generic.coffee
@@ -279,7 +279,7 @@
 class App.ControllerGenericDestroyConfirm extends App.ControllerModal
   buttonClose: true
   buttonCancel: true
-  buttonSubmit: 'yes'
+  buttonSubmit: 'delete'
   buttonClass: 'btn--danger'
   head: 'Confirm'
   small: true


Correct types.

Correct types.

--- lib/linter-clang.coffee
+++ lib/linter-clang.coffee
@@ -85,14 +85,14 @@
             if regex
               if regex.error
                 ToReturn.push(
-                  type: 'Error',
+                  type: 'error',
                   message: regex.message,
                   file: filePath
                   position: [[regex.line, regex.column], [regex.line, regex.column]]
                 )
               if regex.warning
                 ToReturn.push(
-                  type: 'Warning',
+                  type: 'warning',
                   message: regex.message,
                   file: filePath
                   position: [[regex.line, regex.col], [regex.line, regex.col]]


Beautify rustc message

Beautify rustc message

--- lib/linter/rustc.coffee
+++ lib/linter/rustc.coffee
@@ -1,6 +1,7 @@
 {Range, Point} = require 'atom'
 CommandRunner = require '../command-runner'
 Violation = require '../violation'
+util = require '../util'

 DIAGNOSTIC_PATTERN = ///
 ^(.+):(\d+):(\d+):\s*(\d+):(\d+) # file / line1 / column1 / line2 / column2
@@ -44,6 +45,9 @@
       startPoint = new Point(parseInt(lineNumber - 1), parseInt(columnNumber - 1))
       endPoint = new Point(parseInt(lineNumber2 - 1), parseInt(columnNumber2 - 1))
       bufferRange = new Range(startPoint, endPoint)
+
+      message = util.punctuate(util.capitalize(message))
+
       new Violation(severity, bufferRange, message)

   buildCommand: ->


デバッグモードを変更

デバッグモードを変更

--- lib/main.enchant.coffee
+++ lib/main.enchant.coffee
@@ -324,10 +324,11 @@
     rootScene.backgroundColor = BGCOLOR
     WEBGL = false

-  if (DEBUG == true)
-    core.debug()
-  else
-    core.start()
+  #if (DEBUG == true)
+  #  core.debug()
+  #else
+  #  core.start()
+  core.start()

 #******************************************************************************
 # 起動時の処理


:fire: Remove unneeded scaling with retina display

--- lib/minimap-view.coffee
+++ lib/minimap-view.coffee
@@ -333,12 +333,7 @@
     @transform @miniVisibleArea[0], @translate(0, @indicator.y)
     @renderView.scrollTop(@indicator.scroller.y * -1)

-    if devicePixelRatio isnt 1
-      scale = @scale(1 / devicePixelRatio)
-    else
-      scale = ''
-
-    @transform @renderView[0], @translate(0, @indicator.scroller.y + @getFirstVisibleScreenRow() * @getLineHeight()) + scale
+    @transform @renderView[0], @translate(0, @indicator.scroller.y + @getFirstVisibleScreenRow() * @getLineHeight())

     @transform @miniUnderlayer[0], @translate(0, @indicator.scroller.y)
     @transform @miniOverlayer[0], @translate(0, @indicator.scroller.y)


Price import indentation fix.

Price import indentation fix.

--- lib/price-import.coffee
+++ lib/price-import.coffee
@@ -101,6 +101,6 @@
       if matchingSkus.length > 0
         true
       else
-       false
+        false

 module.exports = PriceImport


Add selection functionality on results

Add selection functionality on results

--- lib/python-tools.coffee
+++ lib/python-tools.coffee
@@ -1,5 +1,5 @@
 PythonToolsView = require './python-tools-view'
-{CompositeDisposable} = require 'atom'
+{Range, Point, CompositeDisposable} = require 'atom'
 path = require 'path'

 module.exports = PythonTools =
@@ -73,6 +73,18 @@
     console.log "Got some data back from tools.py"
     console.log "#{response}"

+    response = JSON.parse(response)
+
+    editor = atom.workspace.getActiveTextEditor()
+    selections = []
+    for item in response
+      selections.push new Range(
+        new Point(item['line'] - 1, item['column']),
+        new Point(item['line'] - 1, item['column'] + item['name'].length),  # Use string length
+      )
+
+    editor.setSelectedBufferRanges(selections)
+
   showUsages: ->
     console.log 'Running show usages'
     editor = atom.workspace.getActiveTextEditor()


Update to new moment version.

Update to new moment version.

--- src/p13n.coffee
+++ src/p13n.coffee
@@ -88,7 +88,7 @@
                 resGetPath: app_settings.static_path + 'locales/__lng__.json'
                 fallbackLng: FALLBACK_LANGUAGES

-            moment.lang make_moment_lang(@get_language())
+            moment.locale make_moment_lang(@get_language())

             # debugging: make i18n available from JS console
             window.i18n_debug = i18n


minor refactoring

minor refactoring

--- app/assets/javascripts/annotation_document_manager.coffee
+++ app/assets/javascripts/annotation_document_manager.coffee
@@ -2,7 +2,7 @@

   _this = undefined

-  constructor: (dalphiBaseUrl, projectId, synchronousAjax = false) ->
+  constructor: (dalphiBaseUrl, projectId, synchronousRequest = false) ->
     _this = this
     this.dalphiBaseUrl = dalphiBaseUrl
     this.projectId = projectId
@@ -10,7 +10,7 @@
     this.currentDocument = undefined
     this.maxAnnotationDocumentsToLoad = 1
     this.apiVersion = 'v1'
-    this.asynchronousAjax = !synchronousAjax
+    this.asynchronousRequest = !synchronousRequest

     this.initAjax()
     this.loadAnnotationDocuments()
@@ -72,7 +72,7 @@
       url: requestOptions.url,
       dataType: 'json',
       data: requestOptions.data,
-      async: _this.asynchronousAjax,
+      async: _this.asynchronousRequest,
       success: (data) ->
         responseProcessor(data) if responseProcessor
         postUpdateCallback _this.next() if postUpdateCallback


Fixes bad encoding in Flash notifications

--- app/assets/javascripts/georgia/components/flash.js.coffee
+++ app/assets/javascripts/georgia/components/flash.js.coffee
@@ -5,7 +5,7 @@

     $('<div/>',
       class: "flash-#{type}",
-      text: message
+      html: message
     ).appendTo(".flash-container")

     flash.click -> $(@).fadeOut()


confirmation validation que não estava funcional no teste de ultimo segundo, voltou a ficar

--- app/assets/javascripts/jqvr/built_in_validators.js.coffee
+++ app/assets/javascripts/jqvr/built_in_validators.js.coffee
@@ -30,7 +30,8 @@
     validClass=jQuery(parentForm).validate().settings.validClass

     if isOnkeyup
-      if jQuery(fieldToConfirm).hasClass('was_invalid') or jQuery(fieldToConfirm).hasClass(errorClass) or jQuery(fieldToConfirm).hasClass(validClass)
+      # if jQuery(fieldToConfirm).hasClass('was_invalid') or jQuery(fieldToConfirm).hasClass(errorClass) or jQuery(fieldToConfirm).hasClass(validClass)
+      if jQuery(fieldToConfirm).hasClass(errorClass)
         jQuery(fieldToConfirm).valid()
   )


Updated class on the load more button|

Updated class on the load more button|

--- app/assets/javascripts/lib/components/load_more.js.coffee
+++ app/assets/javascripts/lib/components/load_more.js.coffee
@@ -28,7 +28,7 @@

     appendButton: ->
       @container = $('<footer/>').css('text-align', 'center')
-      @btn = $('<a/>').attr('id', 'js-load-more').addClass('load-more-btn').text(@config.btnLabel)
+      @btn = $('<a/>').attr('id', 'js-load-more').addClass('btn--load-more').text(@config.btnLabel)
       @container.append(@btn)
       $(@config.pagination).after(@container)

@@ -80,7 +80,7 @@

     removeErrorMsg: ->
-      @container.prev('.system-error').remove()
+      @container.prev('.js-error').remove()
       @config.hasError = false


#196 minor changes and cleanup

#196 minor changes and cleanup

--- app/assets/javascripts/search/cells/search_results.coffee
+++ app/assets/javascripts/search/cells/search_results.coffee
@@ -45,7 +45,7 @@
       personal_focus_with_remote: false
       main_results_headline: @mainResultsHeadline('remote_offers')
       remote_focus: true
-      toggle_personal_anchor: "(Zeige lokale Angebote)" # TODO: permanent? +css
+      toggle_personal_anchor: "Zeige lokale Angebote" # TODO: permanent? +css

   ## Headline Building Helpers
@@ -61,7 +61,7 @@
       output += " #{bridge}: „#{@model.query}“ "
       output += HandlebarsTemplates['remove_query_link']()

-    output + " (#{@model.search_location}) #{enclosing}."
+    output + " (#{@model.search_location}) #{enclosing}"

   # breadcrumps to active category
   breadcrumbPath: (@model) ->


no used

no used

--- app/assets/javascripts/uploadcare/widget/dialog.js.coffee
+++ app/assets/javascripts/uploadcare/widget/dialog.js.coffee
@@ -11,7 +11,6 @@
   utils,
   locale: {t},
   templates: {tpl},
-  ui: {progress: {Circle}},
   files,
   widget: {tabs},
   settings: s,


Add history command

Add history command

--- src/adapters/shell.coffee
+++ src/adapters/shell.coffee
@@ -38,10 +38,16 @@
           process.exit 0

         @repl.on 'line', (buffer) =>
-          @repl.close() if buffer.toLowerCase() is 'exit'
+
+          switch buffer.toLowerCase()
+            when "exit"
+              @repl.close()
+            when "history"
+              stdout.write "#{line}\n" for line in @repl.history
+            else
+              user = @robot.brain.userForId '1', name: 'Shell', room: 'Shell'
+              @receive new TextMessage user, buffer, 'messageId'
           @repl.prompt()
-          user = @robot.brain.userForId '1', name: 'Shell', room: 'Shell'
-          @receive new TextMessage user, buffer, 'messageId'

         @emit 'connected'


[Metrics] Track where does someone trying to hire us come from

--- app/assets/javascripts/blog.coffee
+++ app/assets/javascripts/blog.coffee
@@ -1,2 +1,8 @@
 $('#js-menu-toggle').on 'click', ->
   $('#nav').slideToggle()
+
+
+$(document).on 'click', '.hire-us a', ->
+  if(ga)
+    label = $(this).parent().siblings('.post-icon').find('a').attr('href')
+    ga('send', 'event', 'hireUs', 'click', label)


Add copiright and license terms

Add copiright and license terms

--- app/coffee/modules/projects.coffee
+++ app/coffee/modules/projects.coffee
@@ -1 +1,22 @@
+###
+# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
+# Copyright (C) 2014 Jesús Espino Garcia <jespinog@gmail.com>
+# Copyright (C) 2014 David Barragán Merino <bameda@dbarragan.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# File: modules/projects.coffee
+###
+
 module = angular.module("taigaProject", [])


Change assessment to evaluation in controller.

--- app/javascripts/controllers.coffee
+++ app/javascripts/controllers.coffee
@@ -340,10 +340,12 @@
     ]

+    # TODO: 'assessment' is now 'evaluation' in data model, so should
+    #   controller name change as well?
     ctlrs.controller 'AssessmentCtrl', [
       '$scope',
       ($scope) ->
-        $scope.assessment = $scope.encounter.assessment
+        $scope.evaluation = $scope.encounter.evaluation
     ]


use new mkEl

use new mkEl

--- app/js/loader/loader_common.coffee
+++ app/js/loader/loader_common.coffee
@@ -11,11 +11,11 @@
   window.FACTLINK_LOADED = true

   # Add styles
-  style_tag = (mkEl 'style') null, document.createTextNode(style_code)
+  style_tag = mkEl 'style', null, document.createTextNode(style_code)
   document.getElementsByTagName('head')[0].appendChild style_tag

   #### Create iframe so jslib's namespace (window) doesn't collide with any content window.
-  jslib_jail_iframe = (mkEl 'iframe') 'factlink-iframe'
+  jslib_jail_iframe = mkEl 'iframe', 'factlink-iframe'
   jslib_jail_iframe.style.display = 'block'
   jslib_jail_iframe.style.border = '0px solid transparent'


[skip] Removed dependency on the client to implement `serializeObject`; Changed from serializing the nearest form to serializing attributes in the models's view (20m)

--- vendor/assets/javascripts/neat/model_editor.coffee
+++ vendor/assets/javascripts/neat/model_editor.coffee
@@ -64,8 +64,7 @@

   save: (e)->
     e?.preventDefault()
-    $form = $(@el).closest('form')
-    newAttributes = @attributesFromForm($form)
+    newAttributes = @attributesFromForm(@$el)
     @debug 'saving: ', newAttributes
     attributes =  @model.changedAttributes(newAttributes)

@@ -87,8 +86,27 @@
   okToSave: (attributes)->
     true

-  attributesFromForm: ($form)->
-    $form.serializeObject()
+  attributesFromForm: ($el)->
+    attrs = {}
+    $el.find('input, select, textarea').each ->
+      elem = $(this)
+      name = elem.attr('name')
+      if name
+        elemType = elem.attr('type')
+        value = elem.val()
+
+        if name.substr(-2) == '[]'
+          name = name.substring(0, name.length - 2)
+          attrs[name] = attrs[name] || []
+          attrs[name].push elem.val()
+
+        else if elemType == 'checkbox' || elemType == 'radio'
+          attrs[name] = '' if typeof(attrs[name]) == 'undefined'
+          attrs[name] = value if elem.prop('checked')
+
+        else
+          attrs[name] = value
+    attrs

   delete: (e)->
     e?.preventDefault()


Applied @janpaul123's fix for createEventHandler

--- js-library/src/js/models/fact.coffee
+++ js-library/src/js/models/fact.coffee
@@ -35,20 +35,14 @@
   createEventHandlers: (events) ->
     @createEventHandler event_handle for event_handle in events

-  createEventHandler: (event_handle) =>
+  createEventHandler: (event_handle) ->
     @_bound_events[event_handle] = []

-    @[event_handle] = (() =>
-      e = event_handle
-
-      (supplied_args...) =>
-        args = [e].concat supplied_args
-
-        if $.isFunction args[1]
-          @bind.apply this, args
-        else
-          @trigger.apply this, args
-    )()
+    @[event_handle] = (event, args...) =>
+      if $.isFunction event
+        @bind event_handle, event
+      else
+        @trigger event_handle, event, args...

   bind: (type, fn) ->
     @_bound_events[type].push fn


The reference book shell now handles all

--- src/router.cjsx
+++ src/router.cjsx
@@ -87,7 +87,7 @@
       <Router.DefaultRoute name="viewReferenceBookFirstPage" handler={ReferenceBookPageShell}/>

       <Route path='section/:section'
-        name='viewReferenceBookSection' handler={ReferenceBookPageShell} />
+        name='viewReferenceBookSection' handler={ReferenceBookShell} />

       <Route path='page/:cnxId' name='viewReferenceBookPage' handler={ReferenceBookPageShell}/>


Switch to heroku backend

Switch to heroku backend

--- src/Game.coffee
+++ src/Game.coffee
@@ -12,7 +12,7 @@
     @textBox.on 'submit', (word) =>
       @sendWord word

-    @socket = io.connect('http://localhost:8080', {secure: true})
+    @socket = io.connect('https://snapgame.herokuapp.com', {secure: true})
     @socket.emit 'new player', 'name'

     @socket.on 'snap', (data) =>


make test pending

make test pending

--- apps/editorial_features/test/components/eoy/client.coffee
+++ apps/editorial_features/test/components/eoy/client.coffee
@@ -170,7 +170,7 @@

   describe '#setupVideos', ->

-    it 'calls play video for each video', ->
+    xit 'calls play video for each video', ->
       @view.setupVideos()
       $('.video-controls').waypoint.args[4][0]()
       $('.video-controls').waypoint.args[5][0]()


Don't bundle native module files

Don't bundle native module files

--- build/tasks/build-task.coffee
+++ build/tasks/build-task.coffee
@@ -129,6 +129,8 @@
     ignoredPaths.push "#{_.escapeRegExp(path.join('runas', 'src') + path.sep)}.*\\.(cc|h)*"
     ignoredPaths.push "#{_.escapeRegExp(path.join('scrollbar-style', 'src') + path.sep)}.*\\.(cc|h)*"
     ignoredPaths.push "#{_.escapeRegExp(path.join('spellchecker', 'src') + path.sep)}.*\\.(cc|h)*"
+    ignoredPaths.push "#{_.escapeRegExp(path.join('cached-run-in-this-context', 'src') + path.sep)}.*\\.(cc|h)?"
+    ignoredPaths.push "#{_.escapeRegExp(path.join('marker-index', 'src') + path.sep)}.*\\.(cc|h)?"
     ignoredPaths.push "#{_.escapeRegExp(path.join('keyboard-layout', 'src') + path.sep)}.*\\.(cc|h|mm)*"

     # Ignore build files


Remove JSONString property when displaying JSON

--- SingularityUI/app/utils.coffee
+++ SingularityUI/app/utils.coffee
@@ -7,10 +7,12 @@
         JSON.stringify object, null, '    '

     viewJSON: (object) ->
+        objectClone = _.extend {}, object
+        delete objectClone.JSONString
         vex.dialog.alert
             contentCSS:
                 width: 800
-            message: "
#{ utils.stringJSON object }
"
+            message: "
#{ utils.stringJSON objectClone }
"

     getAcrossCollections: (collectionStrings, id) ->
         model = undefined


bugfix

bugfix

--- app/scripts/services/socket.coffee
+++ app/scripts/services/socket.coffee
@@ -16,7 +16,7 @@
     # on this event we should get rid of all listeners on this scope:
     $scope.$on '$destroy', (event)->
       for lis in $scope._listeners
-        socket.removeListener(lis.eventName, lis.callback)
+        socket.removeListener(lis.eventName, lis.ngCallback)
       $scope._listeners.length=0

     # return familiar to us socket.io object that can listen to and emit events:


Resize when opening tab in new window

Resize when opening tab in new window

--- lib/tab-bar-view.coffee
+++ lib/tab-bar-view.coffee
@@ -191,6 +191,7 @@
       itemURI = item.getUri()
     return unless itemURI?
     @closeTab(tab)
+    tab.element.style.maxWidth = '' for tab in @getTabs()
     pathsToOpen = [atom.project.getPaths(), itemURI].reduce ((a, b) -> a.concat(b)), []
     atom.open({pathsToOpen: pathsToOpen, newWindow: true, devMode: atom.devMode, safeMode: atom.safeMode})


only put at end for new tabs

only put at end for new tabs

--- lib/tab-bar-view.coffee
+++ lib/tab-bar-view.coffee
@@ -95,7 +95,10 @@
     tabView = new TabView()
     tabView.initialize(item, @pane)
     tabView.terminatePendingState() if @isItemMovingBetweenPanes
-    @insertTabAtIndex(tabView, index)
+    if atom.config.get('tabs.addNewTabsAtEnd')
+      @appendChild(tabView)
+    else
+      @insertTabAtIndex(tabView, index)

   moveItemTabToIndex: (item, index) ->
     if tab = @tabForItem(item)
@@ -104,7 +107,7 @@

   insertTabAtIndex: (tab, index) ->
     followingTab = @tabAtIndex(index) if index?
-    if followingTab and not atom.config.get('tabs.addNewTabsAtEnd')
+    if followingTab
       @insertBefore(tab, followingTab)
     else
       @appendChild(tab)


Just scroll to bottom if real content is higher then 100% of viewable area.

--- app/assets/javascripts/app/controllers/ticket_zoom.coffee
+++ app/assets/javascripts/app/controllers/ticket_zoom.coffee
@@ -417,6 +417,17 @@
     App.Event.trigger('ui::ticket::shown', { ticket_id: @ticket_id })

   scrollToBottom: =>
+
+    # because of .ticketZoom { min-: 101% } (force to show scrollbar to set layout correctly),
+    # we need to check if we need to really scroll bottom, in case of content isn't really 100%,
+    # just return (otherwise just a part of movable header is shown down)
+    realContentHeight = 0
+    realContentHeight += @$('.ticketZoom-controls').height()
+    realContentHeight += @$('.ticketZoom-header').height()
+    realContentHeight += @$('.ticket-article').height()
+    realContentHeight += @$('.article-new').height()
+    viewableContentHeight = @$('.main').height()
+    return if viewableContentHeight > realContentHeight
     @main.scrollTop( @main.prop('scrollHeight') )

   autosaveStop: =>


fix pan/zoom: send viewBox to SubjectViewer (bad merge)

--- app/assets/javascripts/components/subject-set-viewer.cjsx
+++ app/assets/javascripts/components/subject-set-viewer.cjsx
@@ -90,6 +90,7 @@
         destroyCurrentClassification={@props.destroyCurrentClassification}
         hideOtherMarks={@props.hideOtherMarks}
         currentSubtool={@props.currentSubtool}
+        viewBox={@state.zoomPanViewBox}
       />

     </div>


:racehorse: Use continue instead of _.without

--- src/rule.coffee
+++ src/rule.coffee
@@ -69,7 +69,9 @@
       results.push(result)

     scopes = @grammar.scopesFromStack(ruleStack)
-    for injectionGrammar in _.without(@registry.injectionGrammars, @grammar, baseGrammar)
+    for injectionGrammar in @registry.injectionGrammars
+      continue if injectionGrammar is @grammar
+      continue if injectionGrammar is baseGrammar
       if injectionGrammar.injectionSelector.matches(scopes)
         scanner = injectionGrammar.getInitialRule().getScanner(injectionGrammar, position, firstLine)
         if result = scanner.findNextMatch(lineWithNewline, position)


ScheduledCommand: cleanup enable/disable methods using @ajax

--- app/assets/javascripts/models/scheduled_command.js.coffee
+++ app/assets/javascripts/models/scheduled_command.js.coffee
@@ -40,27 +40,26 @@
       if last = @get("last_run_log")
         new B.m.CommandLog(last)

+    # Disable this ScheduledCommand
     disable: (cb) ->
-      $.ajax @urlRoot + "/disable",
-        type: "POST"
-        dataType: "json"
-        data: _.csrf({id: @id})
+      @toggle("/disable", cb)
+
+    # Enable this ScheduledCommand
+    enable: (cb) ->
+      @toggle("/enable", cb)
+
+    # Toggle this ScheduledCommand
+    toggle: (method, cb) ->
+      @ajax @url(method),
+        data: {id: @id}
         success: (data, textStatus, jqXHR) =>
           @set(data)
           cb.call(@)

-    enable: (cb) ->
-      $.ajax @urlRoot + "/enable",
-        type: "POST"
-        dataType: "json"
-        data: _.csrf({id: @id})
-        success: (data, textStatus, jqXHR) =>
-          @set(data)
-          cb.call(@)
-
+    # Run this command again with the same inputs, targets, etc
     repeat: (time, cb) ->
       @ajax @url("/repeat"),
-        data: {id: @id, scheduled_at: time}
+        data: {scheduled_at: time}
         success: (data, textStatus, jqXHR) =>
           sc = new ScheduledCommand(data)
           cb.call(@, sc)


Fixed function used to filter visible folders.

Specifically, controlled the case in which the root scope contains no feeds in the passed folder. This was not properly controlled and caused the logic to fail in many causes, with unwanted results (folders not becoming visible or the opposite).

--- app/assets/javascripts/ng-services/ng-FolderSvc.js.coffee
+++ app/assets/javascripts/ng-services/ng-FolderSvc.js.coffee
@@ -77,9 +77,10 @@

       # Always show a folder if any of its feeds has a job state alert in the start page
       feeds = findSvc.find_folder_feeds folder
-      for feed in feeds
-        subscribeJobStates = findSvc.find_feed_subscribe_jobs feed.id
-        return true if subscribeJobStates?.length > 0
+      if feeds?.length > 0
+        for feed in feeds
+          subscribeJobStates = findSvc.find_feed_subscribe_jobs feed.id
+          return true if subscribeJobStates?.length > 0

       # If the folder is not in any of the above cases, show it only if it has unread entries
       return unreadCountSvc.folder_unread_entries(folder) > 0


Change holding request JS to select scans regardless of holding status div id

--- app/assets/javascripts/resolve/holding_requests.js.coffee
+++ app/assets/javascripts/resolve/holding_requests.js.coffee
@@ -1,6 +1,6 @@
 $ ->
   scan_request_option_id = '#entire_no'
-  scan_request_container_class = '#holding-request-option-offsite-scan'
+  scan_request_container_class = '[id^=holding-request-option][id$=-scan]'
   # Select scan request if any of the text inputs have a value
   $(document).on 'keypress', scan_request_container_class + ' fieldset input', ->
     $(this).closest('fieldset').prev('label').find('input').first().prop('checked', true)


fix equation editor when opening multiple times

test plan:
* using the rich text editor, use the equation editor
to insert an equation
* click again to insert another equation (should start
with a blank equation editor)
* should be able to insert another equation instead
of receiving an "undefined" message

fixes #CNVS-10242

Change-Id: I7d07a751a8e4fa454eec616d9fadeac01ad8e760
Reviewed-on: https://gerrit.instructure.com/28172
Reviewed-by: Jon Jensen <44f878afe53efc66b76772bd845eb65944ed8232@instructure.com>
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
QA-Review: Nathan Rogowski <2e8aa918660411855c6d44d5bb2da677aa033255@instructure.com>
Product-Review: James Williams  <3a5f4ed991dbfa5c9ef76ad729d240ca12f62180@instructure.com>

--- app/coffeescripts/views/tinymce/EquationEditorView.coffee
+++ app/coffeescripts/views/tinymce/EquationEditorView.coffee
@@ -42,7 +42,6 @@
       '#mathjax-message': '$mathjaxMessage'

     initialize: (@editor) ->
-      super
       @$editor = $("##{@editor.id}")
       @prevSelection = @editor.selection.getBookmark()


rerender on model change in nav

rerender on model change in nav

--- client/code/view/subnav.coffee
+++ client/code/view/subnav.coffee
@@ -160,6 +160,7 @@

   initialize: ->
     @model.on 'change', @setDocumentTitle, @
+    @model.on 'change', @render, this
     # set this so we can override it in Cu.View.ViewSubnav
     # (where the model to save is in fact the parent dataset's model)
     @modelToSave = @model
@@ -216,6 +217,9 @@
     'blur #editable-input': 'editableNameBlurred'
     'keyup #editable-input': 'keypressOnEditableName'

+  initialize: ->
+    @model.on 'change', @render, this
+
   render: ->
     @$el.html("""

@@ -239,6 +243,9 @@
   # This view should be passed a dataset model!
   className: 'subnav-wrapper'

+  initialize: ->
+    @model.on 'change', @render, this
+
   render: ->
     @$el.html("""

@@ -266,6 +273,10 @@
 class Cu.View.ViewNav extends Cu.View.EditableSubnav
   className: 'subnav-wrapper'

+  initialize: ->
+    @model.on 'change', @setDocumentTitle, @
+    @model.on 'change', @render, this
+
   events:
     'click .editable': 'nameClicked'
     'blur #editable-input': 'editableNameBlurred'


for some reason i didn't save after the conflict was resolved…  so i committed unmerged work accidentally…  fixes that

--- node_modules_koding/bongo/lib/bongo.coffee
+++ node_modules_koding/bongo/lib/bongo.coffee
@@ -144,22 +144,6 @@

   connect:(callback)->
     @mq.ready =>
-<<<<<<< HEAD
-      @mq.connection.queue @queueName, {autoDelete:no}, (queue)=>
-        queue.subscribe (message, headers, deliveryInfo)=>
-          {exchange, routingKey} = deliveryInfo
-          msg = ''+message?.data
-          switch routingKey
-            when 'client-message'
-              @handleRequest exchange, msg
-            when 'client-join'
-              message =
-                method    : 'defineApi'
-                arguments : [@describeApi()]
-                callbacks : {}
-              @mq.emit exchange, 'server-message', message
-              @handleAuth exchange, msg
-=======
       @mq.connection.queue @queueName, {autoDelete:no}, (@queue)=>
         queue
           .subscribe((message, headers, deliveryInfo)=>
@@ -186,7 +170,6 @@
     delete @readyState = 0
     delete @queue
     callback null
->>>>>>> d7ddc49... implement Bongo#disconnect (first draft)

   handleAuth:(secretName, sessionToken)->
     @emit 'auth', secretName, sessionToken


Open metrics package directly

Open metrics package directly

- Depends on https://github.com/atom/settings-view/pull/614

--- lib/welcome-view.coffee
+++ lib/welcome-view.coffee
@@ -39,7 +39,7 @@
                 Note: To help us improve Atom, we anonymously
                 track usage metrics, such as launch time, screen size, and current
                 version. See the
-                atom/metrics
+                atom/metrics
                 package for details and instructions to disable it.
               '''

@@ -55,6 +55,9 @@
       eventName = $(this).attr('data-event')
       Reporter.sendEvent("clicked-welcome-#{eventName}-link") if eventName

+    @on 'click', 'a.js-metrics', ->
+      atom.workspace.open('atom://config/packages/metrics')
+
   serialize: ->
     deserializer: @constructor.name
     uri: @getURI()


Safer sourcemap building.

Safer sourcemap building.

--- lib/Watchers/Sourcemap.coffee
+++ lib/Watchers/Sourcemap.coffee
@@ -9,41 +9,46 @@

     handle: (req, res, next)->
         res.status(200).set('Content-Type', @type())
-        if req.path.substr(-4) is '.map'
+        if req.path.substr(-4) is '.map' and @hasMap
             res.send(@map)
         else
-            res.set('SourceMap', req.path + '.map').send(@content)
+            res.set('SourceMap', req.path + '.map') if @hasMap
+            res.send(@content)

     getPaths: -> @files
     concat: (_)->
         content = _.map((f)->f.content).join '\n'
+        sourceMap = null

-        lastOffset = 0
-        bundle = combine.create(@files[0])
-        _.map (f)->
-            comment = convert.fromObject(f.sourceMap).toComment()
-            # + 1 for the '\n' in the join above
-            newLines = (f.content.match(/\n/g)||[]).length + 1
-            source = "#{f.content}\n#{comment}"
-            sourceFile = f.sourceMap.sources[0]
-            {source, sourceFile, newLines}
-        .forEach (f, i)->
-            offset = {line: lastOffset}
+        try
+            lastOffset = 0
+            bundle = combine.create(@files[0])
+            _.map (f)->
+                comment = convert.fromObject(f.sourceMap).toComment()
+                # + 1 for the '\n' in the join above
+                newLines = (f.content.match(/\n/g)||[]).length + 1
+                source = "#{f.content}\n#{comment}"
+                sourceFile = f.sourceMap.sources[0]
+                {source, sourceFile, newLines}
+            .forEach (f, i)->
+                offset = {line: lastOffset}

-            lastOffset += f.newLines
-            delete f.newLines
+                lastOffset += f.newLines
+                delete f.newLines

-            bundle.addFile f, offset
+                bundle.addFile f, offset

-        base64 = bundle.base64()
-        sourceMap = convert.fromBase64(base64).toObject()
-
+            base64 = bundle.base64()
+            sourceMap = convert.fromBase64(base64).toObject()
+        catch err
+            @log {warning: "Failed combining source maps.", err}
         {content, sourceMap}

     finish: (_ = {content: ''})->
         @printSuccess()
         @content = _.content
-        @map = JSON.stringify _.sourceMap
+        @hasMap = _.sourceMap?
+        @map = JSON.stringify _.sourceMap if @hasMap
         @_defer.resolve()

 module.exports = SourcemapWatcher


Redirect to v1 plans page from v2

Redirect to v1 plans page from v2

--- services/web/app/coffee/Features/Subscription/SubscriptionRouter.coffee
+++ services/web/app/coffee/Features/Subscription/SubscriptionRouter.coffee
@@ -9,7 +9,10 @@
 	apply: (webRouter, privateApiRouter, publicApiRouter) ->
 		return unless Settings.enableSubscriptions

-		if !Settings.disablePlansPage
+		if Settings.overleaf?
+			webRouter.get  '/user/subscription/plans', (req, res) ->
+				res.redirect "#{Settings.overleaf.host}/plans"
+		else
 			webRouter.get  '/user/subscription/plans', SubscriptionController.plansPage

 		webRouter.get  '/user/subscription',            AuthenticationController.requireLogin(), SubscriptionController.userSubscriptionPage


Added replace, rfind, rindex, rjust

Added replace, rfind, rindex, rjust

--- src/builtin/string.coffee
+++ src/builtin/string.coffee
@@ -105,6 +105,10 @@
           return false
       return true

+  ###
+  TODO: Fix istitle to account for punctuations as described in:
+  http://docs.python.org/library/stdtypes.html#str.title
+  ###
   istitle: ->
     words = @value.split ' '
     for word in words
@@ -148,6 +152,30 @@
     else
       partitions = [splitValues[0], "", ""]
     return new Tuple(partitions)
+
+  replace: (old, new, count = null) ->
+    if count?
+      return @split(old, count).join(new)
+    else
+      return @split(old).join(new)
+
+  rfind: (sub, start = 0, end = @__len__()) ->
+    lastIndex = @__slice__(start, end).lastIndexOf(sub)
+    return lastIndex
+
+  rindex: (sub, start = 0, end = @__len__()) ->
+    lastIndex = substr.lastIndexOf(sub)
+    if lastIndex == -1
+      (new ValueError "substring not found").raise()
+    else
+      return lastIndex
+
+  rjust: (width, fillchar = ' ') ->
+    if width <= @__len__()
+      return @value
+    delta = width - @__len__()
+    pad = String('').__mul__(delta)
+    return pad + @value

   startswith: (prefix, start = 0, end = @__len__()) ->
     return @value.slice(start, end).indexOf(suffix) == 0


Create Messaging the user + Deserializing sections

--- src/atom.coffee
+++ src/atom.coffee
@@ -430,39 +430,6 @@
     dimensions = @getWindowDimensions()
     @state.windowDimensions = dimensions if @isValidDimensions(dimensions)

-
-
-
-
-  deserializeProject: ->
-    Project = require './project'
-
-    startTime = Date.now()
-    @project ?= @deserializers.deserialize(@state.project) ? new Project(path: @getLoadSettings().initialPath)
-    @deserializeTimings.project = Date.now() - startTime
-
-  deserializeWorkspaceView: ->
-    Workspace = require './workspace'
-    WorkspaceView = require './workspace-view'
-
-    startTime = Date.now()
-    @workspace = Workspace.deserialize(@state.workspace) ? new Workspace
-    @workspaceView = new WorkspaceView(@workspace)
-    @deserializeTimings.workspace = Date.now() - startTime
-
-    @keymaps.defaultTarget = @workspaceView[0]
-    $(@workspaceViewParentSelector).append(@workspaceView)
-
-  deserializePackageStates: ->
-    @packages.packageStates = @state.packageStates ? {}
-    delete @state.packageStates
-
-  deserializeEditorWindow: ->
-    @deserializeTimings = {}
-    @deserializePackageStates()
-    @deserializeProject()
-    @deserializeWorkspaceView()
-
   # Call this method when establishing a real application window.
   startEditorWindow: ->
     {resourcePath, safeMode} = @getLoadSettings()
@@ -513,25 +480,16 @@

     @windowEventHandler?.unsubscribe()

-  loadThemes: ->
-    @themes.load()
-
-  watchThemes: ->
-    @themes.onDidReloadAll =>
-      # Only reload stylesheets from non-theme packages
-      for pack in @packages.getActivePackages() when pack.getType() isnt 'theme'
-        pack.reloadStylesheets?()
-      null
-
-  # Notify the browser project of the window's current project path
-  watchProjectPath: ->
-    onProjectPathChanged = =>
-      ipc.send('window-command', 'project-path-changed', @project.getPath())
-    @subscribe @project, 'path-changed', onProjectPathChanged
-    onProjectPathChanged()
-
-
-  # Public: Open a confirm dialog.
+  ###
+  Section: Messaging the User
+  ###
+
+  # Public: Visually and audibly trigger a beep.
+  beep: ->
+    shell.beep() if @config.get('core.audioBeep')
+    @workspaceView.trigger 'beep'
+
+  # Public: A flexible way to open a dialog akin to an alert dialog.
   #
   # ## Examples
   #
@@ -546,8 +504,8 @@
   #
   # * `options` An {Object} with the following keys:
   #   * `message` The {String} message to display.
-  #   * `detailedMessage` The {String} detailed message to display.
-  #   * `buttons` Either an array of strings or an object where keys are
+  #   * `detailedMessage` (optional) The {String} detailed message to display.
+  #   * `buttons` (optional) Either an array of strings or an object where keys are
   #     button names and the values are callbacks to invoke when clicked.
   #
   # Returns the chosen button index {Number} if the buttons option was an array.
@@ -571,6 +529,92 @@
       callback = buttons[buttonLabels[chosen]]
       callback?()

+  ###
+  Section: Deserialization
+  ###
+
+  deserializeProject: ->
+    Project = require './project'
+
+    startTime = Date.now()
+    @project ?= @deserializers.deserialize(@state.project) ? new Project(path: @getLoadSettings().initialPath)
+    @deserializeTimings.project = Date.now() - startTime
+
+  deserializeWorkspaceView: ->
+    Workspace = require './workspace'
+    WorkspaceView = require './workspace-view'
+
+    startTime = Date.now()
+    @workspace = Workspace.deserialize(@state.workspace) ? new Workspace
+    @workspaceView = new WorkspaceView(@workspace)
+    @deserializeTimings.workspace = Date.now() - startTime
+
+    @keymaps.defaultTarget = @workspaceView[0]
+    $(@workspaceViewParentSelector).append(@workspaceView)
+
+  deserializePackageStates: ->
+    @packages.packageStates = @state.packageStates ? {}
+    delete @state.packageStates
+
+  deserializeEditorWindow: ->
+    @deserializeTimings = {}
+    @deserializePackageStates()
+    @deserializeProject()
+    @deserializeWorkspaceView()
+
+
+
+
+  loadThemes: ->
+    @themes.load()
+
+  watchThemes: ->
+    @themes.onDidReloadAll =>
+      # Only reload stylesheets from non-theme packages
+      for pack in @packages.getActivePackages() when pack.getType() isnt 'theme'
+        pack.reloadStylesheets?()
+      null
+
+  # Notify the browser project of the window's current project path
+  watchProjectPath: ->
+    onProjectPathChanged = =>
+      ipc.send('window-command', 'project-path-changed', @project.getPath())
+    @subscribe @project, 'path-changed', onProjectPathChanged
+    onProjectPathChanged()
+
+
+  ###
+  Section: Managing the Dev Tools
+  ###
+
+  # Public: Open the dev tools for the current window.
+  openDevTools: ->
+    ipc.send('call-window-method', 'openDevTools')
+
+  # Public: Toggle the visibility of the dev tools for the current window.
+  toggleDevTools: ->
+    ipc.send('call-window-method', 'toggleDevTools')
+
+  # Public: Execute code in dev tools.
+  executeJavaScriptInDevTools: (code) ->
+    ipc.send('call-window-method', 'executeJavaScriptInDevTools', code)
+
+
+
+
+  exit: (status) ->
+    app = remote.require('app')
+    app.emit('will-exit')
+    remote.process.exit(status)
+
+  setDocumentEdited: (edited) ->
+    ipc.send('call-window-method', 'setDocumentEdited', edited)
+
+  setRepresentedFilename: (filename) ->
+    ipc.send('call-window-method', 'setRepresentedFilename', filename)
+
+
+
   showSaveDialog: (callback) ->
     callback(showSaveDialogSync())

@@ -579,37 +623,6 @@
     currentWindow = @getCurrentWindow()
     dialog = remote.require('dialog')
     dialog.showSaveDialog currentWindow, {title: 'Save File', defaultPath}
-
-
-  ###
-  Section: Managing the Dev Tools
-  ###
-
-  # Public: Open the dev tools for the current window.
-  openDevTools: ->
-    ipc.send('call-window-method', 'openDevTools')
-
-  # Public: Toggle the visibility of the dev tools for the current window.
-  toggleDevTools: ->
-    ipc.send('call-window-method', 'toggleDevTools')
-
-  # Public: Execute code in dev tools.
-  executeJavaScriptInDevTools: (code) ->
-    ipc.send('call-window-method', 'executeJavaScriptInDevTools', code)
-
-
-
-  exit: (status) ->
-    app = remote.require('app')
-    app.emit('will-exit')
-    remote.process.exit(status)
-
-  setDocumentEdited: (edited) ->
-    ipc.send('call-window-method', 'setDocumentEdited', edited)
-
-  setRepresentedFilename: (filename) ->
-    ipc.send('call-window-method', 'setRepresentedFilename', filename)
-

   saveSync: ->
     stateString = JSON.stringify(@state)
@@ -618,26 +631,12 @@
     else
       @getCurrentWindow().loadSettings.windowState = stateString

-  # Public: Get the time taken to completely load the current window.
-  #
-  # This time include things like loading and activating packages, creating
-  # DOM elements for the editor, and reading the config.
-  #
-  # Returns the {Number} of milliseconds taken to load the window or null
-  # if the window hasn't finished loading yet.
-  getWindowLoadTime: ->
-    @loadTime

   crashMainProcess: ->
     remote.process.crash()

   crashRenderProcess: ->
     process.crash()
-
-  # Public: Visually and audibly trigger a beep.
-  beep: ->
-    shell.beep() if @config.get('core.audioBeep')
-    @workspaceView.trigger 'beep'

   getUserInitScriptPath: ->
     initScriptPath = fs.resolve(@getConfigDirPath(), 'init', ['js', 'coffee'])
@@ -650,7 +649,7 @@
       catch error
         console.error "Failed to load `#{userInitScriptPath}`", error.stack, error

-  # Public: Require the module with the given globals.
+  # Require the module with the given globals.
   #
   # The globals will be set on the `window` object and removed after the
   # require completes.


Use getWindowState instead of referencing window state directly

--- src/atom.coffee
+++ src/atom.coffee
@@ -319,7 +319,7 @@

   # Private: Returns a replicated copy of the current state.
   replicate: ->
-    @windowState.replicate()
+    @getWindowState().replicate()

   crashMainProcess: ->
     remote.process.crash()


fix Log reference

fix Log reference

--- coffee/services/redmine.coffee
+++ coffee/services/redmine.coffee
@@ -38,7 +38,7 @@
   @SHOW: { DEFAULT: 0, NOT: 1, SHOW: 2 }
   @NULLFUNC: () ->

-  constructor: (@auth, @$http, @$q, @observer, @Ticket, @Project, @Base64, @Analytics) ->
+  constructor: (@auth, @$http, @$q, @observer, @Ticket, @Project, @Base64, @Analytics, @Log) ->
     @url = auth.url

   _timeEntryData:
@@ -162,7 +162,7 @@
             url: @auth.url
             id:  issueId
         else
-          Log.debug data
+          @Log.debug data
           @Analytics.sendException("Error: getIssuesById")
         error(data, status))

@@ -188,7 +188,7 @@
         @Analytics.sendEvent 'internal', 'submitTime', 'success', config.hours
         success(data))
       .error((data) =>
-        Log.debug data
+        @Log.debug data
         @Analytics.sendException("Error: submitTime")
         error(data))


simple window.onload wait for now

simple window.onload wait for now

--- coffeescript/punchdrunk.coffee
+++ coffeescript/punchdrunk.coffee
@@ -1,19 +1,20 @@
-# Forward print() messages to the console
-shine.stdout.write = () ->
-  console.log.apply(console, arguments)
+window.onload = ->
+  # Forward print() messages to the console
+  shine.stdout.write = () ->
+    console.log.apply(console, arguments)

-conf = {
-  window: {},
-  modules: {}
-}
+  conf = {
+    window: {},
+    modules: {}
+  }

-new shine.FileManager().load './lua/conf.lua.json', (_, file) ->
-  conf_env = {love: {}}
-  conf_vm = new shine.VM(conf_env)
-  conf_vm.execute(null, file)
-  conf_env.love.conf.call(null, conf)
+  new shine.FileManager().load './lua/conf.lua.json', (_, file) ->
+    conf_env = {love: {}}
+    conf_vm = new shine.VM(conf_env)
+    conf_vm.execute(null, file)
+    conf_env.love.conf.call(null, conf)

-  vm = new shine.VM({
-    love: new Love(conf.window)
-  })
-  vm.load('./js/boot.lua.json')
+    vm = new shine.VM({
+      love: new Love(conf.window)
+    })
+    vm.load('./js/boot.lua.json')


Fix bug in testing preconditions and events

The bug occurs when the session was serialized and deserialized as a
result of requests coming through a new TCP connection.

Resolves: #219

--- lib/cwmp.coffee
+++ lib/cwmp.coffee
@@ -236,6 +236,9 @@
           break

         blackList[channel] = if fault.precondition then 1 else 2
+
+    sessionContext.deviceData.timestamps.revision = 1
+    sessionContext.deviceData.attributes.revision = 1

     deviceEvents = {}
     for p in sessionContext.deviceData.paths.find(['Events', '*'], false, true)


reading width/height from model for table view

--- src/coffee/ui_view.coffee
+++ src/coffee/ui_view.coffee
@@ -54,8 +54,8 @@
       table.append(row)
     @$el.empty()
     @$el.html(table)
-    @$el.height(300)
-    @$el.width(300)
+    @$el.height(@mget('height'))
+    @$el.width(@mget('width'))
     @$el.addClass("bokehtable")

 Continuum.ui.DataTableView = DataTableView


link pool_patches to a pool

link pool_patches to a pool


Early streamer class design

Early streamer class design

--- src/stream.iced
+++ src/stream.iced
@@ -1,14 +1,25 @@
-enc = require './encoding'
-http = require('http');
-b64 = enc.b64.encoding
+stream = require('stream');
+enc = require('./encoding');

-stream_data = (src, dst) ->
-	src.on 'data', (chunk) ->
-		dst.write(b64.decode(new Buffer chunk, 'utf-8'));
+exports.Streamer = class Streamer extends stream.Duplex

-server = http.createServer (req, res) ->
-	stream_data(req, res);
-	req.on 'end', ->
-		res.end();
+	constructor : (block_len) ->
+		alphabet = enc.b58.alphabet if block_len is 58
+		alphabet = enc.b62.alphabet if block_len is 58
+		alphabet = enc.b64.alphabet if block_len is 58
+		@encoder = new Encoding(alphabet, block_len);
+		super({highWaterMark: block_len});

-server.listen(39393);
+	encode : (src) ->
+		src.on('readable', () ->
+			chunk = null;
+			while (chunk = src.read(@highWaterMark)) != null
+				@write enc.b64.encoding.encode(chunk);
+			)
+
+	decode : (src) ->
+		src.on('readable', () ->
+			chunk = null;
+			while (chunk = src.read(@highWaterMark)) != null
+				@write(enc.b64.encoding.decode(chunk));
+			)


Add divide by zero check'

Add divide by zero check'

--- app/views/play/CampaignView.coffee
+++ app/views/play/CampaignView.coffee
@@ -365,7 +365,10 @@
     return experienceScore

   createLine: (o1, o2) ->
-    ratio = parseFloat($(".map").css("width")) / parseFloat($(".map").css("height"))
+    mapHeight = parseFloat($(".map").css("height"))
+    mapWidth = parseFloat($(".map").css("width"))
+    return unless mapHeight > 0
+    ratio =  mapWidth / mapHeight
     p1 = x: o1.x, y: o1.y / ratio - 0.5
     p2 = x: o2.x, y: o2.y / ratio
     length = Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y))