FIX: Query Teaching Period to load on refresh

--- src/app/teaching-periods/states/index/index.coffee
+++ src/app/teaching-periods/states/index/index.coffee
@@ -20,6 +20,7 @@
 .controller("TeachingPeriodIndexStateCtrl", ($scope, $state, $stateParams, listenerService, TeachingPeriod, alertService) ->
   # Error - required teachingPeriodId is missing!
   teachingPeriodId = +$stateParams.teachingPeriodId
+  TeachingPeriod.query()

   TeachingPeriod.get(
     teachingPeriodId


minor bug fix

minor bug fix

--- client/landing/app/MainApp/analytic.coffee
+++ client/landing/app/MainApp/analytic.coffee
@@ -1,10 +1,10 @@
 do->
-	KD.track = (rest...)->
-	  logToGoogle rest...
-	  kdMixpanel = new KDMixpanel
-	  kdMixpanel.createEvent rest...
+  KD.track = (rest...)->
+    logToGoogle rest...
+    kdMixpanel = new KDMixpanel
+    kdMixpanel.createEvent rest...

-	logToGoogle = (rest...)->
-	  category = action = rest.first
-	  trackArray = ['_trackEvent', category, action]
-	  _gaq.push trackArray
+  logToGoogle = (rest...)->
+    category = action = rest.first
+    trackArray = ['_trackEvent', category, action]
+    _gaq.push trackArray


:lipstick: Make defaults private

:lipstick: Make defaults private

--- src/request.coffee
+++ src/request.coffee
@@ -1,7 +1,7 @@
 class @Request
   Helpers.includeInto(this)

-  DEFAULTS =
+  _DEFAULTS =
     url: null
     method: "GET"
     async: true
@@ -33,7 +33,7 @@
         @_emitter.on event, options[event]
         delete options[event]

-    @merge this, DEFAULTS
+    @merge this, _DEFAULTS
     @merge this, options

   send: ->


going back when first navigate to a subpage puts you to potentially non considerit page

Former-commit-id: 507f970197e1390e382759460b615dec63d33631 [formerly 6fe40184ab47b42a918382ebada2fbf9790bf079] [formerly b1d74bc78164e70a3a83dec5a449d6575e2678df [formerly b1d74bc78164e70a3a83dec5a449d6575e2678df [formerly 6a23e67fc4ebdbb87b055f329f897d12a4e14034]]]
Former-commit-id: f4b3ea79b91f4dbc201b6ae9accb7b006060bf36 [formerly 386771b173e3996de5cecba5eb8e00d0fad10365]
Former-commit-id: 954c88d88c5e0d716b645a5c07a5d565a8d6f679
Former-commit-id: c4449a1853004df1d7723d75572fff7b6cbc7e2a

--- app/assets/javascripts/views/appview.coffee
+++ app/assets/javascripts/views/appview.coffee
@@ -45,7 +45,10 @@
     'click .l-navigate-back' : 'go_back'

   go_back : ->
-    window.history.go(-1)
+    if @crumbs.length < 3
+      ConsiderIt.router.navigate(Routes.root_path(), {trigger: true})
+    else
+      window.history.go(-1)

   route_changed : (route, router) ->
     return if route == 'route'


Remove broken submitted state management on timeline

--- app/assets/volume/slot.coffee
+++ app/assets/volume/slot.coffee
@@ -581,7 +581,6 @@

       save: ->
         return if @pending # sorry
-        $scope.form.edit.$setSubmitted()
         @pending = 1
         messages.clear(this)
         (if @file
@@ -592,7 +591,6 @@
         ).then (asset) =>
             delete @pending

-            $scope.form.edit.$setUnsubmitted()
             first = !@asset
             @setAsset(asset)

@@ -614,7 +612,6 @@
             return
           , (res) =>
             delete @pending
-            $scope.form.edit.$setUnsubmitted()
             messages.addError
               type: 'red'
               body: constants.message('asset.update.error', @name)


LMS-1447: Teachers are able to view assignments from another sections

--- app/coffeescripts/models/DueDateList.coffee
+++ app/coffeescripts/models/DueDateList.coffee
@@ -51,4 +51,6 @@
         due_at: @assignment.get('due_at')
         lock_at: @assignment.get('lock_at')
         unlock_at: @assignment.get('unlock_at')
+      if ENV.LIMIT_PRIVILEGES_TO_COURSE_SECTION && ENV.SECTION_LIST && ENV.SECTION_LIST.length
+        override.set 'course_section_id', ENV.SECTION_LIST[0].id
       @overrides.add override


Add some error checking

Add some error checking

--- lib/js/steambuddy.coffee
+++ lib/js/steambuddy.coffee
@@ -68,9 +68,9 @@

 parseUser = (vanityName)->
   deferred = $q.defer()
-  request 'http://steamcommunity.com/id/' + vanityName + '/?xml=1', (error, response, body)=>
+  request "http://steamcommunity.com/id/#{vanityName}/?xml=1", (error, response, body)=>
     parser.parse body, (err, result)->
-      deferred.resolve(new User({name: result.name, id: result.id}))
+      deferred.resolve(new User({name: result.name, id: result.id})) if not err

   deferred.promise


Updating script docs

Updating script docs

--- scripts/p1radiator.coffee
+++ scripts/p1radiator.coffee
@@ -3,7 +3,7 @@
 #
 # Commands:
 #   tinkurbot p1 - turn on the P1 Fire Alarm
-#
+#
 # Author:
 #   Created by Tinkurlab www.tinkurlab.com
 #   https://github.com/TinkurLab/P1InfoRadiator


Fixed another test timing issue.

Fixed another test timing issue.

--- test/integration/signup.coffee
+++ test/integration/signup.coffee
@@ -36,12 +36,12 @@
                 wd40.click '#acceptedTerms', ->
                   wd40.click '#go', done

-      it 'it takes me to the /thankyou page', (done) ->
-        wd40.waitForMatchingURL /[/]thankyou/, done
-
       it 'it says thanks', (done) ->
-        wd40.waitForText 'Thankyou for signing up', done
+        wd40.waitForText 'Thankyou for signing up', 10000, done

       it 'it tells me to check my emails', (done) ->
         wd40.waitForText 'check your email', done

+      it 'it takes me to the /thankyou page', (done) ->
+        wd40.waitForMatchingURL /[/]thankyou/, done
+


Adding a common debug point

Adding a common debug point

--- src/construct/client.coffee
+++ src/construct/client.coffee
@@ -73,6 +73,7 @@

   _onMessage: (m) =>
     message = JSON.parse m.utf8Data
+    # console.log message
     @emit "message", message

     for k,v of message


Adds parameter for custom database uri

Adds parameter for custom database uri

--- coffee/database.coffee
+++ coffee/database.coffee
@@ -11,12 +11,14 @@
 #
 # github.com/mongodb/node-mongodb-native/blob/master/docs/articles/MongoClient.md
 #
-exports.connect = (database, cb) ->
+exports.connect = (custom_uri, cb) ->
   switch process.env['MODE']
     when "production" then uri = process.env['MONGO_PROD_URI']
     when "stage" then uri = process.env['MONGO_STAGE_URI']
     when "development" then uri = process.env['MONGO_DEV_URI']
     else uri = "mongodb://localhost:27017/ntb_test"
+
+  uri = custom_uri if custom_uri isnt null

   MongoClient.connect uri, (err, db) ->
     cb err, db


No reason to wait on initializing the referer until we have verified that Turbolinks is active -- its a weird initialization flow

--- lib/assets/javascripts/turbolinks.js.coffee
+++ lib/assets/javascripts/turbolinks.js.coffee
@@ -1,6 +1,6 @@
 cacheSize      = 10
 currentState   = null
-referer        = null
+referer        = document.location.href
 loadedAssets   = null
 pageCache      = {}
 createDocument = null
@@ -295,7 +295,6 @@

 if browserSupportsTurbolinks
   visit = (url) ->
-    referer = document.location.href
     cacheCurrentPage()
     fetchReplacement url
   initializeTurbolinks()


fix moving selection persistence

fix moving selection persistence

--- app/controllers/selection-move-modal.coffee
+++ app/controllers/selection-move-modal.coffee
@@ -24,12 +24,14 @@

     save: ->
       selection = @get('model')
-      selection.save().then =>
-        @get('oldLabel.selections').removeObject(selection)
-        @get('oldLabel').save().then =>

-          @get('newLabel.selections').addObject(selection)
-          @get('newLabel').save().then =>
+      @get('oldLabel.selections').removeObject(selection)
+      @get('oldLabel').save().then =>
+
+        @get('newLabel.selections').addObject(selection)
+        @get('newLabel').save().then =>
+
+          selection.save().then =>
             @send('closeModal')
             @set('model', null)


git pull from origin

git pull from origin

--- app/js/services/wallet.coffee
+++ app/js/services/wallet.coffee
@@ -119,38 +119,26 @@
             success()

     get_balance: ->
-        @growl.notice "", "DISABLED get_balance"
-        ###
         @rpc.request('wallet_get_balance').then (response) ->
             asset = response.result[0]
             {amount: asset[0], asset_type: asset[1]}
-            ###

     get_wallet_name: ->
-        @growl.notice "", "DISABLED get_wallet_name"
-        ###
         @rpc.request('wallet_get_name').then (response) =>
           console.log "---- current wallet name: ", response.result
           @wallet_name = response.result
-          ###

     get_info: ->
         @rpc.request('get_info').then (response) =>
           response.result

     wallet_add_contact_account: (name, address) ->
-        @growl.notice "", "DISABLED wallet_add_contact_account"
-        ###
         @rpc.request('wallet_add_contact_account', [name, address]).then (response) =>
           response.result
-          ####

     wallet_account_register: (account_name, pay_from_account, public_data, as_delegate) ->
-        @growl.notice "", "DISABLED wallet_account_register"
-        ###
         @rpc.request('wallet_account_register', [account_name, pay_from_account, public_data, as_delegate]).then (response) =>
           response.result
-          ###

     wallet_rename_account: (current_name, new_name) ->
         @rpc.request('wallet_rename_account', [current_name, new_name]).then (response) =>


workaround for play issue 87, cause is_my_account has already been deleted from upstream

--- app/js/services/wallet.coffee
+++ app/js/services/wallet.coffee
@@ -119,7 +119,7 @@
                         @asset_balances[asset_id] = @asset_balances[asset_id] + amount
             angular.forEach @accounts, (acct) =>
                 #console.log "------ refresh_balances acct.name ------>", acct.name
-                if acct.is_my_account and !@balances[acct.name]
+                if !@balances[acct.name]
                     @balances[acct.name] = {}
                     @balances[acct.name][@main_asset.symbol] = @utils.asset(0, @main_asset)
             deffered.resolve(@balances)
@@ -182,20 +182,20 @@
     count_my_accounts: ->
         accounts = 0
         angular.forEach @accounts, (acct, name) ->
-            if acct.is_my_account
-                accounts += 1
+            accounts += 1
         return accounts

     count_my_delegates: ->
         delegates = 0
         angular.forEach @accounts, (acct, name) ->
-            if acct.is_my_account and acct.delegate_info != null
+            if acct.delegate_info != null
                 delegates += 1
         return delegates

     # turn raw rpc return value into nice object
     populate_account: (val) ->
         acct = val
+        acct.is_my_account = true
         acct.active_key = val.active_key_history[val.active_key_history.length - 1][1]
         acct.registered = val.registration_date and val.registration_date != "1970-01-01T00:00:00"
         #console.log "populate_account",acct.name
@@ -406,8 +406,7 @@
 #            if @transactions["*"].length > 0
 #                #@growl.notice "", "You just received a new transaction!"
 #                angular.forEach @accounts, (account, name) =>
-#                    if account.is_my_account
-#                        @refresh_transactions(name)
+#                    @refresh_transactions(name)
 #
 #    # TODO: search for all deposit_op_type with asset_id 0 and sum them to get amount
 #    # TODO: sort transactions, show the most recent ones on top
@@ -505,8 +504,7 @@

     get_first_account: ->
         for k,v of @accounts
-            if v.is_my_account
-                return v
+            return v
         return null

     get_current_or_first_account: ->


checking job interval

checking job interval

--- server/job.coffee
+++ server/job.coffee
@@ -384,7 +384,7 @@
     # and if legit and being hit on every available machine in the cluster, should trigger alert to start more cluster machines?
     API.log {msg:'Not running more jobs, job max memory reached', _cid: process.env.CID, _appid: process.env.APP_ID, function:'API.job.next'}
   else
-    API.log {msg:'Checking for jobs to run',ignore:API.job._ignoregroups,function:'API.job.next',level:'debug'}
+    API.log {msg:'Checking for jobs to run', ignores: {groups:API.job._ignoregroups,ids:API.job._ignoreids}, function:'API.job.next', level:'debug'}
     match = must_not:[{term:{available:false}}] # TODO check this will get matched properly to something where available = false
     match.must_not.push({term: 'group.exact':g}) for g of API.job._ignoregroups
     match.must_not.push({term: '_id.exact':m}) for m of API.job._ignoreids


Regex splited into separate lines.

Regex splited into separate lines.

--- lib/linter-pylama.coffee
+++ lib/linter-pylama.coffee
@@ -5,7 +5,13 @@
 {CompositeDisposable} = require 'atom'
 XRegExp = require('xregexp').XRegExp

-regex = XRegExp('(?<file>.+):(?<line>\\d+):(?<col>\\d+):\\s+((((?<error>E)|(?<warning>[CDFNW]))(?<code>\\d+)(:\\s+|\\s+))|(.*?))(?<message>.+)(\r)?\n')
+regex = XRegExp '(?<file>.+):' +
+  '(?<line>\\d+):' +
+  '(?<col>\\d+):' +
+  '\\s+' +
+  '((((?<error>E)|(?<warning>[CDFNW]))(?<code>\\d+)(:\\s+|\\s+))|(.*?))' +
+  '(?<message>.+)' +
+  '(\r)?\n'

 class LinterPylama
   @pylamaPath: ''


Remove unused import

Remove unused import

--- lib/linter-pylama.coffee
+++ lib/linter-pylama.coffee
@@ -1,7 +1,6 @@
 fs = require "fs"
 path = require 'path'
 helpers = require 'atom-linter'
-{BufferedProcess} = require 'atom'
 {CompositeDisposable} = require 'atom'

 regex = '(?<file_>.+):' +


Don't use deprecated atom.config.unobserve

--- lib/linter-scalac.coffee
+++ lib/linter-scalac.coffee
@@ -18,11 +18,11 @@
 	constructor: (editor) ->
 		super(editor)

-		atom.config.observe('linter-scalac.scalacExecutablePath', =>
+		@pathSubscription = atom.config.observe('linter-scalac.scalacExecutablePath', =>
 			@executablePath = atom.config.get('linter-scalac.scalacExecutablePath')
 		)

-		atom.config.observe('linter-scalac.scalacOptions', =>
+		@optionsSubscription = atom.config.observe('linter-scalac.scalacOptions', =>
 			dotClasspath = atom.project.getPaths()[0] + '/.classpath'

 			if atom.config.get('linter-scalac.scalacOptions')?
@@ -35,12 +35,12 @@
 		)

 	destroy: ->
-		atom.config.unobserve('linter-scalac.scalacExecutablePath')
-		atom.config.unobserve('linter-scalac.scalacOptions')
+		super
+		@pathSubscription.dispose()
+		@optionsSubscription.dispose()

 	lintFile: (filePath, callback) ->
 		command = @executablePath + '/' + @cmd + ' ' + filePath + ' ' + @options
-
 		exec(command, cwd: @cwd, (error, stdout, stderr) => if stderr then @processMessage(stderr, callback))

 module.exports = LinterScalac


Fix transformation issues. Closes #67, #68 and #35.

I think 5 decimal places is probably enough.

--- lib/mixins/vector.coffee
+++ lib/mixins/vector.coffee
@@ -146,7 +146,7 @@
         @addContent 'W' + @_windingRule(rule) + ' n'

     transform: (m11, m12, m21, m22, dx, dy) ->
-        values = [m11, m12, m21, m22, dx, dy].join ' '
+        values = (+v.toFixed(5) for v in [m11, m12, m21, m22, dx, dy]).join(' ')
         @addContent "#{values} cm"

     translate: (x, y) ->
@@ -174,9 +174,7 @@
         if options.origin?
             x = options.origin[0]
             y = @page.height - options.origin[1]
-            x1 = factor * x
-            y1 = factor * y
-            x -= x1
-            y -= y1
+            x -= factor * x
+            y -= factor * y

         @transform factor, 0, 0, factor, x, y


Support windows launch by default

Support windows launch by default

--- lib/node-debugger.coffee
+++ lib/node-debugger.coffee
@@ -4,6 +4,7 @@
 {Debugger, ProcessManager} = require './debugger'
 jumpToBreakpoint = require './jump-to-breakpoint'
 logger = require './logger'
+os = require 'os'

 processManager = null
 _debugger = null
@@ -21,7 +22,7 @@
   config:
     nodePath:
       type: 'string'
-      default: '/bin/node'
+      default: if os.platform() is 'win32' then 'node.exe' else '/bin/node'
     debugPort:
       type: 'number'
       minium: 5857


fix test name

fix test name

--- test/lib/task/lock.spec.coffee
+++ test/lib/task/lock.spec.coffee
@@ -33,7 +33,7 @@

       expect(TaskLock.isTaskLocked(task)).to.be.true

-    it 'should return true ifj the lock is expired.', ->
+    it 'should return true if the lock is expired.', ->
       task  = TaskLock.acquire(null, {})
       @clock.tick(30001)


- added error handling for missing helpers/engines

--- src/crystal/generate.coffee
+++ src/crystal/generate.coffee
@@ -132,6 +132,8 @@
 					loaded_modules[module_name][version_name].exports[export_name].engine = loaded_modules[test][loaded_module.modules[test]].exports[test2].engine

 				if exported.filename and typeof(exported.filename.engine) == 'string'
+					if !loaded_module.imports[exported.filename.engine]
+						throw new Error "Import does not exist for alias (#{exported.filename.engine})"
 					test = loaded_module.imports[exported.filename.engine].split('.')
 					test2 = test.pop()
 					test = test.join('.')
@@ -157,6 +159,9 @@
 					test2 = test.pop()
 					test = test.join('.')

+					if !loaded_modules[test][loaded_module.modules[test]].exports[test2]
+						throw new Error "Import (#{test2}) does not exist for module (#{test})"
+
 					loaded_modules[module_name][version_name].exports[export_name].helper = [{
 						callback: loaded_modules[test][loaded_module.modules[test]].exports[test2].helper
 						name: loaded_modules[test][loaded_module.modules[test]].exports[test2].name


Make sure we're not in the future

Make sure we're not in the future

--- client/file-list.coffee
+++ client/file-list.coffee
@@ -2,7 +2,12 @@

 Template.fileList.helpers
   'files': -> FileList.find {}, sort: LastModified: -1
-  'date': -> moment(@LastModified).fromNow()
+  'date': ->
+    modified = moment(@LastModified)
+    if modified.isBefore()
+      modified.fromNow()
+    else
+      "a few seconds ago"

 handleFiles = (event) ->
   if event.type == "drop"


don't display the incident content when update fail

--- src/sm-cmds.coffee
+++ src/sm-cmds.coffee
@@ -207,8 +207,7 @@
               resp.reply "Incident #{id} was updated, but some fields may be wrong."+wrongmsg
           .catch (r) ->
             robot.logger.debug r
-            msg = robot.sm_ext.buildSlackMsgFromSmError "Failed to update incident #{id}", resp.message.rawMessage.channel, r
-            robot.emit 'slack.attachment', msg
+            resp.reply "Failed to update incident #{id}"+"\r*Reason*: #{r.body.Messages.join('\r')}"

         resp.reply "Updating Incident #{id} on #{ins}<#{Config.get "sm.servers."+ins+".endpoint"}>....."
       attach: (fullCmdLine, resp)->


emit events

emit events

--- components/Tween.coffee
+++ components/Tween.coffee
@@ -13,33 +13,34 @@
       from: new noflo.Port 'number'
       to: new noflo.Port 'number'
       repeat: new noflo.Port 'number'
-      reverse: new noflo.Port 'boolean'
+      autoreverse: new noflo.Port 'boolean'
       easing: new noflo.Port 'string'
     @outPorts =
       started: new noflo.Port 'bang'
       stopped: new noflo.Port 'bang'
       value: new noflo.Port 'bang'

+    # params
     @inPorts.from.on 'data', (value) =>
       @getTween().vars.startAt = { x: value }
-
     @inPorts.to.on 'data', (value) =>
       @getTween().updateTo({ x: value })
+    @inPorts.duration.on 'data', (value) =>
+      @getTween().duration(parseFloat(value) / 1000.0)
+    @inPorts.repeat.on 'data', (value) =>
+      @getTween().repeat(value)
+    @inPorts.autoreverse.on 'data', (value) =>
+      @getTween().yoyo(value)

-    @inPorts.duration.on 'data', (value) =>
-      @getTween().duration(value)
-
+    # actions
     @inPorts.start.on 'data', (value) =>
       @getTween().play()
       @getTween().paused(false)
-
     @inPorts.stop.on 'data', (value) =>
       @getTween().paused(true)
       @getTween().seek(0)
-
     @inPorts.pause.on 'data', (value) =>
       @getTween().paused(true)
-
     @inPorts.unpause.on 'data', (value) =>
       @getTween().paused(false)

@@ -47,7 +48,22 @@
     return @tween if @tween
     @obj =
       x: 0
-    @tween = new gsap.TweenMax(@obj, 1000, { x:1 })
+    params =
+      x: 1
+      ease: 'linear'
+      onStart: () =>
+        return unless @outPorts.started.isAttached()
+        @outPorts.started.send(true)
+        @outPorts.started.disconnect()
+      onUpdate: () =>
+        return unless @outPorts.value.isAttached()
+        @outPorts.value.send(@obj.x)
+        @outPorts.value.disconnect()
+      onComplete: () =>
+        return unless @outPorts.stopped.isAttached()
+        @outPorts.stopped.send(true)
+        @outPorts.stopped.disconnect()
+    @tween = new gsap.TweenMax(@obj, 1, )

   shutdown: () ->
     return unless @tween


Fixed status colors for the uploads

Fixed status colors for the uploads

--- main/static/src/script/site/resource.coffee
+++ main/static/src/script/site/resource.coffee
@@ -54,7 +54,7 @@
         return

       if progress == 100.0 and resource
-        $('.progress-bar', $resource).addClass('bar-success')
+        $('.progress-bar', $resource).addClass('progress-bar-success')
         $('.progress-text', $resource).text("Success #{size_human(file.size)}")
         if resource.image_url and $preview.text().length > 0
           $preview.css('background-image', "url(#{resource.image_url})")
@@ -83,4 +83,3 @@
           $("#{target}").remove()
         if redirect_url
           window.location.href = redirect_url
-


Don't delete unless the selection is one row. Resolves #165

--- src/main/client/grid/grid-directives-tables.coffee
+++ src/main/client/grid/grid-directives-tables.coffee
@@ -259,8 +259,8 @@
                 callback: (command, selection, evt) ->
                   start = selection.start.row
                   end = selection.end.row
-                  for i in [start .. end] by 1
-                    entityIdentifier = handsonTable.getSourceDataAtRow(i).id
+                  if start == end
+                    entityIdentifier = handsonTable.getSourceDataAtRow(start).id
                     deleteCase scope, handsonTable, entityIdentifier
               }
             handsonTable.updateSettings {


Change how overlay is handled

Change how overlay is handled

--- plugins/overlay.coffee
+++ plugins/overlay.coffee
@@ -22,19 +22,7 @@
             editable: null
             toolbar: null
             uuid: ""
-
-            # The pieces of the overlay are re-positioned when the editable is modified. This value defines
-            # the minimal interval between two repositioning to avoid performance issues
-            updateInterval: 100
-
-            # Adapt these values if you have rounded corners for the editable
-            offsetTop: 0
-            offsetLeft: 0
-            offsetRight: 0
-            offsetBottom: 0
-
-            # The overlay pieces around the editable element
-            pieces: {}
+            overlay: null

         _create: ->
             widget = this
@@ -64,104 +52,40 @@

         showOverlay: ->
             @options.visible = true
-            if @options.pieces.top
-                for key, piece of @options.pieces
-                    piece.show()
-                @updateOverlay()
-                return
+            if @options.overlay
+                @options.overlay.show
+
+
+                @options.originalBgColor = @options.currentEditable.css "background-color"
+                @options.currentEditable.css 'background-color', _findBackgroundColor(@options.currentEditable)
+                @options.originalZIndex = @options.currentEditable.css "z-index"
+                @options.currentEditable.css 'z-index', '350'

             @_createOverlay()

         hideOverlay: ->
             @options.visible = false
-            if @options.pieces.top
-                for key, piece of @options.pieces
-                    piece.hide()
+            @options.overlay.hide
+
+            @options.currentEditable.css 'background-color', @options.originalBgColor
+            @options.currentEditable.css 'z-index', originalZIndex

             @options.editable._deactivated {data: @options.editable}

-        # To prevent performance issue, we only allow the update if the last update did not occure
-        # a few millieconds ago (see options.updateInterval)
-        # Pass true as first argument if you want to force the update
-        updateOverlay: (force) ->
-            now = new Date().getTime();
-            # trying to avoid performance issue
-            if !force and @options.lastUpdate and now - @options.lastUpdate < @options.updateInterval
-                return
+        _createOverlay: () ->
+            overlay = jQuery('
')
+            jQuery(document.body).append overlay
+            overlay.bind 'click', jQuery.proxy @hideOverlay, @

-            @options.lastUpdate = now
-            if @options.pieces.top
-                m = @_getMeasures();
+        _findBackgroundColor: (field) ->
+            jQueryfield = jQuery(field)
+            color = jQueryfield.css("background-color")
+            if color isnt 'rgba(0,0,0,0)' and color isnt 'transparent'
+                return color

-                @options.pieces.left.css
-                    height: m.editableHeight - @options.offsetTop - @options.offsetBottom
-                    width: m.editableLeft + @options.offsetLeft
-
-                @options.pieces.right.css
-                    height: m.editableHeight - @options.offsetTop - @options.offsetBottom
-                    width: m.windowWidth - (m.editableLeft + m.editableWidth) + @options.offsetRight
-
-                @options.pieces.bottom.css
-                    top: m.editableTop + m.editableHeight - @options.offsetBottom
-                    height: m.documentHeight - (m.editableTop + m.editableHeight) + @options.offsetBottom
-
-        _createOverlay: () ->
-            m = @_getMeasures();
-
-            top = @_getBasicPiece()
-            top.css
-                top: 0
-                left: 0
-                width: '100%'
-                height: m.editableTop + @options.offsetTop
-            jQuery(document.body).append top
-            @options.pieces.top = top
-
-            left = @_getBasicPiece()
-            left.css
-                top: m.editableTop + @options.offsetTop
-                left: 0
-                width: m.editableLeft + @options.offsetLeft
-                height: m.editableHeight - @options.offsetTop - @options.offsetBottom
-            jQuery(document.body).append left
-            @options.pieces.left = left
-
-            right = @_getBasicPiece()
-            right.css
-                top: m.editableTop + @options.offsetTop
-                right: 0
-                width: m.windowWidth - (m.editableLeft + m.editableWidth) + @options.offsetRight
-                height: m.editableHeight - @options.offsetTop - @options.offsetBottom
-            jQuery(document.body).append right
-            @options.pieces.right = right
-
-            bottom = @_getBasicPiece()
-            bottom.css
-                top: m.editableTop + m.editableHeight - @options.offsetBottom
-                left: 0
-                width: '100%'
-                height: m.documentHeight - (m.editableTop + m.editableHeight) + @options.offsetBottom
-            jQuery(document.body).append bottom
-            @options.pieces.bottom = bottom
-
-            for key, piece of @options.pieces
-                piece.bind 'click', jQuery.proxy @hideOverlay, @
-
-        _getMeasures: ->
-            m =
-                editableHeight: @options.currentEditable.outerHeight()
-                editableWidth: @options.currentEditable.outerWidth()
-                editableTop: parseInt @options.currentEditable.offset().top
-                editableLeft: parseInt @options.currentEditable.offset().left
-                windowWidth: jQuery(window).width()
-                documentHeight: jQuery(window.document).height()
-            m.editableRight = m.editableLeft + m.editableWidth
-            m.editableBottom = m.editableTop + m.editableHeight
-            return m
-
-        _getBasicPiece: ->
-            p = jQuery('
')
-            p.css
-                position: 'absolute'
+            if jQueryfield.is "body"
+                return false;
+            else
+                return _findBackgroundColor(jQueryfield.parent())

 )(jQuery)


fixed minor bug

fixed minor bug

--- plugins/overlay.coffee
+++ plugins/overlay.coffee
@@ -48,7 +48,7 @@
                     widget.showOverlay()

                 widget.options.editable.element.bind "hallomodified", (event, data) ->
-                    if widget.visible
+                    if widget.options.visible
                         widget.updateOverlay()

                 # abort editing when pressing ESCAPE


[node_modules_koding][jraphical] added durable and deliveryMode parameter into message publishing method

--- node_modules_koding/jraphical/lib/bongo-mixin.coffee
+++ node_modules_koding/jraphical/lib/bongo-mixin.coffee
@@ -12,19 +12,25 @@
   @handleEvent = (rest...)->
     eventType = rest[0]
     eventName = rest[2]
+
+    neo4jExchangeOptions =
+      deliveryMode : 2
+      autoDelete   : no
+      durable      : yes
+
     if eventName?
       switch eventName
         when "updateInstance"
           if eventType == "static"
             data =  { event : eventName, payload : [rest[3]]}
-            @mq.emit 'neo4jFeederExchange', "", JSON.stringify(data), autoDelete: no
+            @mq.emit 'neo4jFeederExchange', "", JSON.stringify(data), neo4jExchangeOptions

           if eventType == "instance"
             data =  { event : eventName, payload : [rest[1]]}
-            @mq.emit 'neo4jFeederExchange', "", JSON.stringify(data), autoDelete: no
+            @mq.emit 'neo4jFeederExchange', "", JSON.stringify(data), neo4jExchangeOptions

         when "RelationshipSaved", "RelationshipRemoved", "RemovedFromCollection"
           data =  { event : eventName, payload : rest[3]}
-          @mq.emit 'neo4jFeederExchange', "", JSON.stringify(data), autoDelete: no
+          @mq.emit 'neo4jFeederExchange', "", JSON.stringify(data), neo4jExchangeOptions

     oldHandleEvent.apply this, rest


replace var set/get with brain var methods

--- src/brain.coffee
+++ src/brain.coffee
@@ -260,11 +260,11 @@
       return "ERR: Replies Not Sorted"

     # Initialize the user's profile?
-    if not @master._users[user]
-      @master._users[user] = {"topic": "random"}
+    if not @master.getUservars(user)
+      @master.setUservar(user, "topic", "random")

     # Collect data on this user.
-    topic     = @master._users[user].topic
+    topic     = @master.getUservar(user, "topic")
     stars     = []
     thatstars = [] # For %Previous
     reply     = ""
@@ -272,7 +272,8 @@
     # Avoid letting them fall into a missing topic.
     if not @master._topics[topic]
       @warn "User #{user} was in an empty topic named '#{topic}'"
-      topic = @master._users[user].topic = "random"
+      topic = "random"
+      @master.setUservar(user, "topic", topic)

     # Avoid deep recursion.
     if step > @master._depth
@@ -522,7 +523,7 @@
           @warn "Infinite loop looking for topic tag!"
           break
         name = match[1]
-        @master._users[user].topic = name
+        @master.setUservar(user, "topic", name)
         reply = reply.replace(new RegExp("{topic=" + utils.quotemeta(name) + "}", "ig"), "")
         match = reply.match(/\{topic=(.+?)\}/i)

@@ -536,7 +537,7 @@
           break
         name = match[1]
         value = match[2]
-        @master._users[user][name] = value
+        @master.setUservar(user, name, value)
         reply = reply.replace(new RegExp("<set " + utils.quotemeta(name) + "=" + utils.quotemeta(value) + ">", "ig"), "")
         match = reply.match(/<set (.+?)=(.+?)>/i)
     else
@@ -685,9 +686,7 @@
       match = regexp.match(/<get (.+?)>/i)
       if match
         name = match[1]
-        rep  = 'undefined'
-        if typeof(@master._users[user][name]) isnt "undefined"
-          rep = @master._users[user][name]
+        rep = @master.getUservar(user, name)
         regexp = regexp.replace(new RegExp("<get " + utils.quotemeta(name) + ">", "ig"), rep.toLowerCase())

     # Filter in input/reply tags.
@@ -868,7 +867,7 @@
         # <set> user vars
         parts = data.split("=", 2)
         @say "Set uservar #{parts[0]} = #{parts[1]}"
-        @master._users[user][parts[0]] = parts[1]
+        @master.setUservar(user, parts[0], parts[1])
       else if tag is "add" or tag is "sub" or tag is "mult" or tag is "div"
         # Math operator tags
         parts = data.split("=")
@@ -876,17 +875,17 @@
         value = parts[1]

         # Initialize the variable?
-        if typeof(@master._users[user][name]) is "undefined"
-          @master._users[user][name] = 0
+        if @master.getUservar(user, name) is "undefined"
+          @master.setUservar(user, name, 0)

         # Sanity check
         value = parseInt(value)
         if isNaN(value)
           insert = "[ERR: Math can't '#{tag}' non-numeric value '#{value}']"
-        else if isNaN(parseInt(@master._users[user][name]))
+        else if isNaN(parseInt(@master.getUservar(user, name)))
           insert = "[ERR: Math can't '#{tag}' non-numeric user variable '#{name}']"
         else
-          result = parseInt(@master._users[user][name])
+          result = parseInt(@master.getUservar(user, name))
           if tag is "add"
             result += value
           else if tag is "sub"
@@ -901,11 +900,9 @@

           # No errors?
           if insert is ""
-            @master._users[user][name] = result
+            @master.setUservar(user, name, result)
       else if tag is "get"
-        insert = if typeof(@master._users[user][data] isnt "undefined") \
-          then @master._users[user][data] \
-          else "undefined"
+        insert = @master.getUservar(user, data)
       else
         # Unrecognized tag, preserve it
         insert = "\x00#{match}\x01"
@@ -926,7 +923,7 @@
         break

       name = match[1]
-      @master._users[user].topic = name
+      @master.setUservar(user, "topic", name)
       reply = reply.replace(new RegExp("{topic=" + utils.quotemeta(name) + "}", "ig"), "")
       match = reply.match(/\{topic=(.+?)\}/i) # Look for more


trim user's sentence after punctuation removal

--- src/brain.coffee
+++ src/brain.coffee
@@ -398,7 +398,9 @@
     else
       # For everything else, strip all non-alphanumerics
       msg = utils.stripNasties(msg, @utf8)
-
+
+	# cut leading and trailing blanks once punctuation dropped office
+    msg = msg.trim()
     return msg

   ##


add NotePool for performance

add NotePool for performance


Remove unnecessary code

Remove unnecessary code

--- src/chart.coffee
+++ src/chart.coffee
@@ -224,9 +224,3 @@
   validateData: (data) ->
     if !(_.isArray(data) or _.isObject(data))
       throw new TypeError "#{data} is not an array or object"
-
-# For test on Node.js
-if module?.exports?
-  module.exports.Chart = Chart
-  global._ = require 'underscore'
-  global.d3 = require 'd3'


coordinator: Fix sending of IIPs when started

this.started check did not have the right 'this'

--- src/coordinator.coffee
+++ src/coordinator.coffee
@@ -326,7 +326,7 @@
   addInitial: (partId, portId, data, callback) ->
     id = iipId partId, portId
     @iips[id] = data
-    waitForParticipant @, partId, (err) ->
+    waitForParticipant @, partId, (err) =>
       return callback err if err
       if @started
         @sendTo partId, portId, data, (err) ->


router: handle not found case properly

router: handle not found case properly

--- src/core/router.coffee
+++ src/core/router.coffee
@@ -137,6 +137,7 @@
     qs = @utils.stringifyQuery query
     path += "?#{qs}"  if qs.length

+    notFound = no
     for edge in frags
       if node[edge]
         node = node[edge]
@@ -145,11 +146,13 @@
         if param?
           params[param.name] = edge
           node = param
-        else @handleNotFound frags.join '/'
+        else notFound = yes

     if not suppressListeners and shouldPushState and not replaceState and path is @currentPath
       @emit 'AlreadyHere', path, { params, frags }
       return
+
+    @handleNotFound frags.join '/'  if notFound

     @currentPath = path


cleaning up array constructions

cleaning up array constructions

--- src/color.coffee
+++ src/color.coffee
@@ -157,14 +157,14 @@

       lighten: (amount) ->
         hsl = self.toHsl()
-        hsl[0] = hsl[0].round()
+        hsl[0] = hsl[0]
         hsl[2] = hsl[2] + amount

         return Color(hslToRgb(hsl))

       darken: (amount) ->
         hsl = self.toHsl()
-        hsl[0] = hsl[0].round()
+        hsl[0] = hsl[0]
         hsl[2] = hsl[2] - amount

         return Color(hslToRgb(hsl))


[Dates] Use r.now() instead of new Date for better display in the console

r.now() produces "Sat Apr 25 2015 06:04:23 GMT+00:00" instead of:
```
{
  "$reql_type$": "TIME",
  "epoch_time": 1429941480.221,
  "timezone": "+00:00"
}
```.

Both work with RethinkDB's treatment of Date objects.

--- server/codes/Codes.coffee
+++ server/codes/Codes.coffee
@@ -29,7 +29,7 @@
     userMobileNumber
     message
     code
-    sentTime: new Date
+    sentTime: r.now()
     ip
   }


changing timings

changing timings

--- icivic.framer/app.coffee
+++ icivic.framer/app.coffee
@@ -57,7 +57,7 @@
 			y: report.y - 1000
 			opacity: 0
 		curve: "cubic-bezier(0.645, 0.045, 0.355, 1)"
-		time: 1
+		time: .5

 	report_list.visible = true
 	report_list.animate
@@ -70,13 +70,12 @@
 		properties:
 			opacity: 1
 		time: 1
-		delay: .2

 	spinner.animate
 		properties:
 			opacity: 1
 		delay: .5
-		time: 1.3
+		time: 1.7

 spinner.on Events.AnimationStop, ->
 	spinner.opacity = 0
@@ -88,6 +87,6 @@
 	report_item.animate
 		properties:
 			x: report_item.x + 500
-		time: .3
+		time: .5
 		curve: "spring(200, 15, 10)"


add notification while installing notifications, and final notification about the result

--- lib/sync-settings.coffee
+++ lib/sync-settings.coffee
@@ -286,15 +286,47 @@
         atom.config.set keyPath[1...], value

   installMissingPackages: (packages, cb) ->
-    pending=0
-    for pkg in packages
-      continue if atom.packages.isPackageLoaded(pkg.name) and
-        (!!pkg.apmInstallSource is !!atom.packages.getLoadedPackage(pkg.name).metadata.apmInstallSource)
-      pending++
-      @installPackage pkg, ->
-        pending--
-        cb?() if pending is 0
-    cb?() if pending is 0
+    missing_packages = (
+      pkg for pkg in packages when not atom.packages.isPackageLoaded(pkg.name) or not (!!pkg.apmInstallSource is !!atom.packages.getLoadedPackage(pkg.name).metadata.apmInstallSource))
+    if missing_packages.length is 0
+      atom.notifications.addInfo "Sync-settings: no packages to install"
+      return cb?()
+
+    notifications = {}
+    succeeded = []
+    failed = []
+    installNextPackage = =>
+      if missing_packages.length > 0
+        # start installing next package
+        pkg = missing_packages.shift()
+        i = succeeded.length + failed.length + Object.keys(notifications).length + 1
+        count = i + missing_packages.length
+        notifications[pkg.name] = atom.notifications.addInfo "Sync-settings: installing #{pkg.name} (#{i}/#{count})", {dismissable: true}
+        do (pkg) =>
+          @installPackage pkg, (error) ->
+            # installation of package finished
+            notifications[pkg.name].dismiss()
+            delete notifications[pkg.name]
+            if error?
+              failed.push(pkg.name)
+              atom.notifications.addWarning "Sync-settings: failed to install #{pkg.name}"
+            else
+              succeeded.push(pkg.name)
+            # trigger next package
+            installNextPackage()
+      else if Object.keys(notifications).length is 0
+        # last package installation finished
+        if failed.length is 0
+          atom.notifications.addSuccess "Sync-settings: finished installing #{succeeded.length} packages"
+        else
+          failed.sort()
+          failedStr = failed.join(', ')
+          atom.notifications.addWarning "Sync-settings: finished installing packages (#{failed.length} failed: #{failedStr})", {dismissable: true}
+        cb?()
+    # start as many package installations in parallel as desired
+    concurrency = Math.min missing_packages.length, 8
+    for i in [0...concurrency]
+      installNextPackage()

   installPackage: (pack, cb) ->
     type = if pack.theme then 'theme' else 'package'


No need to print the entire history each time

--- compressHistory.coffee
+++ compressHistory.coffee
@@ -12,19 +12,7 @@
 				ConversionManager.convertOldRawUpdates doc_id, (error) ->
 					return callback(error) if error?
 					console.log doc_id, "DONE"
-					db.docHistory.find { doc_id: ObjectId(doc_id) }, (error, docs) ->
-						return callback(error) if error?
-						doc = docs[0]
-						if doc?
-							for update in doc.docOps
-								op = update?.op[0]
-								if op?.i?
-									console.log doc_id, update.meta.start_ts, update.meta.end_ts, update.meta.user_id, "INSERT", op.p, op.i
-								else if op?.d?
-									console.log doc_id, update.meta.start_ts, update.meta.end_ts, update.meta.user_id, "DELETE", op.p, op.d
-						else
-							console.log doc_id, "NO HISTORY"
-						callback()
+					callback()
 	async.series jobs, (error) ->
 		throw error if error?
 		process.exit()


move to the right, looks better

move to the right, looks better

--- lib/util/progress.coffee
+++ lib/util/progress.coffee
@@ -48,4 +48,4 @@

   showTile: (p) ->
     @hideTile()
-    @tile ?= @statusBar.addLeftTile item: @progressView(p), priority: -10
+    @tile ?= @statusBar.addLeftTile item: @progressView(p)


Update license urls

Update license urls

--- src/definitions.coffee
+++ src/definitions.coffee
@@ -99,7 +99,7 @@
     name: 'Artistic License 2.0'
     priority: 8
     available: true
-    url: 'http://dev.perl.org/licenses/artistic.html'
+    url: 'http://opensource.org/licenses/Artistic-2.0'
     description: 'This is a license for software packages with the intent of giving the original copyright holder some measure of control over his software while still remaining open source. It is flexible and allows you to distribute or sell modified versions as long as you fulfill one of various conditions. Look at section 4 in the full text for a better explanation.'
     categories: ['software', 'perl']

@@ -219,7 +219,7 @@
     name: 'Apache License 2'
     priority: 4
     available: true
-    url: 'http://opensource.org/licenses/Apache-2.0'
+    url: 'http://www.apache.org/licenses/LICENSE-2.0'
     description: 'A license that allows you much freedom with the software, including an explicit right to a patent. "State changes" means that you have to include a notice in each file you modified. '
     categories: ['software', 'permissive']


payment: add plan products to details view

--- client/Dashboard/views/planlistitem.coffee
+++ client/Dashboard/views/planlistitem.coffee
@@ -9,8 +9,14 @@
         cssClass  : 'plan-child-products'
         itemClass : GroupChildProductListItem

-    if plan.childProducts?
+    @details = new KDCustomHTMLView

+    if plan.childProducts.length
+      @details.addSubView new KDCustomHTMLView
+        tagName : "h3"
+        partial : "Contains:"
+
+      @details.addSubView @childProducts.getView()
       @childProducts.instantiateListItems(
         plan.childProducts.map (product) ->
           {
@@ -26,7 +32,6 @@

       {{> @planView}}
       {{> @controls}}
-
Contains:

-      {{> @childProducts.getView()}}
+      {{> @details}}

     """


client: add announcement to public channels

--- client/app/lib/util/isPublicChannel.coffee
+++ client/app/lib/util/isPublicChannel.coffee
@@ -2,4 +2,4 @@

 module.exports = isPublicChatChannel = (channel) ->

-  return not (channel.typeConstant in ['privatemessage', 'collaboration', 'bot'])
+  return not (channel.typeConstant in ['privatemessage', 'collaboration', 'bot', 'announcement'])


Added preview pane to tabview plus menu.

--- client/ide/views/tabview/idetabview.coffee
+++ client/ide/views/tabview/idetabview.coffee
@@ -24,6 +24,8 @@
         callback     : => @createEditor()
       "Terminal"     :
         callback     : => @createTerminal()
+      "Browser"      :
+        callback     : => @createPreview()
       "Drawing Board":
         callback     : => @createDrawingBoard()
     }
@@ -53,5 +55,12 @@
     pane.addSubView new DrawingPane
     @tabView.addPane pane

+  createPreview: ->
+    pane   = new KDTabPaneView
+      name : "Browser"
+
+    pane.addSubView new PreviewPane
+    @tabView.addPane pane
+
   removeOpenDocument: ->
     # TODO: This method is legacy, should be reimplemented in ace bundle.


fixing bug where only image names were being used

--- src/giphy.coffee
+++ src/giphy.coffee
@@ -149,6 +149,7 @@
   getUriFromResultDataWithMaxSize: (images, size = 0, allowLargerThanMaxSize = false) ->
     if images and images.length and size > 0
       imagesBySize = Object.keys images
+        .map (x) -> images[x]
         .sort (a, b) -> a.size - b.size

       allowedImages = imagesBySize


tab through hats

tab through hats

--- popup.coffee
+++ popup.coffee
@@ -6,20 +6,20 @@
 update = ->
   chrome.storage.sync.get storageKey, (got) ->
     items = got[storageKey]
-    console.log got, items
     hats = document.querySelector '#hats'
     # start with empty div
     while hats.firstChild
       hats.removeChild hats.firstChild
+    # now fill it in
     for { color, name }, i in items
       do (color, name, i) ->
         hats.insertAdjacentHTML 'beforeend', "
-          <div id=hat-#{i} style='background-color:#{color}'
+          <button id=hat-#{i} style='background-color:#{color}'
               title='Open new window with this hat'>
             #{name}

-
"
+          </button>"
         document.querySelector "#hat-#{i}"
           .addEventListener 'click', ->
             alert "hat #{i}"
@@ -37,10 +37,11 @@
               url: "edit.html?color=#{encodeURIComponent color}&name=#{
                 encodeURIComponent name}&index=#{i}"
               type: 'popup'
-              focused: yes
             ,
               ({tabs: [ child ] }) ->
                 console.log child
+    document.querySelector 'button'
+      .focus()

 window.addEventListener 'focus', update

@@ -49,7 +50,6 @@
     chrome.windows.create
       url: "edit.html?color=#{encodeURIComponent '#00ff00'}"
       type: 'popup'
-      focused: yes
     ,
       ({tabs: [ child ] }) ->
         console.log child


FIX: Minor changes in calculating top task

Task due less than 24 hours ago was not sorted correctly.

--- src/app/common/services/unit-service.coffee
+++ src/app/common/services/unit-service.coffee
@@ -327,8 +327,7 @@
       currentWeight = 0

       overdueTasks = _.filter sortedTasks, (task) ->
-        task.daysPastTargetDate() > 0
-
+        task.daysPastTargetDate() >= 0
       #
       # Step 2: select tasks not complete that are overdue. Pass tasks are done first.
       #
@@ -347,7 +346,7 @@
       #
       # Step 3: ... up to date, so look forward
       #
-      toAdd = _.filter sortedTasks, (task) -> task.daysUntilTargetDate() >= 0
+      toAdd = _.filter sortedTasks, (task) -> task.daysUntilTargetDate() > 0
       # Sort by the target_grade. Pass task are done first if same due date as others.
       toAdd = _.sortBy(toAdd, 'definition.target_grade')
       # Sort by the upcoming deadline.


combined lib and platforms/lib

combined lib and platforms/lib

--- modules/http/platforms/node/tools/index.coffee
+++ modules/http/platforms/node/tools/index.coffee
@@ -1,8 +1,116 @@

+http = require 'http'
+url = require 'url'
+
+qs = require 'querystring'
 formidable = require 'formidable'

-module.exports =
-
+module.exports = tools =
+
+    ##
+    ##
+    Agent: http.Agent
+
+    ##
+    ##
+    request: ()->
+        http.request.apply http, arguments
+
+
+    ##
+    ##
+    get: (options, fn)->
+
+        tools.parseOptions options, (err, options)->
+
+            http.get options, (res)->
+
+                tools.readResponse res, fn
+
+    ##
+    ##
+    post: (options, data, fn)->
+
+        data = qs.stringify data
+
+        tools.parseOptions options, (err, options)->
+
+            options.method ?= 'POST'
+            options.headers ?= {}
+            options.headers['Content-Type'] = 'application/x-www-form-urlencoded'
+            options.headers['Content-Length'] = data.length
+
+            #console.log options
+
+            req = http.request options, (res)->
+
+                tools.readResponse res, fn
+
+            req.write data
+
+    ##
+    ##
+    parseOptions: (options, fn)->
+
+        if typeof options is 'string'
+            options =
+                url: options
+
+        if options.url
+            #console.log url.parse options.url
+            {auth, hostname, port, path} = url.parse options.url
+            if auth
+                options.auth = auth
+            options.host = hostname
+            options.port = port
+            options.path = path
+
+        fn null, options
+
+
+    ##
+    ##
+    parseData: (req, fn)->
+
+        fn ?= (err, data)->
+            return data
+
+        if req.body
+            return fn null, req.body
+
+        if typeof req is 'string'
+            return fn null, qs.parse req
+
+        data = req.url.split('?')[1] || ''
+
+        if req.method is 'POST'
+            data += '&' if data.length
+
+            req.on 'data', (chunk)=>
+                data += chunk if chunk
+
+            req.on 'end', ()=>
+                fn null, req.body = qs.parse data
+
+        else
+            fn null, req.body = qs.parse data
+
+    ##
+    ##
+    readResponse: (res, fn)->
+        data = ''
+
+        res.on 'data', (chunk)->
+            data += chunk
+
+        res.on 'end', ()->
+            fn null, data, res
+
+        res.on 'error', fn
+
+
+    ##
+    ##
     upload: (req, res, handler, done)->

         ##


Config is now pulled from current directory. This should allow an NPM deploy

--- src/index.coffee
+++ src/index.coffee
@@ -1,7 +1,7 @@
 Server = require './Server'

 ## globals
-global.config = require '../config'
+global.config = require "#{process.cwd()}/config"
 global._      = require 'underscore'

 server = new Server


Rollback

Rollback

--- src/index.coffee
+++ src/index.coffee
@@ -134,7 +134,7 @@
           return after false

         @close() if @_closeAfterRequest is true
-        after results
+        after if params._id? then params else results

   closeAfterRequest: (value) ->
     @_closeAfterRequest = value


Checking callback

Checking callback

--- src/index.coffee
+++ src/index.coffee
@@ -65,7 +65,7 @@
     false

   processError: (e) ->
-    @errorProcessFn e
+    @errorProcessFn? e

   # Wrap function into try-catch.
   catchWrap: (fnOrObj, fnName) ->


Add #INCEPTION.

Add #INCEPTION.


Default to using system fonts for headers

--- src/index.coffee
+++ src/index.coffee
@@ -33,7 +33,10 @@
       }
     ]
     googleFonts: []
-    headerFontFamily: '"Avenir Next", "Helvetica Neue", "Segoe UI", Helvetica, Arial, sans-serif'
+    headerFontFamily: '-apple-system, BlinkMacSystemFont,
+                      "Segoe UI", "Roboto", "Oxygen",
+                      "Ubuntu", "Cantarell", "Fira Sans",
+                      "Droid Sans", "Helvetica Neue", sans-serif;'
     bodyFontFamily: 'georgia, serif'
     headerGray: 20
     headerGrayHue: 0


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/emitterable.coffee
+++ src/emitterable.coffee
@@ -37,9 +37,9 @@

   self.bind 'beforeUpdate', (dt) ->
     I.particles.invoke "trigger", "beforeUpdate", dt
-
+
   self.bind 'afterUpdate', (dt) ->
-    I.particles.invoke "trigger", "beforeUpdate", dt
+    I.particles.invoke "trigger", "afterUpdate", dt

   self.bind 'update', (dt) ->
     I.batchSize.times ->


fix master's lack of pr number

fix master's lack of pr number

--- src/index.coffee
+++ src/index.coffee
@@ -53,7 +53,7 @@

         ENV.commitMessage = exec('git --no-pager log --pretty=format:"%s" -1').replace(/\\"/g, '\\\\"')
         # will either be a PR with a number or just a commit
-        ENV.prNumber = if process.env['CI_PULL_REQUEST'] then basename(process.env['CI_PULL_REQUEST']) else null
+        ENV.prNumber = if process.env['CI_PULL_REQUEST'] then basename(process.env['CI_PULL_REQUEST']) else ''
         ENV.githubDomain  = options.githubDomain ? 'api.github.com'
         return new Bot(ENV)


Added a little timeout before closing to allow all of the locks to close before dropping the connection to the server

--- src/index.coffee
+++ src/index.coffee
@@ -119,9 +119,12 @@

   async.eachLimit objList, 1, doIt, (err) ->
     console.log "Done doing it", err
-    db.close (err) ->
-      console.error "Couldn't close database connection, #{err}" if err
-      console.log "Disconnected from mongo!"
+    setTimeout () ->
+        db.close (err) ->
+          console.error "Couldn't close database connection, #{err}" if err
+          console.log "Disconnected from mongo!"
+      ,
+          1000

 copyObjects = () ->
   console.log "Copying Objects!"


Fixed: if there was no bank, the server crashed

--- server/models/bank.coffee
+++ server/models/bank.coffee
@@ -13,11 +13,17 @@
 Bank.getBanksWithAccounts = (callback) ->
     params = group: true
     BankAccount.rawRequest 'bankWithAccounts', params, (err, banks) ->
-        uuids = []
-        uuids.push bank.key for bank in banks

-        Bank.getManyByUuid uuids, (err, banks) ->
-            callback err, banks
+        if err?
+            callback err, null
+        else if not banks?
+            callback null, []
+        else
+            uuids = []
+            uuids.push bank.key for bank in banks
+
+            Bank.getManyByUuid uuids, (err, banks) ->
+                callback err, banks

 Bank.getManyByUuid = (uuids, callback) ->


fix(minifyHtml): do not minify prior to templateCache

Wrecks formatting for markdown and syntax

--- app/templates/gulpfile.coffee
+++ app/templates/gulpfile.coffee
@@ -606,7 +606,7 @@
 		.then processCss
 		.then processSourceStyles

-gulp.task 'templateCache', ['copy:temp', 'minify:views'], ->
+gulp.task 'templateCache', ['copy:temp'], ->
 	return true if not isProd

 	options =


Add delete button that displays when the user has a node or link selected. In lockdown, only links are deleted. [#158799288]

--- src/code/views/document-actions-view.coffee
+++ src/code/views/document-actions-view.coffee
@@ -13,11 +13,34 @@

   displayName: 'DocumentActions'

+  componentDidMount: ->
+    deleteFunction = @props.graphStore.deleteSelected.bind @props.graphStore
+    @props.graphStore.selectionManager.addSelectionListener (manager) =>
+      selectedNodes     = manager.getNodeInspection() or []
+      selectedLinks      = manager.getLinkInspection() or []
+
+      @setState
+        #selectedNodes: selectedNodes
+        #selectedLinks: selectedLinks
+        selectedItems: selectedNodes.concat selectedLinks
+
   undoClicked: ->
     @props.graphStore.undo()

   redoClicked: ->
     @props.graphStore.redo()
+
+  deleteClicked: ->
+    if @state.lockdown
+      @props.graphStore.removeSelectedLinks()
+      # if @state.selectedLinks && @state.selectedLinks.length
+        # only allow deletion of links in lockdown mode
+        # @props.graphStore.removeSelectedLinks()
+
+    else #if @state.selectedItems && @state.selectedItems.length > 0
+      @props.graphStore.deleteSelected()
+
+    @props.graphStore.selectionManager.clearSelection()

   renderRunPanel: ->
     if not @props.diagramOnly
@@ -32,6 +55,10 @@

       unless @state.hideUndoRedo
         (div {className: 'misc-actions'},
+          # lockdown mode only highlight delete button when we have a link selected
+          # @state.lockdown && @state.selectedLinks && @state.selectedLinks.length > 0 && (i {className: "icon-codap-trash", onClick: @deleteClicked}
+          # )
+          @state.selectedItems && @state.selectedItems.length > 0 && (i {className: "icon-codap-trash", onClick: @deleteClicked})
           (i {className: "icon-codap-arrow-undo #{buttonClass @state.canUndo}", onClick: @undoClicked, disabled: not @state.canUndo})
           (i {className: "icon-codap-arrow-redo #{buttonClass @state.canRedo}", onClick: @redoClicked, disabled: not @state.canRedo})
         )


remove vestigal 'Snapshot Chicago'

remove vestigal 'Snapshot Chicago'

--- app/translations/en_us.coffee
+++ app/translations/en_us.coffee
@@ -42,7 +42,7 @@

   siteIntro:
     s1:
-      title: "Welcome to Snapshot Chicago"
+      title: "Welcome!"
       content: "Welcome to Chicago Wildlife Watch! In this project, we are asking you to identify animals found in camera trap photos from around the city. Your help allows us to continue our research into urban biodiversity, making the city a better home for both humans and animals."
     s2:
       title: "Identifying animals"


Talk messaging

Talk messaging

--- app/translations/en_us.coffee
+++ app/translations/en_us.coffee
@@ -4,7 +4,7 @@
     about: 'About'
     classify: 'Classify'
     profile: 'Profile'
-    discuss: 'Discuss'
+    discuss: 'Talk'
     education: 'Education'
     press: 'Press'


Update with shorter animal descriptions

Update with shorter animal descriptions

--- app/translations/en_us.coffee
+++ app/translations/en_us.coffee
@@ -179,19 +179,25 @@
     aardvark:
       label: 'Aardvark'
       description: '''
-        The elusive aardvark has a long, tubular, pig-like snout with large, pointed ears.  It has short, stout legs with large digging claws and a very rounded back that tapers into a thick tail.  This animal has skin that appears gray to pinkish-brown and is only sparsely covered with bristly hair.
+        Long, tubular, pig-like snout with large, pointed ears;
+        short, stout legs with large claws and a very rounded back that tapers into a thick tail.
+        Skin is gray to pinkish-brown and sparsely covered with bristly hair.
       '''

     aardwolf:
       label: 'Aardwolf'
       description: '''
-        The aardwolf can be easily confused for its larger cousin, the striped hyena: it has the same downward sloping build, gray/tan coat color, vertical black stripes, and a crest of long hair along its neck.  However, aardwolves are smaller than striped hyenas, and their bushy tails are tipped with black.  They only have about 3, very vertical stripes along their sides, and their black snouts are shorter and narrower than those of hyenas.
+        Has a downward sloping build, gray/tan coat, about 3 black stripes,
+        and a crest of long hair along its neck.
+        Smaller than striped hyenas, and have bushy tails with a black tip.
+        Their black snouts are shorter and narrower than those of hyenas.
       '''

     baboon:
       label: 'Baboon'
       description: '''
-        This is the largest Serengeti primate.  Baboons are olive-brown in color, with grey/pink bare patches on their rump.  Adults have large, dog-like muzzles and close-set eyes, whereas young dark brown and have flat, pink faces.
+        This is the largest Serengeti primate. Baboons are olive-brown in color, with grey/pink bare patches on their rump.
+        Adults have large, dog-like muzzles and close-set eyes, whereas young dark brown and have flat, pink faces.
       '''

     batEaredFox:
@@ -209,31 +215,44 @@
     buffalo:
       label: 'Buffalo'
       description: '''
-        Buffalo are massive and cattle like.  They dark brown to black, with relatively long, tufted tails.  Both sexes have horns but those of males are more developed and join in the middle in what is called a ‘boss’. Their large, droopy ears stick out sideways under their horns
+        Massive and cattle-like. Dark brown to black, with long, tufted tails.
+        Both sexes have horns but those of males are more developed and join in the middle.
+        Large, droopy ears stick out sideways under their horns.
       '''

     bushbuck:
       label: 'Bushbuck'
       description: '''
-        Bushbucks have a chestnut to dark brown coat, with white spots and faint stripes on their flanks.  They also have a white patch under their chin, white stripe on their lower neck, and white patch under their bushy tail.  Males have backward-pointing horns with a single twist.
+        Chestnut to dark brown coat, with white spots and faint stripes on their flanks.
+        White patch under their chin, white stripe on their lower neck,
+        and white patch under their bushy tail.
+        Males have backward-pointing horns with a single twist.
+
       '''

     caracal:
       label: 'Caracal'
       description: '''
-        A medium to large cat, the caracal is uniformly reddish-brown/tawny in color with a pale white belly.  It is relatively muscular, with hind quarters rising slightly higher than its shoulders.  The caracal looks almost as though it is wearing makeup – with darkly lined eyes, and striking black markings above its eyes and around its whiskers.  Its large, pointed ears have prominent tufts of black hair.
+        Medium to large cat, red-brown with a pale belly.
+        Fairly muscular, with hind quarters slightly higher than shoulders.
+        Darkly lined eyes, and black markings around whiskers.
+        Large, pointed ears have prominent tufts of black hair.
       '''

     cheetah:
       label: 'Cheetah'
       description: '''
-        This is a lanky, slender cat with long legs, short rounded head, and very round ears.  The cheetah is pale tawny/yellow with black spots.  The tail long and also spotted with several black rings towards the tip.  “Tears ” refers to the distinctive black line that runs from the cheetah’s eyes down its cheeks.
+        Lanky and slender with long legs; very round ears. Pale yellow with black spots.
+        Tail long and spotted with several black rings towards the tip.
+        Distinctive black lines run from eyes down cheeks.
       '''

     civet:
       label: 'Civet'
       description: '''
-        Long, and heavy-set with short legs, the civet looks like a cross between a cat and a dog.  It has a racoon-like black band across its eyes and a white muzzle, its body is generally gray with black spots that darken to solid black on the legs and tail tip.
+        Long, heavy-set with short legs; looks like a cross between a cat and a dog.
+        Black band across its eyes and a white muzzle;
+        its body is usually gray with black spots that darken to black on the legs and tail tip.
       '''

     dikDik:
@@ -257,13 +276,18 @@
     gazelleGrants:
       label: 'Gazelle (Grant\'s)'
       description: '''
-        This pale fawn gazelle has distinctive white belly, white rump, and white tail, with vertical black stripes on either side of the rump.  Juveniles have a band of darker fur along their sides that can mimic a Thomson gazelle.  Long black lines extend from both corners of their eyes.  Adult males have long, ridged horns that widen slightly towards their tips.
+        Fawn has white belly, rump, and tail, with black stripes down rump.
+        Young have a band of darker fur along their sides that can mimic a Thomson's gazelle.
+        Long black lines extend from both corners of their eyes.
+        Adult males have long, ridged horns that widen towards their tips.
       '''

     gazelleThomsons:
       label: 'Gazelle (Thomson\'s)'
       description: '''
-        Locally referred to as a “tommy,” this small, fawn-colored gazelle has a horizontal dark black stripe that runs from their elbow to hip.  They have a white rump and underbelly, but black tail.  They have dark fur running from the inner corners of their eyes to their nose.  Both sexes have ridged horns that curve up and slightly backward.
+        Horizontal dark black band runs from their elbow to hip. White rump and belly; black tail.
+        Dark fur running from the inner corners of their eyes to their nose.
+        Both sexes have ridged horns that curve up and backward.
       '''

     genet:
@@ -293,13 +317,16 @@
     hartebeest:
       label: 'Hartebeest'
       description: '''
-        This large antelope is yellowish tan with pale lower rump.  Its body slopes distinctively from shoulders towards rump.  The hartebeest has a long nose and high-set eyes.  Both sexes have horns that curve out sideways and then inward.
+        Yellow or tan with pale rump.  Body slopes distinctively from shoulders towards rump.
+        Long nose and high-set eyes. Both sexes have horns that curve out sideways and then inward.
       '''

     hippopotamus:
       label: 'Hippopotamus'
       description: '''
-        Hippos are large, rounded animal with short legs and grey to pink skin.  They have small ears and a massive, wide mouth.  Their short, thick tail is trimmed with black bristles.  You mostly see them in the cameras at night when the leave the rivers to forage.
+        Large and round with short legs and grey to pink skin.
+        Small ears and a massive, wide mouth. Short, thick tail is trimmed with black bristles.
+        Mostly seen at night.
       '''

     honeyBadger:
@@ -311,7 +338,10 @@
     hyenaSpotted:
       label: 'Hyena (spotted)'
       description: '''
-        The spotted hyena looks typically dog-like.  Juveniles have dark gray fur with black spots; both spots and fur tend to fade to red/brown in adults. Their lower legs and muzzle are black.  Their heads are broad, they have large, rather pointed ears, and they slope dramatically from shoulder to hip.
+        Looks dog-like.  Young have dark gray fur with black spots;
+        both spots and fur tend to fade to red/brown in adults.
+        Lower legs and muzzle are black. Broad heads, with large pointed ears;
+        body slopes dramatically from shoulder to hip.
       '''

     hyenaStriped:
@@ -323,7 +353,10 @@
     impala:
       label: 'Impala'
       description: '''
-        Impalas are lightly built antelopes, reddish brown in color, with paler fur on sides.  They have white under their belly and chin, and around their eyes.  They have black tufts of hair between their ears, black lines on their rump, and black spots above their heels.  Males have large, S-shaped horns.
+        Lightly built; reddish brown in color, with pale fur on sides.
+        White belly and chin, and around their eyes.
+        Black tufts of hair between their ears, black lines on their rump, and black spots above their heels.
+        Males have large, S-shaped horns.
       '''

     jackal:
@@ -341,7 +374,10 @@
     leopard:
       label: 'Leopard'
       description: '''
-        These are powerfully built, golden brown cats with black rosettes.  Leopards have a spotted face - no black lines as cheetahs have – and small, round ears.  Their long, spotted tail has bright white fur underneath the tip, which is easy to see when they curl their tails upward.
+        Muscular, golden brown with black rosettes.
+        Spotted face, no black lines, with small, round ears.
+        Long, spotted tail has bright white fur underneath the tip,
+        which is easy to see when they curl their tails upward.
       '''

     lionFemale:
@@ -359,7 +395,9 @@
     mongoose:
       label: 'Mongoose'
       description: '''
-        With short legs and a humped back, mongooses appear very weasel- or ferret-like.  The mongooses you’ll see here range in size and color – from the tiny, brown dwarf mongoose to the larger banded mongoose, to the bushy tailed white-tailed mongoose.
+        Short legs and a humped back, appears weasel or ferret-like.
+        Range in size and color – from the tiny, brown dwarf mongoose
+        to the larger banded mongoose, to the bushy tailed white-tailed mongoose.
       '''

     ostrich:
@@ -377,7 +415,10 @@
     reedbuck:
       label: 'Reedbuck'
       description: '''
-        Reedbucks range in color from tan to reddish brown.  They have white bellies and a  short fluffy tail with a white underside.  The have a dark black nose, with white mouth and chin, and a black spot beneath their large ears.  Males have forward-curving ridged horns.
+        Range in color from tan to red brown.
+        White belly and a short fluffy tail with a white underside.
+        Black nose, white mouth and chin, and a black spot beneath their large ears.
+        Males have forward-curving ridged horns.
       '''

     reptiles:
@@ -389,19 +430,25 @@
     rhinoceros:
       label: 'Rhinoceros'
       description: '''
-        Despite its name, the black rhino is grey.  It is immediately recognizable by the large horn on its nose, which can get up to 60cm long.  It has another smaller horn higher on its nose as well.  These are massive, thick animals and are a rare find on our camera traps.
+        Massive and thick. Grey skin.
+        1 large horn and one smaller, slightly higher on the nose.
       '''

     rodents:
       label: 'Rodents'
       description: '''
-        Though the name is deceiving, spring hares are actually rodents and not hares.  (Hares are lagomorphs, not rodents, and have their own category here.)  The springhare looks like a rabbit-sized kangaroo, with long, powerful hind legs, short front legs, a long semi-bushy, black-tipped tail.  Mainly found on the open grassland, the spring hare grazes primarily at night.  Mice are seen infrequently in the cameras because they are so small, but you might get lucky.
+        Spring hares are actually rodents and not hares.
+        The springhare looks like a rabbit-sized kangaroo, with long, powerful hind legs, short front legs, a long bushy, black-tipped tail.
+        Mice are seen infrequently in the cameras because they are so small, but you might get lucky.
       '''

     secretaryBird:
       label: 'Secretary bird'
       description: '''
-        This is a tall bird with long legs and black feathered thighs.  It has a grey neck, body and tail plumes, with black feathers across its lower back and wings.  The bare skin on its face is red and yellow.  It has several long plumes on back of its head that sometimes stick out.
+        Tall bird with long legs and black feathered thighs.
+        Grey neck, body and tail plumes, with black feathers across its lower back and wings.
+        The bare skin on its face is red and yellow.
+        Has several long plumes on back of its head that sometimes stick out.
       '''

     serval:
@@ -413,7 +460,9 @@
     topi:
       label: 'Topi'
       description: '''
-        The topi is a tall hoofed animal that is recognizable for standing sentry on termite mounds.  It has a long nose with high set eyes and horns that curve up and back.  Like the hartebeest, its body slopes steeply down from their shoulder to rump, but topis are reddish brown in color with black patches on their shoulder and hip.
+        Tall hoofed animal; red brown with black patches on shoulders and hips.
+        Long nose with high set eyes and horns that curve up and back.
+        Body slopes steeply down from shoulder to rump.
       '''

     vervetMonkey:
@@ -431,7 +480,9 @@
     waterbuck:
       label: 'Waterbuck'
       description: '''
-        Waterbucks are large, bulky antelope with brown coarse hair and a white circle around their rumps.  They have white markings on their chin and nose, and a white band runs from ear to ear under their neck. Males have ridged horns that curve first backwards then forwards towards the tips.
+        Large, bulky antelope with brown coarse hair and a white circle around rump.
+        White markings on chin and nose, and a white band runs from ear to ear under neck.
+        Males have ridged horns that curve first backwards then forwards towards the tips.
       '''

     wildcat:
@@ -443,7 +494,10 @@
     wildebeest:
       label: 'Wildebeest'
       description: '''
-        This long-legged, migratory antelope has dark grey-brown fur with faint stripes of darker fur on its neck and flank.  It has a large head with a rounded black nose and white ‘beard’.  It stands higher at the shoulder than the rump.  Both sexes have horns that extend out sideways then curve sharply back towards head.
+        Long-legged, with dark grey-brown fur with faint stripes of darker fur on neck and flank.
+        Large head with a rounded black nose and white ‘beard’.
+        Stands higher at the shoulder than the rump.
+        Both sexes have horns that extend out sideways then curve sharply back towards head.
       '''

     zebra:


Hartebeest/topi confusion info, closes #39

--- app/translations/en_us.coffee
+++ app/translations/en_us.coffee
@@ -630,6 +630,11 @@

       impala: '''
         Impalas are more reddish in color, with black bands on their rumps, and black tufts of hair above their heels. They have large S-shaped horns.
+      '''
+
+      topi: '''
+        Although it has a similar body shape, the topi is darker brown than the hartebeest, with dark patches on its knees.
+        Horns curve up and then backwards, whereas hartebeest horns curve out and then inward.
       '''

     hippopotamus:


fix charts superposition

fix charts superposition

--- src/components/chart/chart.directive.coffee
+++ src/components/chart/chart.directive.coffee
@@ -29,6 +29,9 @@
             if !_.isEmpty(data.options)
               angular.extend(options,data.options)

+            # canvas has to be removed/appended to be redrawned without superposition
+            elem.children().get(0).remove()
+            elem.append('<canvas></canvas>')
             canvas = elem.children().get(0)
             ctx = canvas.getContext("2d")


figured out that == and all that are only in identifierToken due to alias resolution

--- src/lexer.coffee
+++ src/lexer.coffee
@@ -164,10 +164,11 @@
         # are: JS_KEYWORDS and STRICT_PROSCRIBED, so things like "true, false, typeof" or "eval, arguments"

     # continuing with the case above, if you are using one of the reserved words, and forcedIdentifier is false, go inside this block
+    # but also, of course, if you're not even using a reserved work and forcedIdentifier is false.
     unless forcedIdentifier
       # change id to the coffee alias (resolve the coffee alias) if it is one of those
       id  = COFFEE_ALIAS_MAP[id] if id in COFFEE_ALIASES
-      # handle these cases here for some crazy reason.
+      # handle these cases here because they were created by alias resolution!
       tag = switch id
         when '!'                 then 'UNARY'
         when '==', '!='          then 'COMPARE'


Minor performance hack.  Don't do this is real life kids, use macros instead.

--- src/lists.coffee
+++ src/lists.coffee
@@ -36,13 +36,12 @@

 nil = (-> new ConsList())()

-
 vectorp = (c) -> toString.call(c) == '[object Array]'
 cellp = (c) -> !!c.isList
-pairp = (c) -> c.isList and (c.length == 2)
-listp = (c) -> c.isList and (c.length == 2) and (cellp cdr c)
+pairp = (c) -> !!c.isList and (c.length == 2)
+listp = (c) -> !!c.isList and (c.length == 2) and (cellp cdr c)
 recordp = (c) -> Object.prototype.toString.call(c) == '[object Object]'
-nilp = (c) -> cellp(c) and c.length == 0
+nilp = (c) -> !!c.isList and c.length == 0

 cons = (a = nil, b = nil) ->
   return nil if (nilp a) and (nilp b)


Display the progress bar if some replicas are not ready -- Related to #1997

--- admin/static/coffee/namespaces/replicas.coffee
+++ admin/static/coffee/namespaces/replicas.coffee
@@ -70,6 +70,8 @@
             @universe_replicas = new NamespaceView.DatacenterReplicas universe_datacenter.get('id'), @model
             @primary_datacenter = new NamespaceView.PrimaryDatacenter model: @model

+            @render_status() # Render the status
+
         # A method that is going to call multiple methods (triggered when replica_affinities are changed
         global_trigger_for_replica: =>
             @render_acks_greater_than_replicas()
@@ -178,6 +180,12 @@
                     @.$('.replica-status').html @progress_bar.render(0, @expected_num_replicas, {}).$el
             else
                 # Blueprint was regenerated, so we can display the bar
+
+                # If a replica is not ready, we must display a progress bar.
+                # In case we don't, se skip to processing (we do not show the "Started stage"
+                if num_replicas_not_ready > 0 and @progress_bar.stage is 'none'
+                    @progress_bar.skip_to_processing() # We set the state to processing
+
                 if num_replicas_ready+num_replicas_not_ready is @expected_num_replicas
                     @.$('.replica-status').html @progress_bar.render(num_replicas_ready, num_replicas_ready+num_replicas_not_ready, progress_bar_info).$el
                 else # The blueprint was not regenerated, so we can consider that no replica is up to date


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/flickerable.coffee
+++ src/flickerable.coffee
@@ -4,7 +4,9 @@
     player = GameObject
       alpha: 0.9

-    player.include 'Flickerab'
+    player.include 'Flickerable'
+
+

 @name Flickerable
 @module


Use appearance_code vs catalog_offering_identifier

A course isn't required to have a `catalog_offering_identifier` but
should still be able to be styled

--- src/flux/course.coffee
+++ src/flux/course.coffee
@@ -92,12 +92,9 @@
         if not name? or name is ''
           return ['required']

-    # This is currently bassed on the course title.
-    # eventually the backend will provide it as part of the course's metadata.
-    getCategory: (courseId) ->
-      return @_get(courseId).catalog_offering_identifier or (
-        this.exports.getShortName.call(this, courseId).toLowerCase()
-      )
+    # Returns the configured appearance code for a course
+    getAppearanceCode: (courseId) ->
+      return @_get(courseId)?.appearance_code or 'default'

     getShortName: (courseId) ->
       title = @_get(courseId)?.name or ""


filter http errors

filter http errors

--- angular/core/services/exception_handler.coffee
+++ angular/core/services/exception_handler.coffee
@@ -9,7 +9,7 @@
     host:       AppConfig.errbit.url

   client.addFilter( (notice) ->
-    notice.context.environment = 'production'
+    return null if notice.errors[0].type == ""
     notice
   )


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/bounded.coffee
+++ test/bounded.coffee
@@ -23,7 +23,7 @@
   bounds = obj.centeredBounds()

   equals bounds.x, (-5 / 2) + (100 / 2)
-  equals bounds.y, 30
+  equals bounds.y, (20 / 2) + (200 / 2)

 test "Bounds returns correct x, y when called with offset", ->
   obj = GameObject


Updating CLI test

Updating CLI test

--- test/cliSpec.coffee
+++ test/cliSpec.coffee
@@ -116,7 +116,6 @@
     it 'should add a update a host in an existent .authrc file', (done) ->

       suppose("#{cwd}/bin/authrc", ['update', 'my.site.org'])
-        .debug(fs.createWriteStream('../../cli.log'))
         .on(/user name/).respond('john\n')
         .on(/Enter the password:/).respond('n€w_p@ssw0rd\n')
         .on(/Confirm the password/).respond('n€w_p@ssw0rd\n')


Adjustments to logging.

Adjustments to logging.

--- app/assets/javascripts/angular-services.coffee
+++ app/assets/javascripts/angular-services.coffee
@@ -11,6 +11,8 @@
 pwgLogging = ->
   log      = log4javascript.getLogger()
   appender = new log4javascript.BrowserConsoleAppender()
+
+  log4javascript.setShowStackTraces true

   # Allow the console appender to use the default NullLayout, which allows
   # for the logging of objects without converting them to strings.


charts: fixed table view

charts: fixed table view

--- app/assets/javascripts/lib/models/chart.coffee
+++ app/assets/javascripts/lib/models/chart.coffee
@@ -103,7 +103,7 @@
         present_value: Metric.autoscale_value(s.safe_present_value(), unit, 2)
         future_value:  Metric.autoscale_value(s.safe_future_value(),  unit, 2)
     # some charts draw series bottom to top. Let's flip the array
-    return items.reverse() if type in ['vertical_stacked_bar', 'bezier']
+    return items.reverse() if @get('type') in ['vertical_stacked_bar', 'bezier']
     items

   # raw array of the associated gqueries. Delegates to the collection object


Fix wrong indention.

Fix wrong indention.

--- src/haml-coffee.coffee
+++ src/haml-coffee.coffee
@@ -294,7 +294,7 @@

     # Render the template
     template += "#{ namespace }['#{ templateName }'] = (context) ->\n"
-    template += indent(@precompile(), 2)
+    template += indent(@precompile(), 1)
     template += "fn.call(context)"

     template
@@ -353,7 +353,7 @@
     fn  += "#{ code }\n"
     fn  += "$o.join(\"\\n\")#{ @cleanupWhitespace(code) }"

-    "fn = ->\n#{ indent(fn, 2) }\n"
+    "fn = ->\n#{ indent(fn, 1) }\n"

   # Create the CoffeeScript code for the template.
   #


test class instance's properties

test class instance's properties

--- tests/simple.coffee
+++ tests/simple.coffee
@@ -61,9 +61,9 @@
             log "test2"
             test()

-    v = new OOO('vvv')
+    v = new OOO('名字')
     v.ask2()
-
+    log v.name


add note about browserify

add note about browserify

--- app/templates/gulp/tasks/browserSync.coffee
+++ app/templates/gulp/tasks/browserSync.coffee
@@ -1,5 +1,6 @@
 gulp         = require "gulp"

+# add your vhost to secrets.coffee to allow for live reloading and css injection
 secret = require '../secrets'

 gulp.task 'browser-sync', () ->


fetch correct prepaids in managelicenseview in shared-classroom (#6797)

Co-authored-by: smallst_wsl <6c42689ff77371401bf43b7d56b93ac1ca3e92d3@163.com>

--- app/views/courses/ManageLicenseModal.coffee
+++ app/views/courses/ManageLicenseModal.coffee
@@ -45,7 +45,7 @@
     @users.comparator = (user) -> user.broadName().toLowerCase()
     @prepaids = new Prepaids()
     @prepaids.comparator = 'endDate' # use prepaids in order of expiration
-    @supermodel.trackRequest @prepaids.fetchMineAndShared()
+    @supermodel.trackRequest @prepaids.fetchForClassroom(@classroom) # do we need this or just passing prepaids from parent view?
     @classrooms = new Classrooms()
     @selectedPrepaidType = null
     @prepaidByGroup = {}


class objects need orefs too

class objects need orefs too

--- src/java_object.coffee
+++ src/java_object.coffee
@@ -111,6 +111,7 @@

 class root.JavaClassObject extends root.JavaObject
   constructor: (rs, @$type, defer_init=false) ->
+    @ref = rs.high_oref++
     @type = types.c2t 'java/lang/Class'
     @fields = {}
     @init_fields(rs) unless defer_init


TAP5-2353: It should be possible to unregister DOM event listeners

--- tapestry-core/src/main/preprocessed-coffeescript/org/apache/tapestry5/t5-core-dom.coffee
+++ tapestry-core/src/main/preprocessed-coffeescript/org/apache/tapestry5/t5-core-dom.coffee
@@ -136,6 +136,8 @@
   # Event handlers may return false to stop event propogation; this prevents an event from bubbling up, and
   # prevents any browser default behavior from triggering.  This is often easier than accepting the `EventWrapper`
   # object as the first parameter and invoking `stop()`.
+  #
+  # Returns a function of no parameters that removes any added handlers.

   onevent = (jqueryObject, eventNames, match, handler) ->
     throw new Error "No event handler was provided." unless handler?
@@ -156,7 +158,8 @@

     jqueryObject.on eventNames, match, wrapped

-    return
+    # Return a function to stop listening
+    -> jqueryObject.off eventNames, match, wrapped
 #elseif prototype
   # Interface between the dom's event model, and Prototype's.
   #
@@ -166,9 +169,11 @@
   # * handler - event handler function to invoke; it will be passed an `EventWrapper` instance as the first parameter,
   #   and the memo as the second parameter. `this` will be the `ElementWrapper` for the matched element.
   #
-  # Event handlers may return false to stop event propogation; this prevents an event from bubbling up, and
+  # Event handlers may return false to stop event propagation; this prevents an event from bubbling up, and
   # prevents any browser default behavior from triggering.  This is often easier than accepting the `EventWrapper`
   # object as the first parameter and invoking `stop()`.
+  #
+  # Returns a function of no parameters that removes any added handlers.

   onevent = (elements, eventNames, match, handler) ->
       throw new Error "No event handler was provided." unless handler?
@@ -191,11 +196,16 @@

         return

+      eventHandlers = []
+
       for element in elements
         for eventName in eventNames
-          Event.on element, eventName, match, wrapped
-
-      return
+          eventHandlers.push (Event.on element, eventName, match, wrapped)
+
+      # Return a function to remove the handler(s)
+      ->
+        for eventHandler in eventHandlers
+          eventHandler.stop()
 #endif

   # Wraps a DOM element, providing some common behaviors.
@@ -610,6 +620,8 @@
     #   will invoke the handler.
     # * handler - function invoked; the function is passed an `EventWrapper` object, and the
     #   context (`this`) is the `ElementWrapper` for the matched element.
+    #
+    # Returns a function of no parameters that removes any added handlers.
     on: (events, match, handler) ->
       exports.on @element, events, match, handler
       return this
@@ -878,7 +890,7 @@

     ajaxRequest: ajaxRequest

-    # Used to add an event handler to an element (possibly from elements below it in the hierarch).
+    # Used to add an event handler to an element (possibly from elements below it in the hierarchy).
     #
     # * selector - CSS selector used to select elements to attach handler to; alternately,
     #   a single DOM element, or an array of DOM elements. The document is considered an element
@@ -889,6 +901,8 @@
     #   will invoke the handler.
     # * handler - function invoked; the function is passed an `EventWrapper` object, and the context (`this`)
     #   is the `ElementWrapper` for the matched element
+    #
+    # Returns a function of no parameters that removes any added handlers.
     on: (selector, events, match, handler) ->
       unless handler?
         handler = match
@@ -901,10 +915,10 @@
       events = utils.split events
 #endif
       onevent elements, events, match, handler
-      return

     # onDocument() is used to add an event handler to the document object; this is used
     # for global (or default) handlers.
+    # Returns a function of no parameters that removes any added handlers.
     onDocument: (events, match, handler) ->
       exports.on document, events, match, handler


Fix typo

Fix typo

--- src/languages/c.coffee
+++ src/languages/c.coffee
@@ -137,7 +137,7 @@
      # Check to see whether the called method is a single identifier, like `puts` in
      # `getc()`, rather than `getFunctionPointer()()` or `a.b()`
      node.children[0].children[0].type is 'primaryExpression' and
-     node.children[0].children[0].children[0].type is 'Identifier' and
+     node.children[0].children[0].children[0].type is 'Identifier'

     # If all of these are true, we have a function name to give
     return node.children[0].children[0].children[0].data.text


Fixes that all sidebars-navs are hidden

Fixes that all sidebars-navs are hidden

--- app/assets/javascripts/bsat/sidebar.js.coffee
+++ app/assets/javascripts/bsat/sidebar.js.coffee
@@ -60,5 +60,5 @@

   path = $('nav#sidebar').find('li.active a').parents('ul').attr('id')
   if path
-    $('nav#sidebar').find('ul.nav').addClass 'hidden'
+    $('nav#sidebar').has('.subnav-menu').find('ul.nav').addClass 'hidden'
     $('nav#sidebar').find("##{path}").removeClass 'hidden'


Add the coffeescript.

Add the coffeescript.

--- app/assets/javascripts/dashing_json.js.coffee
+++ app/assets/javascripts/dashing_json.js.coffee
@@ -0,0 +1,30 @@
+# Let's make the json extra pretty.
+#
+# Adapted from Pumbaa80's answer on:
+# http://stackoverflow.com/questions/4810841/json-pretty-print-using-javascript
+
+$ ->
+  json.syntaxHighlight()
+
+
+json =
+  syntaxHighlight: ->
+    for jsonElem in $('.dashing-json')
+      do (jsonElem) ->
+        jsonData = $(jsonElem).attr('data-dashing-json')
+        if(typeof jsonData != 'string')
+          jsonData = JSON.stringify(jsonData, undefined, 2)
+        jsonData = jsonData.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
+        $('.parsed-json').append(json.doSyntaxHighlighting(jsonData))
+
+  doSyntaxHighlighting: (jsonData) ->
+    jsonData.replace /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, (match) ->
+      if(/^"/.test(match))
+        cls = if /:$/.test(match) then 'key' else 'string'
+      else if(/true|false/.test(match))
+        cls = 'boolean'
+      else if (/null/.test(match))
+        cls = 'null'
+      else if (/[0-9]+/.test(match))
+        cls = 'number'
+      return '
' + match + '
'


don't display passwords in check args

don't display passwords in check args

--- app/assets/javascripts/models/check.js.coffee
+++ app/assets/javascripts/models/check.js.coffee
@@ -21,8 +21,16 @@
     args_str: ->
       args = @get("args")
       if ! args
-        return null
-      _.map(args, (val, key) -> key + " = " + val ).join(", ")
+        return ""
+
+      _.map(args, (val, key) ->
+        s = key + " = "
+        if _.contains(["password", "pass", "pw"], key)
+          s += "[hidden]"
+        else
+          s += val
+        return s
+      ).join(", ")

   class exports.CheckList extends Stark.Collection


Fix bug on presentations list

Fix bug on presentations list

--- app/assets/javascripts/presentation.js.coffee
+++ app/assets/javascripts/presentation.js.coffee
@@ -18,12 +18,12 @@
         when 33, 37, 38 # Page Up, Left, Up
           e.preventDefault()
           previousItem = $("#presentation-list .current").prev()
-          moveToSlide(previousItem) if previousItem?
+          moveToSlide(previousItem) if previousItem.length > 0

         when 34, 39, 40 # Page Down, Right, Down
           e.preventDefault()
           nextItem = $("#presentation-list .current").next()
-          moveToSlide(nextItem) if nextItem?
+          moveToSlide(nextItem) if nextItem.length > 0

     $("#presentation-list li").on "click", ->
       moveToSlide(@)


[Dropdown] Handle case when above and below isn't enough space

--- app/assets/javascripts/rdb.ui.dropdown.coffee
+++ app/assets/javascripts/rdb.ui.dropdown.coffee
@@ -39,17 +39,41 @@
         closeAll()
         link.addClass('rdb-active')

+        container
+          .find('.rdb-dropdown-container')
+          .css('max-height', 'inherit')
+
         offset = link.offset()

         position =
           left: offset.left
           top: offset.top + link.outerHeight()

+        # Check left/right
         if offset.left + container.outerWidth() > $(window).width()
           position.left = offset.left - container.outerWidth() + link.outerWidth()

-        if offset.top + container.outerHeight() > $(window).height()
-          position.top = offset.top - container.outerHeight()
+        # Padding that should always be at the top and bottom
+        SPACE_PADDING = 25
+
+        spaceAbove = offset.top - SPACE_PADDING
+        spaceBelow = $(window).height() - offset.top - link.outerHeight() - SPACE_PADDING
+
+        # Check if dialog is longer then screen space bellow button
+        if spaceBelow < container.outerHeight()
+
+          # Check if dialog is longer then screen space above
+          if spaceAbove < container.outerHeight()
+            spaceMissing = container.outerHeight() - spaceBelow - link.outerHeight()
+            position.top = offset.top - Math.min(spaceMissing, spaceAbove)
+
+            container
+              .find('.rdb-dropdown-container')
+              .css('max-height', "#{spaceAbove + spaceBelow + link.outerHeight()}px")
+
+          else
+            # We do have enough space above so move dropdown up
+            position.top = offset.top - container.outerHeight()

         container
           .css


Removed preset slide heights, except for slide-1, for better content flow

--- app/assets/javascripts/slide_sizing.js.coffee
+++ app/assets/javascripts/slide_sizing.js.coffee
@@ -1,5 +1,6 @@
 @slidesReady = () ->
-  winH = 800 # $(window).height()
+  winH = 700 # $(window).height()
   navH = $('nav').height()
-  $('.row-fullscreen').height(winH - navH)
+  # $('.row-fullscreen').height(winH - navH)
   $('#slide-1').css('margin-top', navH)
+  $('#slide-1').height(800);


assignments dragged to Saturday no longer break calendar function

test plan:
 * Navigate to calendar
 * Press "+" to create new event, switch to assignment
 * Create a few assignments on thursday, 2015-01-08
 * Drag one assignment to Saturday 2015-01-10
 * Notice that calendar does not break as it does in prod

Fixes CNVS-10532

Change-Id: Iee938249a3e3756ad73d4c5598a4a788d3b23bd9
Reviewed-on: https://gerrit.instructure.com/49104
Reviewed-by: Andrew Butterfield <c9c7a32d9a1e9779cfad12bed963960e7af36eac@instructure.com>
Tested-by: Jenkins
QA-Review: Steven Shepherd <e794458448443812fb2685675aab3bbd1a3891bc@instructure.com>
Product-Review: Matthew Wheeler <ce71fbafda91d6c8f12582e1837687d5fe592dd9@instructure.com>

--- app/coffeescripts/calendar/CommonEvent.coffee
+++ app/coffeescripts/calendar/CommonEvent.coffee
@@ -96,7 +96,9 @@
         @start.setMinutes(30)
         @start.setSeconds(0)
         @end = new Date(@start.getTime()) unless @end
-      @forceMinimumDuration()
+      else
+        # minimum duration should only be enforced if not due at midnight
+        @forceMinimumDuration()

     forceMinimumDuration: () ->
       minimumDuration = 30 * 60 * 1000 # 30 minutes


increase default column width for easier grade entry

Fixes CNVS-36917

Test plan:
* Create an assignment out of 10 points possible
* Load new gradebook
* Make sure you can enter a grade and see the whole input

Change-Id: Ia6ff551f450d5a3fe7bdfb36541a69703afc2ad4
Reviewed-on: https://gerrit.instructure.com/112936
Tested-by: Jenkins
QA-Review: KC Naegle <9fbecd016338f9910821a8a5d5d0ae4fc9abfaa5@instructure.com>
Reviewed-by: Jeremy Neander <20252aad5efdc666f083d82ab63ed0f9f72a043e@instructure.com>
Product-Review: Keith T. Garner <a1a80143a840c140f31c3495ebbd9ec906e09fed@instructure.com>

--- app/coffeescripts/gradezilla/Gradebook.coffee
+++ app/coffeescripts/gradezilla/Gradebook.coffee
@@ -1359,7 +1359,7 @@

       @allAssignmentColumns = for id, assignment of @assignments
         shrinkForOutOfText = assignment && assignment.grading_type == 'points' && assignment.points_possible?
-        minWidth = if shrinkForOutOfText then 70 else 90
+        minWidth = if shrinkForOutOfText then 140 else 90

         fieldName = @getAssignmentColumnId(id)