Fixed bug with retrieving movepool

Fixed bug with retrieving movepool

--- client/app/js/models/pokemon.coffee
+++ client/app/js/models/pokemon.coffee
@@ -34,11 +34,11 @@

     learnset = []
     for generation in [3, 4, 5]
-      generation_move_methods = species.learnset["generation-#{generation}"] || []
-      for method, moves of generation_move_methods
-        learnset.push(moveName) for moveName, level of moves
+      generationMoveMethods = species.learnset["generation-#{generation}"] || []
+      for method, moves of generationMoveMethods
+        learnset.push(moveName)  for moveName, level of moves

-    learnset = _.chain(learnset).sort().unique(true)
+    learnset = _.chain(learnset).sort().unique(true).value()

     # Map each move name to a move object
     return _(learnset).map (moveName) ->


Fix typo.

Fix typo.

--- src/application.coffee
+++ src/application.coffee
@@ -123,7 +123,7 @@
 					for envVar in app.environment_variable
 						env[envVar.name] = envVar.value
 				return {
-					imageId: "#{pocess.env.REGISTRY_ENDPOINT}/#{path.basename(app.git_repository, '.git')}/#{app.commit}"
+					imageId: "#{process.env.REGISTRY_ENDPOINT}/#{path.basename(app.git_repository, '.git')}/#{app.commit}"
 					env: env
 				}


Get remote apps per uuid

Get remote apps per uuid

--- src/application.coffee
+++ src/application.coffee
@@ -413,22 +413,25 @@
 	updateStrategies[strategy](options)

 getRemoteApps = (apiKey) ->
-	appIds = _.map(config.multivisor.apps, (app) -> app.appId)
-	if appIds.length == 1
-		appIds = appIds[0]
-	cachedResinApi.get
-		resource: 'application'
-		options:
-			select: [
-				'id'
-				'git_repository'
-				'commit'
-			]
-			filter:
-				commit: $ne: null
-				id: appIds
-		customOptions:
-			apikey: apiKey
+	Promise.map config.multivisor.apps, (app) ->
+		device.getUUID(app.appId)
+		.then (uuid) ->
+			cachedResinApi.get
+				resource: 'application'
+				options:
+					select: [
+						'id'
+						'git_repository'
+						'commit'
+					]
+					filter:
+						commit: $ne: null
+						device:
+							uuid: uuid
+				customOptions:
+					apikey: apiKey
+	.then(_.flatten)
+

 getEnvAndFormatRemoteApps = (deviceIds, remoteApps, uuids, apiKey) ->
 	deviceIds = _.mapValues _.indexBy(deviceIds, 'appId'), (d) ->


Fix for character tinting.

Fix for character tinting.

--- packages/landsofillusions/engine/world/renderermanager.coffee
+++ packages/landsofillusions/engine/world/renderermanager.coffee
@@ -64,7 +64,7 @@
     # in this pass. This will setup shadows for further passes as well.
     @renderer.shadowMap.needsUpdate = true

-    @renderer.setClearColor 0xffff00, 1
+    @renderer.setClearColor 0x000000, 1
     @renderer.render scene, camera, @preprocessingRenderTarget

     # Render the color shadow maps. First set the shadow color material on all meshes.


client: home: move creds view as stacks' tab's last tab

--- client/home/lib/stacks/index.coffee
+++ client/home/lib/stacks/index.coffee
@@ -10,6 +10,8 @@
 HomeVirtualMachinesVirtualMachines = require '../virtualmachines/homevirtualmachinesvirtualmachines'
 HomeVirtualMachinesConnectedMachines = require '../virtualmachines/homevirtualmachinesconnectedmachines'
 HomeVirtualMachinesSharedMachines = require '../virtualmachines/homevirtualmachinessharedmachines'
+
+HomeAccountCredentialsView = require '../account/credentials/homeaccountcredentialsview'

 EnvironmentFlux = require 'app/flux/environment'

@@ -41,6 +43,7 @@
     kd.singletons.mainController.ready =>
       @createStacksViews()
       @createVMsViews()
+      @createCredentialsViews()

   handleAction: (action) ->
@@ -78,3 +81,9 @@

     @vms.addSubView headerize 'Shared Machines'
     @vms.addSubView sectionize 'Shared Machines', HomeVirtualMachinesSharedMachines
+
+
+  createCredentialsViews: ->
+
+    @credentials.addSubView headerize 'Credentials'
+    @credentials.addSubView sectionize 'Credentials', HomeAccountCredentialsView


lower max changefeeds per client due to bug fixes

--- src/smc-hub/rethink.coffee
+++ src/smc-hub/rethink.coffee
@@ -27,9 +27,7 @@
 # thousands of changefeeds to get opened in a second.
 # If there were a better error, this could be a parameter that depends on
 # whether the user (or project) is paying or not.
-MAX_CHANGEFEEDS_PER_CLIENT = 5*100 # about 3-5 feeds per file right now
-# increase until better garbage collection of changefeeds!
-MAX_CHANGEFEEDS_PER_CLIENT = 12*100
+MAX_CHANGEFEEDS_PER_CLIENT = 6*100 # about 3-5 feeds per file right now

 fs         = require('fs')
 async      = require('async')


update some blob management params

update some blob management params

--- src/smc-hub/rethink.coffee
+++ src/smc-hub/rethink.coffee
@@ -2620,8 +2620,9 @@
         opts = defaults opts,
             limit    : 10000     # number of blobs to backup
             path     : required  # path where [timestamp].tar file is placed
-            throttle : 1         # wait this many seconds between pulling blobs from database
+            throttle : 0         # wait this many seconds between pulling blobs from database
             repeat_until_done : 0 # if positive keeps re-call'ing this function until no more results to backup (pauses this many seconds between)
+            map_limit: 5
             cb    : undefined # cb(err, '[timestamp].tar')
         dbg     = @dbg("backup_blobs_to_tarball(limit=#{opts.limit},path='#{opts.path}')")
         join    = require('path').join
@@ -2660,7 +2661,7 @@
                             else
                                 dbg("blob is expired, so nothing to be done, ever.")
                                 cb()
-                async.mapLimit(v, 2, f, cb)
+                async.mapLimit(v, opts.map_limit, f, cb)
             (cb) =>
                 dbg("successfully wrote all blobs to files; now make tarball")
                 misc_node.execute_code
@@ -2686,7 +2687,7 @@
                 opts.cb?(err)
             else
                 dbg("done")
-                if opts.repeat_until_done and to_remove.length > 0
+                if opts.repeat_until_done and to_remove.length == opts.limit
                     f = () =>
                         @backup_blobs_to_tarball(opts)
                     setTimeout(f, opts.repeat_until_done*1000)
@@ -2703,7 +2704,7 @@
             bucket    : BLOB_GCLOUD_BUCKET # name of bucket
             limit     : 1000               # copy this many in each batch
             map_limit : 1                  # copy this many at once.
-            throttle  : 1                  # wait this many seconds between uploads
+            throttle  : 0                  # wait this many seconds between uploads
             repeat_until_done_s : 0        # if nonzero, waits this many seconds, then recalls this function until nothing gets uploaded.
             errors    : {}                 # used to accumulate errors
             remove    : false


fix https://github.com/sagemathinc/smc/issues/1895 -- "display of mathjax in safari (in markdown output) is completely broken"

--- src/smc-webapp/r_misc.cjsx
+++ src/smc-webapp/r_misc.cjsx
@@ -754,11 +754,14 @@
              not underscore.isEqual(@props.style, newProps.style) or \
              @props.safeHTML != newProps.safeHTML

+    ###
+    # Seems no longer necessary and *DOES* break massively on Safari! -- see https://github.com/sagemathinc/smc/issues/1895
     _update_escaped_chars: ->
         if not @_is_mounted
             return
         node = $(ReactDOM.findDOMNode(@))
         node.html(node[0].innerHTML.replace(/\\\$/g, '$'))
+    ###

     _update_mathjax: (cb) ->
         if not @_is_mounted  # see https://github.com/sagemathinc/smc/issues/1689
@@ -794,7 +797,7 @@
         @_update_mathjax =>
             if not @_is_mounted
                 return
-            @_update_escaped_chars()
+            #@_update_escaped_chars()
             @_update_links()   # this MUST be after update_escaped_chars -- see https://github.com/sagemathinc/smc/issues/1391
             @_update_tables()


Fix function call context.

Fix function call context.

Fix #243

--- app/stores/assignments-store.coffee
+++ app/stores/assignments-store.coffee
@@ -49,9 +49,8 @@
     if newState.activeAssignment
       newState.activeAssignment.myClassificationCount++

-  _getClassificationCount: (assignment, state) ->
+  _getClassificationCount: (assignment, studentData) ->
     studentAssignments = assignment.relationships.student_assignments.data
-    studentData = state.assignments.student_data
     studentUsers = assignment.relationships.student_users.data
     classifications = 0
     studentAssignments.forEach (studentAssignmentsItem) ->
@@ -78,14 +77,12 @@
       if json.data.length
         newState = _.assign {}, @data
         newState.active = true
-
-        newState.assignments = newState.assignments.concat json.data.map (assignment) ->
+        newState.assignments = newState.assignments.concat json.data.map (assignment) =>
           id: assignment.id
           workflowId: assignment.attributes.workflow_id
           name: assignment.attributes.name
           classificationTarget: assignment.attributes.metadata.classifications_target ? ''
-          myClassificationCount: @_getClassificationCount(assignment, newState)
-
+          myClassificationCount: @_getClassificationCount(assignment, json.included)
         @data = newState
         @trigger @data
         console.info 'assignments', @data


Fix facebook share media group params

Fix facebook share media group params

--- src/collections/teamMediaGroups.coffee
+++ src/collections/teamMediaGroups.coffee
@@ -38,8 +38,8 @@

 # Share teamMediaGroup on an associated Facebook page that YOU manage
-exports.facebookShareMediaGroup = (teamMediumId, facebookPageId, postToWall,
-  albumName, callback) ->
+exports.facebookShareMediaGroup = (teamMediaGroupId, facebookPageId,
+  isSuppressedFromFeed, albumName, callback) ->
     if typeof albumName is 'function'
       callback = albumName

@@ -53,10 +53,10 @@
       boolean postToWall'

     params = {
-      teamMediumId: teamMediumId,
+      teamMediaGroupId: teamMediaGroupId,
       facebookPageId: facebookPageId,
       albumName: albumName,
-      postToWall: postToWall
+      isSuppressedFromFeed: isSuppressedFromFeed
     }

     @collections.teamMedia.exec('facebookShareMediaGroup', params)


console log

console log

--- apps/auction/client/bid_form.coffee
+++ apps/auction/client/bid_form.coffee
@@ -40,7 +40,6 @@
     @timesPolledForBidPlacement = 0
     @$submit.addClass('is-loading')
     @clearErrors()
-    console.log @getBidAmount(), @saleArtwork.get('minimum_next_bid_cents')
     if @getBidAmount(@$('input.max-bid').val()) >= @saleArtwork.get('minimum_next_bid_cents')
       bidderPosition = new BidderPosition
         sale_id              : @model.get('id')


Clean things up.

Clean things up.

--- apps/partner/client/overview.coffee
+++ apps/partner/client/overview.coffee
@@ -82,7 +82,7 @@
     locations.url = "#{@partner.url()}/locations"
     locations.fetchUntilEnd success: =>
       locationsArray = []
-      _.each locations.groupBy('city'), (ls, c) =>
-        _.each ls, (l) =>
-          locationsArray.push '
' + l.toHtml() + '
'
+      _.each locations.groupBy('city'), (ls, c) ->
+        _.each ls, (l) ->
+          locationsArray.push "
#{l.toHtml()}
"
       @$('.locations').html locationsArray.join('')


Add missing sponsors.

Add missing sponsors.

--- assets/scripts/data/sponsors.coffee
+++ assets/scripts/data/sponsors.coffee
@@ -39,6 +39,9 @@
   { type: 'silver', link: "Twitter: instantly connects people everywhere" }
   { type: 'silver', link: "AGiLE ANiMAL: we <3 Travis CI." }
   { type: 'silver', link: "Tupalo: Discover, review & share local businesses." }
+  { type: 'silver', link: "Pivotal Labs"}
+  { type: 'silver', link: "Fiksu"}
+  { type: 'silver', link: "Sauce Labs"}
 ]

 @Travis.WORKERS = {


add demo poetry genre material

add demo poetry genre material

--- client/views/reading/reading.coffee
+++ client/views/reading/reading.coffee
@@ -52,6 +52,75 @@
       }
   )

+Template.reading.helpers(
+
+    work : () -> {
+
+        title : "Aeneid",
+        slug : "aeneid",
+
+        author : {
+            english_full : "Vergil",
+            original_full : "Publius Vergilius Maximus"
+
+          },
+
+        edition : {
+            editor : "R. A. B. Mynors",
+            year : 1922,
+
+          },
+
+        meta : "book-line",
+
+        books : [{
+                type : "book",
+                n : "I",
+
+                lines : [{
+
+                          n : "1",
+                          html : "
Arma virumque cano, Troiae qui primus ab oris
",
+                        },{
+                          n : "2",
+                          html : "
Italiam, fato profugus, Laviniaque venit
"
+                        },{
+                          n : "3",
+                          html : "
litora, multum ille et terris iactatus et alto
"
+                        },{
+                          n : "4",
+                          html : "
vi superum saevae memorem Iunonis ob iram;
"
+                        },{
+                          n : "5",
+                          html : "
multa quoque et bello passus, dum conderet urbem,
"
+                        },{
+                          n : "6",
+                          html : "
inferretque deos Latio, genus unde Latinum,
"
+                        },{
+                          n : "7",
+                          html : "
Albanique patres, atque altae moenia Romae.
"
+                        },{
+                          n : "8",
+                          html : "
Musa, mihi causas memora, quo numine laeso,
"
+                        },{
+                          n : "9",
+                          html : "
quidve dolens, regina deum tot volvere casus
"
+                        },{
+                          n : "10",
+                          html : "
insignem pietate virum, tot adire labores
"
+                        },{
+                          n : "11",
+                          html : "
impulerit.  Tantaene animis caelestibus irae?
"
+
+                        }]
+
+                      }]
+
+              }]
+      }
+  )
+
+

 Template.headerReading.events = (


fixed undefined before filterBy. need to handle refresh

--- app/app/controllers/posts/post.coffee
+++ app/app/controllers/posts/post.coffee
@@ -1,7 +1,7 @@
 Controller = Ember.ObjectController.extend

 	normalImage: (->
-		@get("images").filterBy("type","normal")[0]?.get("link")
+		@get("images")?.filterBy("type","normal")[0]?.get("link")
 	).property("images.@each")

 `export default Controller`


Add GFLOPS and memory bandwidth to cloud status.

--- src/ext/components/cloud-output.coffee
+++ src/ext/components/cloud-output.coffee
@@ -62,6 +62,8 @@
     [ "Load", yes ]
     [ "My CPU %", yes ]
     [ "Sys CPU %", yes ]
+    [ "GFLOPS", yes ]
+    [ "Memory Bandwidth", yes ]
     [ "Data (Used/Total)", yes ]
     [ "Data (% Cached)", yes ]
     [ "GC (Free / Total / Max)", yes ]
@@ -85,6 +87,8 @@
       format3f node.sys_load
       node.my_cpu_pct
       node.sys_cpu_pct
+      format3f node.gflops
+      "#{prettyPrintBytes node.mem_bw} / s"
       "#{prettyPrintBytes node.mem_value_size} / #{prettyPrintBytes node.total_value_size}"
       "#{Math.floor node.mem_value_size * 100 / node.total_value_size}%"
       "#{prettyPrintBytes node.free_mem} / #{prettyPrintBytes node.tot_mem} / #{prettyPrintBytes node.max_mem}"
@@ -109,6 +113,8 @@
       format3f sum nodes, (node) -> node.sys_load
       '-'
       '-'
+      "#{(format3f sum nodes, (node) -> node.gflops)}"
+      "#{prettyPrintBytes (sum nodes, (node) -> node.mem_bw)} / s"
       "#{prettyPrintBytes (sum nodes, (node) -> node.mem_value_size)} / #{prettyPrintBytes (sum nodes, (node) -> node.total_value_size)}"
       "#{Math.floor (avg nodes, (node) -> node.mem_value_size * 100 / node.total_value_size)}%"
       "#{prettyPrintBytes (sum nodes, (node) -> node.free_mem)} / #{prettyPrintBytes (sum nodes, (node) -> node.tot_mem)} / #{prettyPrintBytes (sum nodes, (node) -> node.max_mem)}"


remove view project permission when the user has not other permissions

--- app/coffee/modules/admin/roles.coffee
+++ app/coffee/modules/admin/roles.coffee
@@ -410,7 +410,10 @@
                     activePermissions = _.sortBy(_.map(activePermissions, (t) ->
                         permission = angular.element(t).parents(".category-item").data("id")
                     ))
-                    activePermissions.push("view_project")
+
+                    if activePermissions.length
+                        activePermissions.push("view_project")
+
                     return activePermissions

                 target = angular.element(event.currentTarget)


Add in extra null check

Add in extra null check

--- app/coffee/DocManager.coffee
+++ app/coffee/DocManager.coffee
@@ -63,7 +63,7 @@

 	_findDocInFolder: (folder = {}, doc_id, currentPath) ->
 		for doc, i in folder.docs or []
-			if doc._id? and doc._id.toString() == doc_id.toString()
+			if doc?._id? and doc._id.toString() == doc_id.toString()
 				return {
 					doc: doc
 					mongoPath: "#{currentPath}.docs.#{i}"


small adjustment to prev commit

small adjustment to prev commit

--- app/js/services/market_service.coffee
+++ app/js/services/market_service.coffee
@@ -699,7 +699,7 @@

             deferred.resolve(true)

-    pull_market_status: (data = null, deferred) ->
+    pull_market_status: (data = null, deferred = null) ->
         self = data?.context or @
         market = self.market.get_actual_market()
         self.blockchain_api.market_status(market.asset_base_symbol, market.asset_quantity_symbol).then (result) ->
@@ -716,11 +716,11 @@
                     self.market.median_price = market.median_price = price
                     self.market.min_short_price = market.median_price
                     self.market.max_short_price = market.max_short_price = price * 10.0 / 9.0
-                deferred.resolve(true)
+                deferred.resolve(true) if deferred
             , (error) ->
-                deferred.reject(error)
+                deferred.reject(error) if deferred
         , (error) ->
-                deferred.reject(error)
+                deferred.reject(error) if deferred

 angular.module("app").service("MarketService", ["$q", "$interval", "$log", "$filter", "Utils", "Wallet", "WalletAPI", "Blockchain",  "BlockchainAPI",  MarketService])


fix(mixpanel): Correctly associate events with distinct_ids

--- src/flux/stores/analytics-store.coffee
+++ src/flux/stores/analytics-store.coffee
@@ -70,7 +70,10 @@
   track: (action, data={}) ->
     _.defer =>
       # send to the analytics service
-      @analytics.track(action, _.extend(data, accountId: AccountStore.current()?.id))
+      @analytics.track(action, _.extend(data, {
+        accountId: AccountStore.current()?.id
+        distinct_id: AccountStore.current()?.id
+      }))

       # send to the logs that we ship to LogStash
       console.debug(printToConsole, {action, data})


fix(zoom): Only set zoom to valid numeric values

--- src/flux/stores/workspace-store.coffee
+++ src/flux/stores/workspace-store.coffee
@@ -45,7 +45,8 @@
       @trigger()

     NylasEnv.config.observe 'core.workspace.interfaceZoom', (zoom) =>
-      require('electron').webFrame.setZoomFactor(zoom)
+      if zoom and _.isNumber(zoom)
+        require('electron').webFrame.setZoomFactor(zoom)

     NylasEnv.commands.add 'body', @_navigationCommands()


fixing lint error

fixing lint error

--- src/stores/exercise.coffee
+++ src/stores/exercise.coffee
@@ -31,7 +31,7 @@
   #filter out all editable tags
   editable = _.filter tags, (tag) ->
     _.reduce(FixedTags, (memo, fixedTag) ->
-      memo and !isFixedTagType(tag, fixedTag)
+      memo and not isFixedTagType(tag, fixedTag)
     , true)

   fixedArray = _.filter tags, (tag) -> editable.indexOf(tag) is -1


Remove unused require

Remove unused require

--- src/packages/collaboration/lib/participant-view.coffee
+++ src/packages/collaboration/lib/participant-view.coffee
@@ -1,4 +1,3 @@
-crypto = require 'crypto'
 {View} = require 'space-pen'

 class ParticipantView extends View


Remove homepage test for nexting on lab feature

--- apps/home/test/routes.coffee
+++ apps/home/test/routes.coffee
@@ -92,16 +92,6 @@
             @res.render.args[0][1].heroUnits.first().has 'link'
               .should.be.false() # Fallback is just welcome without the signup link

-      it 'calls next when user has personalized homepage lab feature', ->
-        Backbone.sync
-          .onCall 0
-          .yieldsTo 'success', []
-
-        user = new CurrentUser lab_features: ['Personalized Homepage']
-
-        routes.index(extend({ user: user}, @req), @res, @next)
-        @next.called.should.be.true()
-
   describe '#redirectToSignup', ->
     it 'redirects to signup', ->
       routes.redirectToSignup @req, @res


Fixed keys event bug.

Fixed keys event bug.

--- src/ubret/base_tool.coffee
+++ src/ubret/base_tool.coffee
@@ -21,9 +21,11 @@
     @trigger 'data-received', @childData()
     @

-  keys: (keys=[]) =>
+  keys: (keys=[], triggerEvent = true) =>
     @opts.keys = keys
-    @trigger 'keys-received', @opts.keys
+
+    if triggerEvent
+      @trigger 'keys-received', @opts.keys
     @

   selectIds: (ids=[], triggerEvent = true) =>
@@ -37,7 +39,6 @@
     @

   selectKeys: (keys=[], triggerEvent = true) =>
-    console.log 'selecting keys'
     if _.isArray keys
       @opts.selectedKeys = keys
     else
@@ -69,16 +70,17 @@

     @opts.parentTool = tool

-    @data(tool.childData())
-      .keys(tool.opts.keys)
-      .selectIds(tool.opts.selectedIds, false)
-      .selectKeys(tool.opts.selectedKeys, false)
-
     @opts.parentTool.on 'keys-received', @keys
     @opts.parentTool.on 'data-received', @data
     @opts.parentTool.on 'selection', @selectIds
     @opts.parentTool.on 'keys-selection', @selectKeys
     @opts.parentTool.on 'add-filter', @filters
+
+    @data(tool.childData())
+      .keys(tool.opts.keys, false)
+      .selectIds(tool.opts.selectedIds, false)
+      .selectKeys(tool.opts.selectedKeys, false)
+
     @trigger 'bound-to', tool
     @


Table widget testing

Table widget testing

--- widgets/table/table.coffee
+++ widgets/table/table.coffee
@@ -3,5 +3,5 @@
     onData: (data) ->
         console.log 'table widget data: ', data
         console.log 'table widget node: ', $(@node)
-        console.log 'table widget node height: ', $(@node).clientHeight()
-        console.log 'table widget parent: ', $(@node).parent()
+        console.log 'table widget node height: ', $(@node).clientHeight
+        #console.log 'table widget parent: ', $(@node).parent()


fixed by ternjs 0.9

fixed by ternjs 0.9

--- lib/atom-ternjs-provider.coffee
+++ lib/atom-ternjs-provider.coffee
@@ -43,11 +43,6 @@
     requestHandler: (options) ->
         return [] unless options?.editor? and options?.buffer? and options?.cursor?
         prefix = options.prefix
-
-        # .. crashes the server
-        if prefix.indexOf('..') != -1
-            @manager.documentation.hide()
-            return []

         if !@isValidPrefix(prefix) and !@force
             @manager.documentation.hide()


force trigger of hidden elements

force trigger of hidden elements

http://stackoverflow.com/a/8965804/614612

--- lib/client/autoform-file.coffee
+++ lib/client/autoform-file.coffee
@@ -81,6 +81,7 @@
           pct = fileObj.uploadProgress()
           if (pct >= 100)
             clearInterval(progress)
+            $(t.find('.js-value')).trigger('change')
           Session.set('uploaderProgress', pct)
         , 250)

@@ -107,6 +108,7 @@
         pct = fileObj.uploadProgress()
         if (pct >= 100)
           clearInterval(progress)
+          $(t.find('.js-value')).trigger('change')
         Session.set('uploaderProgress', pct)
       , 250)


apply changes from 5e3a301 and 680bff1

apply changes from 5e3a301 and 680bff1

--- both/methods/shift/shiftRequest.coffee
+++ both/methods/shift/shiftRequest.coffee
@@ -42,12 +42,12 @@
 								$pull: 'teams.$.declined': _id: userId
 								$addToSet: 'teams.$.participants': user

-							#TODO: if team.max reached -> close team
+							if team.participants.length == team.max - 1
+								Meteor.call 'closeTeam', shiftId, teamId

 							Meteor.call 'sendTeamUpdate', shiftId, teamId, 'participant'
 						else throw new Meteor.Error 500, TAPi18n.__('modal.shift.maximumReached')
-					else if team.pending.length == team.min - 1
-						#TODO: set condition to team.pending.length >= team.min - 1
+					else if team.pending.length >= team.min - 1
 						acceptedUsers = [ userId ]
 						hasTeamleader = false
 						chosenId = null


Fix typo

Fix typo

--- src/trix/controllers/level_2_input_controller.coffee
+++ src/trix/controllers/level_2_input_controller.coffee
@@ -336,7 +336,7 @@
     range.setEnd(staticRange.endContainer, staticRange.endOffset)
     range

-  # Event kelpers
+  # Event helpers

   dragEventHasFiles = (event) ->
     "Files" in (event.dataTransfer?.types ? [])


Fix notification window not hiding on start

--- assets/javascripts/application.coffee
+++ assets/javascripts/application.coffee
@@ -3,7 +3,7 @@
 #= require_tree ./dashing
 #= require_tree ../../widgets

-Dashing.on 'ready', ->
+$ ->
   Dashing.widget_margins ||= [5, 5]
   Dashing.widget_base_dimensions ||= [300, 360]
   Dashing.numColumns ||= 4


Fix coding style

Fix coding style

--- coffee/index.coffee
+++ coffee/index.coffee
@@ -32,32 +32,32 @@
   args.push '--items=' + options.items             if options.items
   args.push '--save-for-web'                       if yesOrNo options.saveForWeb
   args.push '--bounds=' + options.bounds           if options.bounds
-
+
   options.clean = yesOrNo options.clean
-
+
   through.obj (file, encoding, callback) ->
     if file.isStream()
       @emit 'error', new gutil.PluginError PLUGIN_NAME, 'Streaming not supported'
       return callback()
-
+
     # file_name.sketch is a directory (=3.0)
     # file_name.sketch is a file (>3.1)
-
+
     src = file.path
     tmp_dir = new temporary.Dir()

     # Output JSON
     if options.outputJSON
       args.push '--outputJSON=' + tmp_dir.path + '/' + options.outputJSON
-
+
     # SketchTool
     program = spawn cmnd, args.concat src, '--output=' + tmp_dir.path

     # Verbose Output
     if options.verbose
-        program.stdout.on 'data', (data) ->
-            gutil.log(data.toString())
-
+      program.stdout.on 'data', (data) ->
+        gutil.log data.toString()
+
     # return data
     program.stdout.on 'end', =>
       recursive tmp_dir.path, (err, files) =>


retain form text if it is provided

retain form text if it is provided

--- static/coffee/temba.coffee
+++ static/coffee/temba.coffee
@@ -381,12 +381,17 @@
       @ele.find('.loader').show()

       modal = @
-
       modal.submitText = modal.ele.find('.primary').text()

       fetchPJAXContent(@url, "#active-modal .fetched-content",
         onSuccess: ->
           modal.ele.find('.loader').hide()
+
+          # if the form comes back with a save button defer to that
+          submitText = $(".form-group button[type='submit']").text()
+          if submitText
+            modal.submitText = submitText
+
           modal.ele.find(".primary").text(modal.submitText)
           modal.focusFirstInput()
           if modal.listeners and modal.listeners.onFormLoaded


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/animation.coffee
+++ src/animation.coffee
@@ -22,7 +22,7 @@
       active: (name) ->
         if (name != undefined)
           if data.animations[name]
-            currentSprite = data.animations[name].frames[0]
+            currentSprite = data.animations[name].frames[0]
         else
           return activeAnimation


Only initialize once

Only initialize once

The caller may sometimes call initialize multiple times.  If we re-init
the loader then event listeners on the api channel will be called multiple times

--- src/api/index.coffee
+++ src/api/index.coffee
@@ -5,8 +5,14 @@

 channel = new EventEmitter2 wildcard: true

+# HACK - WORKAROUND
+# MediaBodyView.prototype.initializeConceptCoach calls this multiple times
+# (triggered by back-button and most perhaps search)
+IS_INITIALIZED = false
+
 initialize = (baseUrl) ->
   settings.baseUrl ?= baseUrl
-  loader(channel, settings)
+  loader(channel, settings) unless IS_INITIALIZED
+  IS_INITIALIZED = true

 module.exports = {loader, settings, initialize, channel}


Dart support

Dart support

--- assets/scripts/travis.coffee
+++ assets/scripts/travis.coffee
@@ -111,6 +111,7 @@
     d:           'D'
     julia:       'Julia'
     csharp:      'C#'
+    dart:        'Dart'
   }

   QUEUES: [


don't allow to pass function via data- attribute


Only operate on valid markers.

Only operate on valid markers.

--- lib/info/quick_info_view.coffee
+++ lib/info/quick_info_view.coffee
@@ -42,6 +42,7 @@

   withValidMarker: (editor, marker, callback) =>
     return unless marker.getProperties().isDartMarker
+    return unless marker.isValid()

     selectedBufferRange = editor.getSelectedBufferRange()
     markerRange = marker.getBufferRange()


exportable

exportable

--- src/async-xml.coffee
+++ src/async-xml.coffee
@@ -1,108 +1,144 @@
-{ EventEmitter } = require 'events'
+uglify = require 'uglify-js'

-# helper
-
-indent = ({level, opts:{pretty}}) ->
-    return "" unless pretty
-    pretty = "  " if pretty is on
-    output = ""
-    for i in [0...level]
-        output += pretty
-    return output
+# CoffeeScript-generated JavaScript may contain anyone of these; but when we
+# take a function to string form to manipulate it, and then recreate it through
+# the `Function()` constructor, it loses access to its parent scope and
+# consequently to any helpers it might need. So we need to reintroduce these
+# inside any "rewritten" function.
+coffeescript_helpers = """
+  var __slice = Array.prototype.slice;
+  var __hasProp = Object.prototype.hasOwnProperty;
+  var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
+  var __extends = function(child, parent) {
+    for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
+    function ctor() { this.constructor = child; }
+    ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype;
+    return child; };
+  var __indexOf = Array.prototype.indexOf || function(item) {
+    for (var i = 0, l = this.length; i < l; i++) {
+      if (this[i] === item) return i;
+    } return -1; };
+"""

-new_attrs = (attrs) ->
-    strattrs = for k, v of attrs
-        if v?
-            v = "\"#{v}\"" unless typeof v is 'number'
-            "#{k}=#{v}"
-        else "#{k}"
-    strattrs.unshift '' if strattrs.length
-    strattrs.join ' '
+skeleton = ->
+    { EventEmitter } = require 'events'

-# main logic
+    # helper

-new_tag = (name, opts) ->
-    buffer = []
-    @pending.push tag = new Tag name, opts
-    tag.self.on 'data', pipe = (data) =>
-        if @pending[0] is tag
-            @emit 'data', data
-        else
-            buffer.push data
+    indent = ({level, opts:{pretty}}) ->
+        return "" unless pretty
+        pretty = "  " if pretty is on
+        output = ""
+        for i in [0...level]
+            output += pretty
+        return output

-    tag.self.on 'end', on_end = (data) =>
-        buffer.push data unless data is undefined
-        if @pending[0] is tag
-            if tag.self.pending.length
-                (pender = tag.self.pending[0].self).once 'end', =>
-                    on_end()
-                    @emit 'end' unless @pending.length
+
+    new_attrs = (attrs) ->
+        strattrs = for k, v of attrs
+            if v?
+                v = "\"#{v}\"" unless typeof v is 'number'
+                "#{k}=#{v}"
+            else "#{k}"
+        strattrs.unshift '' if strattrs.length
+        strattrs.join ' '
+
+    # main logic
+
+    new_tag = (name, opts) ->
+        buffer = []
+        @pending.push tag = new Tag name, opts
+        tag.self.on 'data', pipe = (data) =>
+            if @pending[0] is tag
+                @emit 'data', data
             else
-                if tag.self.buffer.length
-                    buffer = buffer.concat tag.self.buffer
-                    tag.self.buffer = []
-                @pending = @pending.slice(1)
-                tag.self.removeListener 'data', pipe
-                tag.self.removeListener 'end', on_end
-                for data in buffer
-                    @emit 'data', data
-        else
-            for known, i in @pending
-                if tag is known
-                    @pending = @pending.slice(0,i).concat @pending.slice i+1
-                    before = @pending[i-1].self
-                    before.buffer = before.buffer.concat buffer
+                buffer.push data
+
+        tag.self.on 'end', on_end = (data) =>
+            buffer.push data unless data is undefined
+            if @pending[0] is tag
+                if tag.self.pending.length
+                    (pender = tag.self.pending[0].self).once 'end', =>
+                        on_end()
+                        @emit 'end' unless @pending.length
+                else
+                    if tag.self.buffer.length
+                        buffer = buffer.concat tag.self.buffer
+                        tag.self.buffer = []
+                    @pending = @pending.slice(1)
                     tag.self.removeListener 'data', pipe
                     tag.self.removeListener 'end', on_end
-                    return
-            throw new Error("this shouldn't happen D:")
-    return tag
+                    for data in buffer
+                        @emit 'data', data
+            else
+                for known, i in @pending
+                    if tag is known
+                        @pending = @pending.slice(0,i).concat @pending.slice i+1
+                        before = @pending[i-1].self
+                        before.buffer = before.buffer.concat buffer
+                        tag.self.removeListener 'data', pipe
+                        tag.self.removeListener 'end', on_end
+                        return
+                throw new Error("this shouldn't happen D:")
+        return tag

-# classes
+    # classes

-class Tag extends EventEmitter
-    constructor: (@name, {@level, @opts}) ->
-        @buffer = [] # after this tag all children emitted data
-        @pending = [] # no open child tag
-        @attrs.self = this
-        @attrs.end = (attrs) => @attrs(attrs).end()
-        return @attrs
+    class Tag extends EventEmitter
+        constructor: (@name, {@level, @opts}) ->
+            @buffer = [] # after this tag all children emitted data
+            @pending = [] # no open child tag
+            @attrs.self = this
+            @attrs.end = (attrs) => @attrs(attrs).end()
+            return @attrs

-    attrs: (attrs = {}) =>
-        @headers = "<#{@name}#{new_attrs attrs}"
-        return this
+        attrs: (attrs = {}) =>
+            @headers = "<#{@name}#{new_attrs attrs}"
+            return this

-    tag: (name) =>
-        if @headers
-            @emit 'data', "#{indent this}#{@headers}>"
-            delete @headers
-        new_tag.call this, name, opts:@opts, level:@level+1
+        tag: (name) =>
+            if @headers
+                @emit 'data', "#{indent this}#{@headers}>"
+                delete @headers
+            new_tag.call this, name, opts:@opts, level:@level+1

-    end: () =>
-        if @headers
-            data = "#{indent this}#{@headers}/>"
-        else
-            data = "#{indent this}</#{@name}>"
-        @emit 'end', data
+        end: () =>
+            if @headers
+                data = "#{indent this}#{@headers}/>"
+            else
+                data = "#{indent this}</#{@name}>"
+            @emit 'end', data

-class Builder extends EventEmitter
-    constructor: (@opts = {}) ->
-        @buffer = [] # for child output
-        @pending = [] # no open child tag
-        @opts.pretty ?= off
-        @level = @opts.level ? 0
+    class Builder extends EventEmitter
+        constructor: (@opts = {}) ->
+            @buffer = [] # for child output
+            @pending = [] # no open child tag
+            @opts.pretty ?= off
+            @level = @opts.level ? 0

-    tag: (name) =>
-        new_tag.call this, name, opts:@opts, level:@level
+        tag: (name) =>
+            new_tag.call this, name, opts:@opts, level:@level

-    end: () =>
-        @emit 'end' unless @pending.length
+        end: () =>
+            @emit 'end' unless @pending.length

-# exports
+    # exports

-module.exports = { Tag, Builder }
+    module?.exports? { Tag, Builder }
+    null

+
+# load skeleton code as module
+module.exports = (exports) -> module.exports = exports
+do skeleton # bootstrap
+
+# Stringify the skeleton and unwrap it from its enclosing `function(){}`, then
+# add the CoffeeScript helpers.
+module.exports.skeleton = uglify coffeescript_helpers + String(skeleton)
+    .replace(/function\s*\(.*\)\s*\{/, '')
+    .replace(/return null;\s*\}$/, '')
+


Kitecontroller:run: make sure it works with both new and old kites correctly

--- client/Main/kite/kitecontroller.coffee
+++ client/Main/kite/kitecontroller.coffee
@@ -97,6 +97,10 @@
       command = options
       options = {}

+    if "string" is typeof options.withArgs
+      command = options.withArgs
+      options.withArgs = {}
+
     options.method   or= "exec"
     options.kiteName or= "os"

@@ -119,7 +123,7 @@
       else @getKite options.kiteName, correlationName

     if command
-      options.withArgs = command
+      options.withArgs.command = command
     else
       #related to this this empty object kite response returns "An error occured: Invalid argument,
       # [string] expected." error
@@ -137,7 +141,7 @@
       then kite.vmOn()
       else Promise.cast()

-    ok.then =>
+    ok.then ->
       kite.tell options.method, options.withArgs

     .nodeify (err, response) =>


fixed setting page title

fixed setting page title

--- client/app/MainApp/kodingrouter.coffee
+++ client/app/MainApp/kodingrouter.coffee
@@ -1,4 +1,8 @@
 class KodingRouter extends KDRouter
+
+  nicenames = {
+    StartTab  : 'Develop'
+  }

   constructor:(@defaultRoute)->

@@ -66,6 +70,7 @@
     KD.getSingleton('groupsController').changeGroup group, (err)=>
       if err then new KDNotificationView title: err.message
       else
+        @setPageTitle nicenames[app] ? app
         appManager = KD.getSingleton "appManager"
         appManager.open app
         appManager.tell app, 'handleQuery', query
@@ -99,6 +104,8 @@
   openContent:(name, section, models, route, query, passOptions=no)->
     method   = 'createContentDisplay'
     [models] = models  if Array.isArray models
+
+    @setPageTitle @getContentTitle models

     # HK: with passOptions false an application only gets the information
     # 'hey open content' with this model. But some applications require
@@ -401,4 +408,4 @@
             KD.remote.cacheable routeInfo.params.name, (err, [model], name)=>
               open.call this, routeInfo, model

-    routes+    routes


Right, don't overwrite the imported `path`.

--- lib/merge-conflicts-view.coffee
+++ lib/merge-conflicts-view.coffee
@@ -21,9 +21,9 @@
         @span class: 'pull-right icon icon-unfold', click: 'restore', 'Show'
       @div outlet: 'body', =>
         @ul class: 'block list-group', outlet: 'pathList', =>
-          for {path, message} in state.conflicts
+          for {path: p, message} in state.conflicts
             @li click: 'navigate', class: 'list-item navigate', =>
-              @span class: 'inline-block icon icon-diff-modified status-modified path', path
+              @span class: 'inline-block icon icon-diff-modified status-modified path', p
               @div class: 'pull-right', =>
                 @span class: 'inline-block text-subtle', message
                 @progress class: 'inline-block', max: 100, value: 0


fix: atom beautify no analytics

fix: atom beautify no analytics

--- configs/atom.cson
+++ configs/atom.cson
@@ -1,4 +1,6 @@
 "*":
+  "atom-beautify":
+    general: {}
   core:
     telemetryConsent: "limited"
     themes: [


Improved sort, only use lower if attribute is a string.

--- app/assets/javascripts/app/models/_application_model.js.coffee
+++ app/assets/javascripts/app/models/_application_model.js.coffee
@@ -553,8 +553,11 @@
       return '' if item[ attribute ] is undefined
       return '' if item[ attribute ] is null

-      # return value
-      item[ attribute ].toLowerCase()
+      # return value if string
+      if item[ attribute ].toLowerCase
+        return item[ attribute ].toLowerCase()
+
+      item[ attribute ]
     )

   @_order: ( collection, attribute ) ->


Slightly mute default foreground color

Slightly mute default foreground color

--- src/coffee/main.coffee
+++ src/coffee/main.coffee
@@ -4,7 +4,7 @@

   smilesMode = true

-  foregroundColor = 'ba5353'
+  foregroundColor = 'ce3838'
   backgroundColor = '5f0000'
   compoundName = 'caffeine'


Change canvas dimensions if plot_{width,height} changed

--- bokehjs/src/coffee/common/plot.coffee
+++ bokehjs/src/coffee/common/plot.coffee
@@ -176,6 +176,12 @@
     render: (force_canvas=false) ->
       logger.trace("Plot.render(force_canvas=#{force_canvas})")

+      width = @mget("plot_width")
+      height = @mget("plot_height")
+
+      if @canvas.get("canvas_width") != width or @canvas.get("canvas_height") != height
+        @canvas._set_dims([width, height], trigger=false)
+
       super()
       @canvas_view.render(force_canvas)


Maintain order of renderers when rendering levels

--- bokehjs/src/coffee/common/plot.coffee
+++ bokehjs/src/coffee/common/plot.coffee
@@ -246,10 +246,15 @@
         ctx.clip()
         ctx.beginPath()

+      indices = {}
+      for renderer, i in @mget("renderers")
+        indices[renderer.id] = i
+      sortKey = (renderer) -> indices[renderer.model.id]
+
       for level in levels
-        renderers = @levels[level]
-        for k, v of renderers
-          v.render()
+        renderers = _.sortBy(_.values(@levels[level]), sortKey)
+        for renderer in renderers
+          renderer.render()

       ctx.restore()


Little fix for nested forms

Little fix for nested forms

--- app/assets/javascripts/rails_admin/ra.nested-form-hooks.coffee
+++ app/assets/javascripts/rails_admin/ra.nested-form-hooks.coffee
@@ -50,3 +50,8 @@
     add_button = toggler.next()
     add_button.addClass('add_nested_fields').html(add_button.data('add-label'))

+  # Removing all reuired attributes from deleted child form to bypass browser validations.
+  field.find('[required]').each ->
+    #console.log $(this).attr('name')
+    $(this).removeAttr('required')
+    return


search bar select on close

search bar select on close

--- app/assets/javascripts/revised/sections/bike_search_bar.coffee
+++ app/assets/javascripts/revised/sections/bike_search_bar.coffee
@@ -88,7 +88,8 @@
       placeholder: $query_field.attr('placeholder') # Pull placeholder from HTML
       dropdownParent: $('.bikes-search-form') # Append to search for for easier css access
       templateResult: formatSearchText # let custom formatter work
-      escapeMarkup: (markup) -> markup # Allow our
+      selectOnClose: true # Select the options when the dropdown is closed (e.g. clicked outside)
+      escapeMarkup: (markup) -> markup # Allow our fancy display of options
       ajax:
         url: '/api/autocomplete'
         dataType: 'json'


Add debug logging

Add debug logging

--- client/services/dropzoneservice.coffee
+++ client/services/dropzoneservice.coffee
@@ -30,6 +30,7 @@
 handleDropzoneEvent = (event, dropzone, args...) =>
   dropzoneLogger.debug("#{event}:", args)
   if event in ["addedfile", "addedfiles", "removedfile"]
+    logger.debug("Dropzone changed, notifying dependents")
     dep = getDependency(dropzone)
     dep.changed()


Clean up the syntax highlighting

Clean up the syntax highlighting

--- lib/space-pen-extensions.coffee
+++ lib/space-pen-extensions.coffee
@@ -35,29 +35,20 @@
         @colorizedCodeBlock 'example-html', 'text.xml', beautifyHtml(html)

   colorizedCodeBlock: (cssClass, grammarScopeName, code) ->
-    # FIXME: this is editor abuse. I just want the tokenized html.
-    editor = new Editor(mini: true)
-    editor.setText(code)
+    editorBlock = $$ ->
+      @pre class: cssClass+' editor-colors editor', ''

-    editorBlock = $$ ->
-      @div class: cssClass+' editor mini', ''
-
-    refreshHtml = (timeout) ->
-      fn = ->
-        html = editor.htmlForScreenRows(0, editor.getLineCount()-1)
-        editorBlock.html(html)
-      # FIXME: does not colorize without the timeout...
-      if timeout then setTimeout(fn, 10) else fn()
-    refreshHtml() # initially set the null-grammar'd code
+    refreshHtml = (grammar) ->
+      editorBlock.empty()
+      for tokens in grammar.tokenizeLines(code)
+        editorBlock.append(Editor.buildLineHtml({tokens, text: code}))

     if grammar = syntax.grammarForScopeName(grammarScopeName)
-      editor.setGrammar(grammar)
-      refreshHtml(true)
+      refreshHtml(grammar)
     else
       syntax.on 'grammar-added grammar-updated', (grammar) ->
         return unless grammar.scopeName == grammarScopeName
-        editor.setGrammar(grammar)
-        refreshHtml(true)
+        refreshHtml(grammar)

     @subview '__', editorBlock


use same class name as element name

use same class name as element name

--- lib/status-bar-tile-view.coffee
+++ lib/status-bar-tile-view.coffee
@@ -1,10 +1,12 @@
 {Disposable} = require 'atom'
 path = require 'path'
+
+element_name = 'waka-status-bar' + Date.now()

 class StatusBarTileView extends HTMLElement

   init: ->
-    @classList.add('wakatime-status-bar-tile', 'inline-block')
+    @classList.add(element_name, 'inline-block')

     @link = document.createElement('a')
     @link.classList.add('inline-block')
@@ -38,4 +40,4 @@
     @tooltip = atom.tooltips.add this,
       title: text

-module.exports = document.registerElement('wakatime-status-bar-tile' + Date.now(), prototype: StatusBarTileView.prototype, extends: 'div')
+module.exports = document.registerElement(element_name, prototype: StatusBarTileView.prototype, extends: 'div')


Add dispose method no-op to fit panel pattern

--- lib/system-windows-panel.coffee
+++ lib/system-windows-panel.coffee
@@ -49,6 +49,9 @@
       @setRegistration WinShell.folderContextMenu, e.target.checked
       @setRegistration WinShell.folderBackgroundContextMenu, e.target.checked

+  dispose: ->
+    return
+
   setRegistration: (option, shouldBeRegistered) ->
     if shouldBeRegistered
       option.register ->


Minor change to the kernel

Minor change to the kernel

--- library/gearing/kernel.coffee
+++ library/gearing/kernel.coffee
@@ -53,9 +53,9 @@
         @title = "flames"
         @version = "0.1.0"
         @codename = "cripple"
-        arts = [@title, "larry3d"]
+        header = [@title, "larry3d"]
         idents = [@version, @codename]
-        asciify arts..., (error, art) =>
+        asciify header..., (error, art) =>
             util.puts art.toString().blue
             identify = "Running kernel %s, codename %s"
             logger.info(identify.grey, idents...)


minor syntax convs in the krn

minor syntax convs in the krn

--- library/nucleus/kernel.coffee
+++ library/nucleus/kernel.coffee
@@ -258,8 +258,8 @@
     # scoping configuration in order to obtain the data necessary
     # for instantiating, configuring and launching up the servers.
     startupHttpsServer: ->
-        assert server = nconf.get "server"
-        assert hostname = nconf.get "server:host"
+        assert server = nconf.get "server" or {}
+        assert hostname = nconf.get "server:host" or 0
         assert _.isNumber(server.https), "no HTTPS port"
         assert _.isObject options = @resolveSslDetails()
         running = "Running HTTPS server at %s".magenta
@@ -267,8 +267,8 @@
         logger.info running.underline, location.underline
         @secure = https.createServer options, @connect
         assert _.isObject @domain; @domain.add @secure
-        @secure.listen server.https, hostname
-        @secure.on "connection", (socket) ->
+        do -> @secure.listen server.https, hostname
+        return @secure.on "connection", (socket) ->
             return socket.setNoDelay yes

     # Setup and launch either HTTP or HTTPS servers to listen at
@@ -276,16 +276,16 @@
     # scoping configuration in order to obtain the data necessary
     # for instantiating, configuring and launching up the servers.
     startupHttpServer: ->
-        assert server = nconf.get "server"
-        assert hostname = nconf.get "server:host"
+        assert server = nconf.get "server" or {}
+        assert hostname = nconf.get "server:host" or 0
         assert _.isNumber(server.http), "no HTTP port"
         running = "Running HTTP server at %s".magenta
         location = "#{hostname}:#{server.http}".toString()
         logger.info running.underline, location.underline
         @server = http.createServer @connect, undefined
         assert _.isObject @domain; @domain.add @server
-        @server.listen server.http, hostname
-        @server.on "connection", (socket) ->
+        do -> @server.listen server.http, hostname
+        return @server.on "connection", (socket) ->
             return socket.setNoDelay yes

     # Setup and attach Socket.IO handlers to each of the servers.


minor convs

minor convs

--- library/nucleus/kernel.coffee
+++ library/nucleus/kernel.coffee
@@ -338,8 +338,8 @@
     # operate correctly. You are encouraged to override this method
     # to provide a Connect setup procedure to your own liking, etc.
     setupConnectPipeline: ->
-        @connect = connect()
-        @connectStaticAssets()
+        assert @connect = connect()
+        assert @connectStaticAssets()
         threshold = plumbs.threshold this
         @connect.use @threshold = threshold
         @connect.use @query = connect.query()


Minor changes.

Minor changes.

--- tasks/markdown_jade.coffee
+++ tasks/markdown_jade.coffee
@@ -211,11 +211,9 @@

       leaveDest = "#{leaveDest}#{ext}"

-      grunt.log.writeln 'mkdirp', path.dirname(leaveDest)
+      grunt.log.debug 'mkdirp', path.dirname(leaveDest)

       mkdirp.sync path.dirname(leaveDest)
-
-      grunt.log.writeln 'last', _.last leavePath

       grunt.file.copy tpl, leaveDest,
         process: (contents, path) ->


Precompile bootstrap.less

Precompile bootstrap.less

--- build/tasks/prebuild-less-task.coffee
+++ build/tasks/prebuild-less-task.coffee
@@ -1,9 +1,24 @@
 path = require 'path'
 fs = require 'fs'
-
+temp = require('temp').track()
 LessCache = require 'less-cache'

 module.exports = (grunt) ->
+  {rm} = require('./task-helpers')(grunt)
+
+  compileBootstrap = ->
+    appDir = grunt.config.get('atom.appDir')
+    bootstrapLessPath = path.join(appDir, 'static', 'bootstrap.less')
+    bootstrapCssPath = path.join(appDir, 'static', 'bootstrap.css')
+
+    lessCache = new LessCache
+      cacheDir: temp.mkdirSync('atom-less-cache')
+      resourcePath: path.resolve('.')
+
+    bootstrapCss = lessCache.readFileSync(bootstrapLessPath)
+    grunt.file.write(bootstrapCssPath, bootstrapCss)
+    rm(bootstrapLessPath)
+
   grunt.registerMultiTask 'prebuild-less', 'Prebuild cached of compiled LESS files', ->
     prebuiltConfigurations = [
       ['atom-dark-ui', 'atom-dark-syntax']
@@ -78,3 +93,5 @@
       for file in themeMains
         grunt.verbose.writeln("File #{file.cyan} created in cache.")
         cssForFile(file)
+
+    compileBootstrap()


Spliced: toggle play/pause on click.

Spliced: toggle play/pause on click.

--- coffee/src/shells/spliced.shell.coffee
+++ coffee/src/shells/spliced.shell.coffee
@@ -30,6 +30,10 @@

   className: @classNameExtend 'spliced-shell'
+
+
+  events: => _.extend super,
+    'click .click-capture': => @togglePlayPause()

   defaults: => _.extend super,
@@ -84,6 +88,7 @@
       @shellViews[index].pause()
       @hideView index
     @showView 0
+    @$el.append $('<div>').addClass('click-capture')
     @


Rails 5.1 removes id from form fields

Rails 5.1 removes id from form fields

--- vendor/assets/javascripts/fustrate/generic_form.coffee
+++ vendor/assets/javascripts/fustrate/generic_form.coffee
@@ -9,7 +9,7 @@
   _reloadUIElements: =>
     super

-    for domObject in $('[name][id]', @root)
+    for domObject in $('[name]', @root)
       element = $ domObject
       name = element.prop 'name'


Convert async scenarios to use should.

Convert async scenarios to use should.

--- src/Witness/Scripts/specs/dsl/async.coffee
+++ src/Witness/Scripts/specs/dsl/async.coffee
@@ -8,8 +8,8 @@
 	when: ->
 		@func = @target.async (->)

-	then: ->
-		@func.async?
+	then:
+		func: async: should.notBe undefined
 },
 {
 	given: ->
@@ -21,5 +21,6 @@
 		# specify the timeout
 		@func = @target.async (->), 2000

-	then: -> @func.async.timeout == 2000
+	then:
+		func: async: timeout: should.be 2000
 }


coordinator: Actually support --ignore

coordinator: Actually support --ignore

Was there in options but did not do anything

--- src/coordinator.coffee
+++ src/coordinator.coffee
@@ -470,7 +470,9 @@
         componentName = graph.processes[role].component
         console.log "\t#{role}(#{componentName})"

-      options.only = rolesWithComponent
+      rolesToSetup = rolesWithComponent.concat([]).filter (r) ->
+        return r not in options.ignore
+      options.only = rolesToSetup

       setupParticipants = (setupCallback) =>
         participantStartConcurrency = 10


Fix for role name being reset on server restart

--- packages/rocketchat-authorization/server/startup.coffee
+++ packages/rocketchat-authorization/server/startup.coffee
@@ -62,4 +62,4 @@
 	]

 	for role in defaultRoles
-		RocketChat.models.Roles.createOrUpdate role.name, role.scope, role.description, true
+		RocketChat.models.Roles.upsert { _id: role.name }, { $setOnInsert: { scope: role.scope, description: role.description || '', protected: true } }


Fix console output

Fix console output

--- hubot/scripts/docker.coffee
+++ hubot/scripts/docker.coffee
@@ -31,3 +31,6 @@
     if error
       msg.send error
       msg.send stderr
+    else
+      if !!stdout
+        msg.send '```' + stdout + '```'


Improve input suggestions template readability.

--- services/web/public/coffee/components/inputSuggestions.coffee
+++ services/web/public/coffee/components/inputSuggestions.coffee
@@ -43,12 +43,32 @@
 			inputType: "@?"
 			inputRequired: "=?"
 		controller: inputSuggestionsController
-		template: """
-

-

-
-

-				<input type="text" ng-focus="$ctrl.handleFocus()" ng-keyDown="$ctrl.handleKeyDown($event)" ng-blur="$ctrl.handleBlur()" ng-model="$ctrl.localNgModel" ng-model-options="$ctrl.localNgModelOptions" ng-model-options="{ debounce: 50 }" class="form-control input-suggestions-main" ng-attr-id="{{ ::$ctrl.inputId }}" ng-attr-placeholder="{{ ::$ctrl.inputPlaceholder }}" ng-attr-type="{{ ::$ctrl.inputType }}" ng-attr-name="{{ ::$ctrl.inputName }}" ng-required="::$ctrl.inputRequired">
-

-			"""
+		template: [
+				'
',
+					'
',
+						'',
+						'',
+						'',
+						'',
+					'
',
+					'<input type="text"',
+						' class="form-control input-suggestions-main"',
+						' ng-focus="$ctrl.handleFocus()"',
+						' ng-keyDown="$ctrl.handleKeyDown($event)"',
+						' ng-blur="$ctrl.handleBlur()"',
+						' ng-model="$ctrl.localNgModel"',
+						' ng-model-options="$ctrl.localNgModelOptions"',
+						' ng-model-options="{ debounce: 50 }"',
+						' ng-attr-id="{{ ::$ctrl.inputId }}"',
+						' ng-attr-placeholder="{{ ::$ctrl.inputPlaceholder }}"',
+						' ng-attr-type="{{ ::$ctrl.inputType }}"',
+						' ng-attr-name="{{ ::$ctrl.inputName }}"',
+						' ng-required="::$ctrl.inputRequired">',
+				'
'
+				].join ""
+
 	}


character limit widget for new proposals

not enforced server side, so this is sort of a soft limit

--- @client/new_proposal.coffee
+++ @client/new_proposal.coffee
@@ -144,24 +144,35 @@

             proposal_fields.name

-          AutoGrowTextArea
-            id:"#{cluster_slug}-name"
+
+
+          CharacterCountTextInput
+            id: "#{cluster_slug}-name"
+            maxLength: 180
             name:'name'
-            pattern:'^.{3,}'
+            pattern: '^.{3,}'
             'aria-label': t('proposal_summary_instr')
             placeholder: t('proposal_summary_instr')
-            required:'required'
+            required: 'required'
+
+            count_style:
+              position: 'absolute'
+              right: 0
+              top: -18
+              fontSize: 14
+
             style:
               fontSize: 22
               width: w
               border: "1px solid #ccc"
               outline: 'none'
               padding: '6px 8px'
-              resize: 'none'
               fontWeight: 600
               #textDecoration: 'underline'
               #borderBottom: "1px solid #444"
-              color: '#000'
+              color: '#000'
+              minHeight: 75
+              resize: 'vertical'

         DIV
           style:


sorting translations by id

sorting translations by id

--- @client/translations.coffee
+++ @client/translations.coffee
@@ -44,7 +44,6 @@
       else
         translation.push part

-    translation
   else
     translation = message

@@ -203,6 +202,8 @@
     local = fetch 'translations'

     all_langs = ( [k,v] for k,v of translations.available_languages when k != DEVELOPMENT_LANGUAGE)
+    if current_user.is_super_admin
+      all_langs.push ['pseudo-en', "Pseudo English (for testing)"]

     if !local.translating_lang
       if subdomain.lang && subdomain.lang != 'en'
@@ -348,15 +349,17 @@
     updated_translations = get_temporary_translations(lang, @props.key)

-    sections = {}
-    for name in to_translate
-      sp = name.split('.')
-      if sp.length > 1
-        sections[sp[0]] ||= []
-        sections[sp[0]].push name
-      else
-        sections.misc ||= []
-        sections.misc.push name
+    sections = {"all": to_translate}
+    # sections = {}
+    # for name in to_translate
+    #   sp = name.split('.')
+    #   if sp.length > 1
+    #     sections[sp[0]] ||= []
+    #     sections[sp[0]].push name
+    #   else
+    #     sections.misc ||= []
+    #     sections.misc.push name
+

     current_user = fetch '/current_user'

@@ -393,7 +396,7 @@

         for section, names of sections
-
+          names.sort()
           for name in names
             do (name) =>
               no_id = name == native_messages[name].txt


Improved constructor. Added default values.

--- app/assets/javascripts/app/controllers/_application_controller_form.js.coffee
+++ app/assets/javascripts/app/controllers/_application_controller_form.js.coffee
@@ -8,8 +8,14 @@
     @handlers.push @_showHideToggle
     @handlers.push @_requiredMandantoryToggle

+    # set empty class attributes if needed
     if !@form
       @form = @formGen()
+    if !@model
+      @model = {}
+    @attributes = []
+
+    # if element is given, prepend form to it
     if @el
       @el.prepend( @form )


Also disable textarea's on form disable.

--- app/assets/javascripts/app/controllers/_application_controller_form.js.coffee
+++ app/assets/javascripts/app/controllers/_application_controller_form.js.coffee
@@ -2482,7 +2482,7 @@
       App.Log.debug 'ControllerForm', 'disable form...', lookupForm

       # set forms to read only during communication with backend
-      lookupForm.find('button, input, select').attr('readonly', true)
+      lookupForm.find('button, input, select, textarea').attr('readonly', true)

       # disable additionals submits
       lookupForm.find('button.btn').attr('disabled', true)
@@ -2499,7 +2499,7 @@
       App.Log.debug 'ControllerForm', 'enable form...', lookupForm

       # enable fields again
-      lookupForm.find('button, input, select').attr('readonly', false)
+      lookupForm.find('button, input, select, textarea').attr('readonly', false)

       # enable submits again
       lookupForm.find('button.btn').attr('disabled', false)


Fix URI encoding with Japanese characters

--- server/controllers/board_controller.coffee
+++ server/controllers/board_controller.coffee
@@ -25,7 +25,7 @@
       res.redirect "/board"
     else
       req.flash 'info', 'Successfully added board!'
-      res.redirect "/board/#{req.body.boardName}"
+      res.redirect encodeURI("/board/#{req.body.boardName}")

 boardController.view = (req, res, next) ->
   return next() if not req.params.boardName?
@@ -88,7 +88,7 @@
         )
       ]
       , (err, result) ->
-        res.redirect "/board/#{req.params.boardName}"
+        res.redirect encodeURI("/board/#{req.params.boardName}")
       )

 boardController.viewThread = (req, res, next) ->
@@ -154,8 +154,8 @@
             _next()
         )
       ]
-      , (err, result) ->
-          res.redirect "/board/#{req.params.boardName}/thread/#{req.params.id}#p#{currentPostCount}"
+      , (err, result) ->
+          res.redirect encodeURI("/board/#{req.params.boardName}/thread/#{req.params.id}#p#{currentPostCount}")
       )

 module.exports = boardController


fixes 3482

fixes 3482

--- common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee
+++ common/lib/xmodule/xmodule/js/src/combinedopenended/display.coffee
@@ -392,6 +392,7 @@
     else
       @submit_button.show()
       @submit_button.attr('disabled', false)
+      @answer_area.attr("disabled", false)
       @gentle_alert response.error

   confirm_save_answer: (event) =>


Made RenameItemModal less coupled to specific models

--- admin/static/coffee/ui_components/modals.coffee
+++ admin/static/coffee/ui_components/modals.coffee
@@ -169,14 +169,18 @@
     error_template: require('../../handlebars/error_input.hbs')
     class: 'rename-item-modal'

-    initialize: (model, options) =>
-        super()
+    initialize: (options) =>
+        super
         if @model instanceof models.Table
             @item_type = 'table'
         else if @model instanceof models.Database
             @item_type = 'database'
         else if @model instanceof models.Server
             @item_type = 'server'
+        else if options.item_type?
+            @item_type = options.item_type
+        else
+            throw "Rename *what* kind of item?"

     render: ->
         super
@@ -189,7 +193,7 @@
         @$('#focus_new_name').focus()

-    on_submit: ->
+    on_submit: =>
         super
         @old_name = @model.get('name')
         @formdata = util.form_data_as_object($('form', @$modal))
@@ -207,13 +211,13 @@

         # Check if already use
         if no_error is true
-            if @model instanceof models.Table
+            if @item_type == "table"
                 query = r.db(system_db).table('table_config').get(@model.get('id')).update
                     name: @formdata.new_name
-            else if @model instanceof model.Database
+            else if @item_type == "database"
                 query = r.db(system_db).table('db_config').get(@model.get('id')).update
                     name: @formdata.new_name
-            else if @model instanceof model.Server
+            else if @item_type == "server"
                 query = r.db(system_db).table('server_config').get(@model.get('id')).update
                     name: @formdata.new_name


Issue #65: add a support of classes to settings of the Atom plugin

--- tools/atom-plugin/language-micro/settings/language-micro.cson
+++ tools/atom-plugin/language-micro/settings/language-micro.cson
@@ -11,5 +11,8 @@
 		'
 		'decreaseIndentPattern': '(?x)
 			^\\s*;
+			| ^\\s*\\[\\];
+			| ^\\s*\\{\\};
+			| ^\\s*this;
 			| ^\\s*\\)
 		'


New implementation of tree with recaltulate center and animation

--- app/assets/javascripts/admin/moi_tree.js.coffee
+++ app/assets/javascripts/admin/moi_tree.js.coffee
@@ -9,6 +9,7 @@
   width: null
   height: null
   zoom: null
+  diagonal: null

   constructor: (@selector) ->
     @$node = $(@selector)
@@ -32,6 +33,9 @@
   createD3Elements: ->
     @tree = d3.layout.tree().size([@width, @height-20])
                             .nodeSize([100, 70])
+    @diagonal = d3.svg.diagonal().projection((d) =>
+      [ d.x, @height - d.y ]
+    )

   setZoom: ->
     @zoom = d3.behavior.zoom().scaleExtent([0.0001,3])
@@ -43,12 +47,10 @@
               .append("svg")
               .attr("width", @width)
               .attr("height", @height)
-              .attr('viewBox',"0 0 #{@width} #{@height}")
-              .attr('preserveAspectRatio', 'xMidYMid')
               .style("overflow", "scroll")
               .append('g')
               .attr("class","drawarea")
-              .attr('transform', 'translate(0,10)')
+              .attr("transform", "translate(#{@width / 2},-30)")
     d3.select('svg').call @zoom

@@ -63,6 +65,9 @@
     @rootNeuron = neurons.filter((neuron) ->
       neuron.id == response.meta.root_id
     )[0]
+
+    @rootNeuron.x0 = @height / 2;
+    @rootNeuron.y0 = @width;

     @neuron_parents = { "no_parent":[] }

@@ -78,57 +83,11 @@

     @neurons = @tree.nodes(@rootNeuron)
     @shownNeurons = @neurons
-
-    @drawLinks()
-    @drawNeurons()
+    @update(@rootNeuron)
     @drawWithoutParent()
-
-  drawNeurons: ->
-    self = this
-    neuron = @svg.selectAll("g.node")
-                  .data(@shownNeurons)
-                  .enter()
-                  .append("g")
-                  .attr("class", "node")
-                  .attr("transform", (d) =>
-                    "translate(#{d.x}, #{ @height - d.y})"
-                  )
-    neuron.append("circle")
-          .attr("r", 4.5)
-          .style("stroke", (d) ->
-            if d.deleted then "#ec5747"
-          ).style("fill", (d) ->
-            if d._children then "lightsteelblue" else "#fff"
-          ).on "click", (node) =>
-            @toggleNode(node)
-
-    neuron.append('text')
-          .attr('dx', -8)
-          .attr('dy', 3)
-          .attr('text-anchor', "end")
-          .text((d) ->
-            d.title
-          ).on("mouseenter", (node) ->
-            self.showDetails(node, this)
-          ).on("click", @showNeuron)

   showNeuron: (neuron) =>
     window.location.pathname = "/admin/neurons/#{neuron.id}"
-
-  drawLinks: ->
-    # re-calculate tree position
-    @tree.nodes(@rootNeuron)
-
-    links = @tree.links(@shownNeurons)
-    diagonal = d3.svg.diagonal().projection((d) =>
-      [ d.x, @height - d.y ]
-    )
-    link = @svg.selectAll("path.link")
-                .data(links)
-                .enter()
-                .append("path")
-                .attr("class", "link")
-                .attr("d", diagonal)

   drawWithoutParent: ->
     self = this
@@ -187,7 +146,7 @@
     else
       @showChildren(node)
     @filterShownNeurons()
-    @draw()
+    @update(node)

   draw: ->
     d3.select(@selector).html("")
@@ -196,6 +155,95 @@
     @drawLinks()
     @drawNeurons()
     @drawWithoutParent()
+
+  update: (source) ->
+    self = this
+    duration = if d3.event and d3.event.altKey then 5000 else 500
+    # Compute the new tree layout.
+    nodes = @tree.nodes(@rootNeuron).reverse()
+    # Normalize for fixed-depth.
+    nodes.forEach (d) ->
+      d.y = d.depth * 50
+      return
+    # Update the nodes…
+    node = @svg.selectAll('g.node').data(nodes, (d) ->
+      d.id or (d.id = ++i)
+    )
+    # Enter any new nodes at the parent's previous position.
+    nodeEnter = node.enter().append('svg:g').attr('class', 'node').attr('transform', (d) ->
+      'translate(' + source.y0 + ',' + source.x0 + ')'
+    ).on('click', (d) =>
+      @toggleNode d
+      @update d
+      return
+    )
+    nodeEnter.append('svg:circle').attr('r', 4)
+                                  .style('stroke', (d) ->
+                                    if d.deleted then "#ec5747")
+                                  .style('fill', (d) ->
+                                    if d._children then "lightsteelblue" else "#fff")
+
+
+    nodeEnter.append('svg:text').attr('dy', -5).attr('text-anchor', 'middle').text((d) ->
+      d.title
+    ).on("mouseenter", (node) ->
+      self.showDetails(node, this)
+      )
+
+    # Transition nodes to their new position.
+    nodeUpdate = node.transition().duration(duration).attr('transform', (d) =>
+      'translate(' + d.x + ',' + (@height - (d.y)) + ')'
+    )
+    nodeUpdate.select('circle').attr('r', 4)
+                               .style('stroke', (d) ->
+                                 if d.deleted then "#ec5747")
+                               .style('fill', (d) ->
+                                 if d._children then "lightsteelblue" else "#fff")
+
+    nodeUpdate.select('text').style('fill-opacity', 1)
+
+    # Transition exiting nodes to the parent's new position.
+    nodeExit = node.exit().transition().duration(duration).attr('transform', (d) ->
+      'translate(' + source.y + ',' + source.x + ')'
+    ).remove()
+    nodeExit.select('circle').attr 'r', 4
+    nodeExit.select('text').style 'fill-opacity', 1e-6
+    # Update the links…
+    link = @svg.selectAll('path.link').data(@tree.links(nodes), (d) ->
+      d.target.id
+    )
+    # Enter any new links at the parent's previous position.
+    link.enter().insert('svg:path', 'g').attr('class', 'link').attr('d', (d) =>
+      o =
+        x: source.x0
+        y: source.y0
+      @diagonal
+        source: o
+        target: o
+    ).transition().duration(duration).attr 'd', @diagonal
+    # Transition links to their new position.
+    link.transition().duration(duration).attr 'd', @diagonal
+    # Transition exiting nodes to the parent's new position.
+    link.exit().transition().duration(duration).attr('d', (d) =>
+      o =
+        x: source.x
+        y: source.y
+      @diagonal
+        source: o
+        target: o
+    ).remove()
+    # Stash the old positions for transition.
+    nodes.forEach (d) ->
+      d.x0 = d.x
+      d.y0 = d.y
+      return
+    d3.select('svg').call d3.behavior.zoom().scaleExtent([
+      0.5
+      5
+    ]).on('zoom', zoom)
+    if source.name == 'root'
+      d3.select('.drawarea').attr 'transform', 'translate(' + 380 + ',' + -20 + ')'
+    return

   showDetails: (neuron, text) ->
     new moiTree.TreeDialog(neuron, text, @rootNeuron)


Improved wording.

Improved wording.

--- app/assets/javascripts/app/models/sla.js.coffee
+++ app/assets/javascripts/app/models/sla.js.coffee
@@ -4,13 +4,13 @@
   @url: 'api/slas'
   @configure_attributes = [
     { name: 'name',                display: 'Name',                tag: 'input',    type: 'text', limit: 100, null: false, 'class': 'span4' },
-    { name: 'first_response_time', display: 'First Resposne Time', tag: 'input',    type: 'text', limit: 100, null: true, 'class': 'span4' },
-    { name: 'update_time',         display: 'Update Time',         tag: 'input',    type: 'text', limit: 100, null: true, 'class': 'span4' },
-    { name: 'close_time',          display: 'Solution Time',       tag: 'input',    type: 'text', limit: 100, null: true, 'class': 'span4' },
+    { name: 'first_response_time', display: 'First Resposne Time', tag: 'input',    type: 'text', limit: 100, null: true, 'class': 'span4', note: 'In minutes, only business hours are counted.' },
+    { name: 'update_time',         display: 'Update Time',         tag: 'input',    type: 'text', limit: 100, null: true, 'class': 'span4', note: 'In minutes, only business hours are counted.' },
+    { name: 'close_time',          display: 'Solution Time',       tag: 'input',    type: 'text', limit: 100, null: true, 'class': 'span4', note: 'In minutes, only business hours are counted.' },
     { name: 'condition',           display: 'Conditions where SLA is used', tag: 'ticket_attribute_selection', null: true, class: 'span4' },
     {
       name:    'data'
-      display: 'Working Hours'
+      display: 'Business Times'
       tag:     'working_hour'
       default: {
         Mon: true


[#72428520] Replace snapshot wasn't replacing the snapshot!

https://www.pivotaltracker.com/story/show/72428520

--- app/assets/javascripts/image_question.js.coffee
+++ app/assets/javascripts/image_question.js.coffee
@@ -258,8 +258,8 @@
       @$text_response.val(@$saved_response.data('raw'))

   replace_snapshot:() ->
+    @shutterbug.getDomSnapshot()
     @show()
-    svg = @get_svg_canvas()
     @clear_drawing_layer()

   snapshot_updater: (e) =>


close notification.

close notification.

--- app/assets/javascripts/models/startup.js.coffee
+++ app/assets/javascripts/models/startup.js.coffee
@@ -6,3 +6,5 @@
       $(".loading-indicator").show()
     $(document).on 'turbolinks:request-end', ->
       $(".loading-indicator").hide()
+    $('.delete').on 'click', ->
+      $('.delete').parent('div:first').hide()


Add facebook appid

Add facebook appid

--- app/assets/javascripts/social-buttons.js.coffee
+++ app/assets/javascripts/social-buttons.js.coffee
@@ -1,5 +1,8 @@
 class Social
   constructor: ->
-    Socialite.load ($ '.social-buttons')
+    Socialite.load ($ '.social-buttons',
+      facebook:
+        appId: '498001033582275'
+    )

-App.Utilities.Social = Social+App.Utilities.Social = Social


change the hostnameAlias field on the domain instance when a vm is binded or unbinded.

--- client/landing/app/Applications/Environments.kdapplication/views/domains/domainsroutingview.coffee
+++ client/landing/app/Applications/Environments.kdapplication/views/domains/domainsroutingview.coffee
@@ -89,6 +89,7 @@
         listItem.hideLoader()
         @disconnectedVMController.removeItem listItem
         @connectedVMController.addItem vm
+        domain.hostnameAlias.push hostnameAlias
       else
         notifyError err

@@ -103,6 +104,7 @@
         listItem.hideLoader()
         @connectedVMController.removeItem listItem
         @disconnectedVMController.addItem vm
+        domain.hostnameAlias.splice domain.hostnameAlias.indexOf(hostnameAlias), 1
       else
         notifyError err


Zoomed drawing works

Zoomed drawing works

--- coffee/main.coffee
+++ coffee/main.coffee
@@ -176,8 +176,8 @@

   clientCoordsToDrawingCoords: (x, y) ->
     {
-      x: x - (@position.x * @scale),
-      y: y - (@position.y * @scale),
+      x: (x - @position.x) / @scale,
+      y: (y - @position.y) / @scale,
     }

   begin: (x, y) ->


reticulating materializaton

reticulating materializaton

--- coffee/main.coffee
+++ coffee/main.coffee
@@ -228,7 +228,7 @@
   setSshCmd: (x) =>
     x.props.sshcmd =
       'ssh -A -t '+g.user+'@users.isi.deterlab.net '+
-      'ssh -A '+x.props.name+'.'+g.user+'-'+dsg+'.SPIdev'
+      'ssh -A '+x.props.name+'.'+g.user+'-'+dsg+'.cypress'

   #The Computer class is a representation of a computer
   Computer: class Computer
@@ -239,7 +239,7 @@
       @props = {
         name: "computer0",
         sys: "root",
-        os: "Ubuntu1504-54-STD",
+        os: "Ubuntu1404-54-STD",
         start_script: "",
         interfaces: {},
         sshcmd: ""


use server side query on videocall too

use server side query on videocall too


shortcuts: factor out recorder to https://github.com/tetsuo/record-shortcuts

--- client/app/lib/shortcuts/record.coffee
+++ client/app/lib/shortcuts/record.coffee
@@ -1,55 +0,0 @@
-$ = require 'jquery'
-_ = require 'lodash'
-keycode = require 'keycode'
-
-MAX_KEYS = 5
-WAIT_MS  = 1000
-
-seq  = []
-next = null
-pending = null
-running = no
-
-
-done = ->
-
-  next? _.uniq seq
-  reset()
-
-  return
-
-
-reset = ->
-
-  $(document).off 'keydown', record
-  clearTimeout pending
-  seq  = []
-  next = null
-  running = no
-
-  return
-
-
-record = (e) ->
-
-  e.preventDefault()
-  e.stopPropagation()
-
-  clearTimeout pending
-
-  code = e.which or e.keyCode
-  key  = keycode code
-
-  if seq.push(key) > (MAX_KEYS - 1)
-  then done()
-  else pending = setTimeout done, WAIT_MS
-
-
-module.exports = (cb) ->
-
-  if running then reset()
-  running = yes
-  next = cb
-  $(document).on 'keydown', record
-
-  return


data should be an array to work with collections

--- client/lanes/testing/BeforeEach.coffee
+++ client/lanes/testing/BeforeEach.coffee
@@ -20,7 +20,7 @@
     SYNC_RESPONSE = {
         success: true
         message: ''
-        data: {}
+        data: []
     }

     originalFn = Lanes.Models.Sync.perform


fullpieagent testing

fullpieagent testing


consistent coffee styling

consistent coffee styling

--- app/assets/javascripts/controllers/paper_manage_controller.js.coffee
+++ app/assets/javascripts/controllers/paper_manage_controller.js.coffee
@@ -7,7 +7,7 @@
   ).property('model.phases.@each')

   updatePositions: (phase)->
-    relevantPhases = this.get('model.phases').filter((p)->
+    relevantPhases = @get('model.phases').filter((p)->
       p != phase && p.get('position') >= phase.get('position')
     )


added comments for BaseItemView

added comments for BaseItemView

Change-Id: I6c3a51c1d124d4a59c01634796ee26ef3e864150

--- app/coffeescripts/home/views/quickStartBar/BaseItemView.coffee
+++ app/coffeescripts/home/views/quickStartBar/BaseItemView.coffee
@@ -7,8 +7,33 @@
   'jquery.disableWhileLoading'
 ], ({View}, _, $, Assignment, template, ContextSearch) ->

+  ##
+  # Base class for all quickstart bar form views.
+  # Emits 'save' and 'saveFail' events when the underlying model is saved.
   class BaseItemView extends View

+    ##
+    # The form submit event is handled in this base class.
+    # Remember when extending with coffeescript the `events` will get
+    # overwritten, so you need to do something like this to not blow
+    # this event away:
+    #
+    #    class Sub extends BaseItemView
+    #      events: _.extend
+    #        'click .something': 'someHandler'
+    #      , BaseItemView::events
+    events:
+      'submit form': 'onFormSubmit'
+
+    ##
+    # Sub-classes should define a template function that returns
+    # a string. Typically this will be a pre-compiled handlebars template.
+    template: -> ''
+
+    ##
+    # ContextSearch has a lengthy api, each sub-class should define
+    # the contextSearchOptions in its entirety, and it will be automatically
+    # created
     contextSearchOptions:
       fakeInputWidth: '100%'
       contexts: ENV.CONTEXTS
@@ -21,17 +46,21 @@
             row.noExpand = true
         browser: false

-    events:
-      'submit form': 'onFormSubmit'
-
+    ##
+    # Renders the template and sets the @$el html
     render: ->
       @$el.html @template()
       super

+    ##
+    # Creates date pickers and context search instances after render
     filter: ->
       @$('.dateField').datetime_field()
       @$('.contextSearch').contextSearch @contextSearchOptions

+    ##
+    # Form submit handler, converts the form into a JavaScript object and calls
+    # the `@save` method. Also handles some shared display concerns.
     onFormSubmit: (event) ->
       event.preventDefault()
       $form = $ event.target
@@ -42,7 +71,7 @@
       dfd.fail => @trigger 'saveFail'

     ##
-    # sub classes should implement their own save method
-    # that returns a deferred object
+    # Sub-classes should implement their own save method
+    # that returns a deferred object, used in `@onFormSubmit`
     save: -> @model.save()


Do not indent coffee files.

Do not indent coffee files.

--- app/views/alchemy/admin/pages/destroy.js.coffee
+++ app/views/alchemy/admin/pages/destroy.js.coffee
@@ -2,17 +2,17 @@

 <% if @layoutpage %>

-  window.location.replace '<%= alchemy.admin_layoutpages_path -%>'
+window.location.replace '<%= alchemy.admin_layoutpages_path -%>'

 <% elsif @page_root %>

-  $('#sitemap').replaceWith '<%= escape_javascript(render(:partial => "sitemap")) -%>'
-  Alchemy.growl '<%= @message -%>'
-  Alchemy.Tooltips()
+$('#sitemap').replaceWith '<%= escape_javascript(render(:partial => "sitemap")) -%>'
+Alchemy.growl '<%= @message -%>'
+Alchemy.Tooltips()^

 <% else %>

-  window.location.replace '<%= alchemy.admin_pages_path -%>'
+window.location.replace '<%= alchemy.admin_pages_path -%>'

 <% end %>


couple ui bugs

couple ui bugs

--- app/assets/javascripts/submission.js.coffee
+++ app/assets/javascripts/submission.js.coffee
@@ -54,8 +54,8 @@
     @$('.progress .meter').animate(width: "#{(@progress) / @progressTotal * 100}%")

   setListeners: ->
-    @$('.action-next').click => @nextStep()
-    @$('.action-previous').click => @prevStep()
+    @$('.action-next a').click => @nextStep()
+    @$('.action-previous a').click => @prevStep()

     @$('form :submit').click (e) =>
       e.preventDefault()
@@ -63,7 +63,7 @@
       @nextStep()
       setTimeout((=> @$('form').submit()), 1000)

-    @$('.action-comment').click ->
+    @$('.action-comment a').click ->
       $comments = $(this).closest('.metric').find('.comments')
       if $comments.is(':visible')
         $(this).fadeTo('fast', 1)
@@ -89,14 +89,13 @@
     @$('form').change =>
       $.post @$('form').attr('action'), @$('form').serialize()

-    @$('.rating :radio').change ->
+    @$('.rating :radio').click ->
       $metric = $(this).closest('.metric')
-      $metric.find('.rating-value').text($(this).val())
       $metric.find('textarea').focus()

       if parseInt($(this).val()) <= 2
         unless $metric.find('.comments').is(':visible')
-          $metric.find('.action-comment').click()
+          $metric.find('.action-comment a').click()

     @$('.rating-option').click ->
       $(this).closest('.rating').add(this).addClass('rated')


refactored removeEvent functions

refactored removeEvent functions

--- app/coffee/drm-calendar/drm-calendar.coffee
+++ app/coffee/drm-calendar/drm-calendar.coffee
@@ -408,8 +408,11 @@

             self.body.on 'click', 'div.drm-calendar-event-details button.drm-event-delete', (e) ->
                 e.preventDefault()
-                eventId = $(@).data 'event'
-                self.removeCalendarEvent eventId
+                that = $ @
+                eventId = that.data 'event'
+                index = self.getEventIndex eventId
+                self.removeCalendarEvent eventId, index
+                self.removeEventDetails(e)

             self.body.on 'click', 'div.drm-calendar-event-details button.drm-event-close', self.removeEventDetails

@@ -470,13 +473,21 @@

             if events.type is 'holiday' then eventList.find("a:contains(#{events.name})").addClass @classes.holiday

-        removeCalendarEvent: (eventId) =>
+        removeCalendarEvent: (eventId, index) =>
             events = @calendar.find "ul.#{@eventClass} a[data-event=#{eventId}]"
             events.remove()
-            @events.splice eventId, 1
+            @events.splice index, 1
+
+        getEventIndex: (eventId) =>
+            index = null
+            $.each @events, (key, value) ->
+                if value.id is eventId
+                    index = key
+            index

         showEventDetails: (eventId, fullDate) =>
-            events = @events[eventId]
+            index = @getEventIndex eventId
+            events = @events[index]
             eventDate = "#{fullDate.month} #{fullDate.date}, #{fullDate.year}"
             eventFrequency =
                 if events.recurrance is 'yearly' and events.dayNum?