Insert the callback function in guardLoops into the parsetree so we don't get eval scope issues in some instances

--- app/javascripts/interrogate.coffee
+++ app/javascripts/interrogate.coffee
@@ -49,17 +49,26 @@
     # setup try catch code which we'll turn into parse trees on demand
     # I think it's more efficient to do that then try to clone the parsetree
     # everytime you need a copy of it
-    tryCatch = "
-      try {
+    getTryCatchTree = ()->
+      tryCatch = "
+        try {

-      }catch(e){
-        if(failureCallback){
-          failureCallback(e)
-        }else{
-          throw e
+        }catch(e){
+          var failureCallback;
+          if(failureCallback){
+            failureCallback(e)
+          }else{
+            throw e
+          }
         }
-      }
-    "
+      "
+      tryCatchTree = esprima.parse(tryCatch)
+      # insert the callback function passed into the guardloops method
+      if failureCallback
+        tryCatchTree.body[0].handlers[0].body.body[0] = esprima.parse(failureCallback.toString()).body[0]
+
+      tryCatchTree
+
     # Traverse through the parse tree looking for loops
     estraverse.traverse parseTree,
       countId: 0
@@ -90,7 +99,7 @@
           node.body.splice(index, 1)

           # turn the trycatch code into a parse tree and inject the loop code into the try block
-          tryCatchNode = esprima.parse(tryCatch)
+          tryCatchNode = getTryCatchTree()
           tryCatchNode.body[0].block.body.push(errorThrowVariableNode,statement)

           # splice the trycatch code back into the original code in the correct position


make tests not fail in browser that dont support Error.captureStackTrace

--- test/error.coffee
+++ test/error.coffee
@@ -31,8 +31,9 @@
     hinoki(source, lifetime, 'a').catch hinoki.CircularDependencyError, (error) ->
       t.equal error.name, 'CircularDependencyError'
       t.equal error.message, "circular dependency `a <- a`"
-      t.equal 'string', typeof error.stack
-      t.ok error.stack.split('\n').length > 8
+      if Error.captureStackTrace?
+        t.equal 'string', typeof error.stack
+        t.ok error.stack.split('\n').length > 8

       t.deepEqual error.path, ['a', 'a']
       t.deepEqual lifetime, {}
@@ -48,8 +49,9 @@
     hinoki(source, lifetime, 'a').catch hinoki.CircularDependencyError, (error) ->
       t.equal error.name, 'CircularDependencyError'
       t.equal error.message, "circular dependency `a <- b <- a`"
-      t.equal 'string', typeof error.stack
-      t.ok error.stack.split('\n').length > 8
+      if Error.captureStackTrace?
+        t.equal 'string', typeof error.stack
+        t.ok error.stack.split('\n').length > 8

       t.deepEqual error.path, ['a', 'b', 'a']
       t.deepEqual lifetime, {}
@@ -67,8 +69,9 @@
   hinoki(source, lifetime, 'a').catch hinoki.ErrorInFactory, (error) ->
     t.equal error.name, 'ErrorInFactory'
     t.equal error.message, "error in factory for `a`. original error `Error: fail`"
-    t.equal 'string', typeof error.stack
-    t.ok error.stack.split('\n').length > 8
+    if Error.captureStackTrace?
+      t.equal 'string', typeof error.stack
+      t.ok error.stack.split('\n').length > 8

     t.deepEqual error.path, ['a']
     t.equal error.factory, a
@@ -86,8 +89,9 @@
   hinoki(source, lifetime, 'a').catch hinoki.FactoryReturnedUndefinedError, (error) ->
     t.equal error.name, 'FactoryReturnedUndefinedError'
     t.equal error.message, "factory for `a` returned undefined"
-    t.equal 'string', typeof error.stack
-    t.ok error.stack.split('\n').length > 8
+    if Error.captureStackTrace?
+      t.equal 'string', typeof error.stack
+      t.ok error.stack.split('\n').length > 8

     t.deepEqual error.path, ['a']
     t.equal error.factory, a
@@ -106,8 +110,9 @@
   hinoki(source, lifetime, 'a').catch hinoki.PromiseRejectedError, (error) ->
     t.equal error.name, 'PromiseRejectedError'
     t.equal error.message, "promise returned from factory for `a` was rejected. original error `Error: fail`"
-    t.equal 'string', typeof error.stack
-    t.ok error.stack.split('\n').length > 8
+    if Error.captureStackTrace?
+      t.equal 'string', typeof error.stack
+      t.ok error.stack.split('\n').length > 8

     t.deepEqual error.path, ['a']
     t.equal error.error, rejection
@@ -126,8 +131,9 @@
     hinoki(source, lifetime, 'a').catch hinoki.BadFactoryError, (error) ->
       t.equal error.name, 'BadFactoryError'
       t.equal error.message, "factory for `a` has to be a function, object of factories or array of factories but is `number`"
-      t.equal 'string', typeof error.stack
-      t.ok error.stack.split('\n').length > 8
+      if Error.captureStackTrace?
+        t.equal 'string', typeof error.stack
+        t.ok error.stack.split('\n').length > 8

       t.deepEqual error.path, ['a']
       t.equal error.factory, 1
@@ -150,8 +156,9 @@
     hinoki(source, lifetime, 'b').catch hinoki.BadFactoryError, (error) ->
       t.equal error.name, 'BadFactoryError'
       t.equal error.message, "factory for `a[b][c][2]` has to be a function, object of factories or array of factories but is `string`"
-      t.equal 'string', typeof error.stack
-      t.ok error.stack.split('\n').length > 8
+      if Error.captureStackTrace?
+        t.equal 'string', typeof error.stack
+        t.ok error.stack.split('\n').length > 8

       t.deepEqual error.path, ['a[b][c][2]', 'b']
       t.equal error.factory, 'fail'
@@ -175,8 +182,9 @@
     hinoki(source, lifetime, 'b').catch hinoki.BadFactoryError, (error) ->
       t.equal error.name, 'BadFactoryError'
       t.equal error.message, "factory for `a[2][c][d]` has to be a function, object of factories or array of factories but is `string`"
-      t.equal 'string', typeof error.stack
-      t.ok error.stack.split('\n').length > 8
+      if Error.captureStackTrace?
+        t.equal 'string', typeof error.stack
+        t.ok error.stack.split('\n').length > 8

       t.deepEqual error.path, ['a[2][c][d]', 'b']
       t.equal error.factory, 'fail'


Ensure dialog does not show on first visit after login.

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -96,6 +96,7 @@
       @tutorial.start()
     else
       @tutorial.end()
+      @tutorial.dialog.close()

   onNoLocalSubjects: =>
     getEmptySubject().select()


safe margin when calculate fee based on message length

--- app/js/controllers/trollbox.coffee
+++ app/js/controllers/trollbox.coffee
@@ -141,9 +141,13 @@
           keep_chat_down()
         , 300

+  getRequiredFee = (msgSize) ->
+    (pricing?.price + (parseInt( msgSize / 400 ) + 1) * Info.PRECISION) / Info.PRECISION
+
   checkMessageFee = (message) ->
-    msgSize = Utils.byteLength JSON.stringify(message.message)
-    feeRequired = (pricing.price + (parseInt( msgSize / 400 ) + 1) * Info.PRECISION) / Info.PRECISION
+    msgSize = Utils.byteLength JSON.stringify(message.message) - 20 # deal with marginal length problem
+    feeRequired = getRequiredFee(msgSize)
+
     return message.amount.amount / Info.PRECISION >= feeRequired

   $scope.setForm = (frm) -> form = frm
@@ -159,7 +163,7 @@
       form.message.$error.reg_acct_required = true

     msgSize = Utils.byteLength JSON.stringify($scope.chatBid)
-    $scope.feeRequired = (pricing.price + (parseInt( msgSize / 400 ) + 1) * Info.PRECISION) / Info.PRECISION
+    $scope.feeRequired = getRequiredFee(msgSize + 10) # deail with marginal length problem

     if $scope.feeRequired > $scope.from.account.balance.amount / $scope.precision
       form.$setValidity "message", false
@@ -206,8 +210,6 @@

     $scope.doSend()

-
-
   if !$scope.symbol and Info.symbol == ''
     Info.refresh_info().then ->
       $scope.symbol = Info.symbol


Remove un-intersected label

Remove un-intersected label

--- app/controllers/tools/axes.coffee
+++ app/controllers/tools/axes.coffee
@@ -88,7 +88,7 @@
       angle = 90 - Math.abs angle - 90
       label = "#{angle}°"
     else
-      label = '...'
+      label = ''

     # NOTE: Don't call the setter! It calls this render function.
     @mark.label = label


Correct the test on subsequent lock priority following an exclusive write lock. Previously, additional writers had priority. Now, readers have priority until the write_request is refreshed by one or more waiting writers.

--- test/index.coffee
+++ test/index.coffee
@@ -569,8 +569,8 @@
               assert ld?
               order += '1')

-    it "should give priority to a write request waiting on a write lock over a subsequent read request", (done) ->
-      expectedOrder = "112233"
+    it "should give priority to a read request waiting on a write lock over a subsequent write request", (done) ->
+      expectedOrder = "113322"
       order = ''
       lock1.obtainWriteLock().on 'locked', (ld) ->
         assert ld?
@@ -581,6 +581,8 @@
             lock2.releaseLock().on 'released', (ld) ->
               assert ld?
               order += '2'
+              assert.equal order, expectedOrder
+              done()
         ).once('write-req-set', () ->
             lock3.obtainReadLock().on 'locked', (ld) ->
               assert ld?
@@ -588,8 +590,6 @@
               lock3.releaseLock().on 'released', (ld) ->
                 assert ld?
                 order += '3'
-                assert.equal order, expectedOrder
-                done()
             lock1.releaseLock().on 'released', (ld) ->
               assert ld?
               order += '1')


better default location handling in geocode-promise

--- app/scripts/geocode-promise.coffee
+++ app/scripts/geocode-promise.coffee
@@ -1,5 +1,8 @@
 define ->
-	defaultLocation: new google.maps.LatLng(47.6097, -122.3331)
+	defaultLocation:
+		name: 'Seattle'
+		vicinity: 'Seattle, WA'
+		position: new google.maps.LatLng(47.6097, -122.3331)

 	initialize: (map) ->
 		# initalize Places service using Google map object (tricky Google!)
@@ -24,10 +27,7 @@
 		error = (error) =>
 			console.error error.message
 			if resolveDefault
-				promise.resolve
-					name: 'Default'
-					vicinity: 'Seattle, WA'
-					position: @defaultLocation
+				promise.resolve @defaultLocation
 			else promise.reject error
 		# make the call with the callbacks we just wrote
 		navigator.geolocation.getCurrentPosition success, error


Use new jQuery syntax

Use new jQuery syntax

--- app/js/publisher_poc/nu.nl.coffee
+++ app/js/publisher_poc/nu.nl.coffee
@@ -78,9 +78,9 @@
     """
     button_with_count = $(html)

-    button_with_count.find('.fl-overlay-annotate-button').mouseenter ->
+    button_with_count.find('.fl-overlay-annotate-button').on 'mouseenter', ->
       $('.fl-button-with-count-help-text').show()
-    button_with_count.find('.fl-overlay-annotate-button').mouseleave ->
+    button_with_count.find('.fl-overlay-annotate-button').on 'mouseleave', ->
       $('.fl-button-with-count-help-text').hide()

     button_with_count
@@ -90,9 +90,9 @@
     $('.fl-fact-count').text count

   bindActions: ->
-    $('.fl-overlay-scroll-button').click ->
+    $('.fl-overlay-scroll-button').on 'click', ->
       fact_id = $('.factlink.fl-first').first().data("factid")
       FACTLINK.scrollTo fact_id if fact_id

-    $('.fl-overlay-annotate-button').click ->
+    $('.fl-overlay-annotate-button').on 'click', ->
       FACTLINK.triggerClick()


fixed recovering from error state

fixed recovering from error state

--- app/routes/algorithmRouter.coffee
+++ app/routes/algorithmRouter.coffee
@@ -39,28 +39,31 @@
       status = AlgorithmManagement.getStatusByRoute('/' + route)
       imageName = AlgorithmManagement.generateImageName(req.body)
       if(status?)
-        #TODO Check also against deployment statuses
-        if(status.status.statusCode == 200)
-          #method with this route already exists, return an error
-          err =
-            statusCode: 500
-            statusText: 'An algorithm with the same name / type combination already exsists. Please change the name of the algorithm'
-            errorType: 'MethodDuplication'
-          sendError(res, err)
-        else if(status.status.statusCode == 410)
-          #algorithm was deleted, create a new one
-          identifier = AlgorithmManagement.createIdentifier()
-          createAlgorithm(req,res, route, identifier, imageName)
-        else if(status.status.statusCode == 500)
-          identifier = AlgorithmManagement.createIdentifier()
-          AlgorithmManagement.updateIdentifier('/'+route, identifier)
-          createAlgorithm(req, res, route, identifier, imageName)
-        else
-          response =
-            statusCode: status.status.statusCode
-            identifier: status.identifier
-            statusMessage: status.status.statusMessage
-          sendResponse res, null, response
+        switch status.status.statusCode
+          when 200
+            #method with this route already exists, return an error
+            err =
+              statusCode: 500
+              statusText: 'An algorithm with the same name / type combination already exsists. Please change the name of the algorithm'
+              errorType: 'MethodDuplication'
+            sendError(res, err)
+          when 410
+            #algorithm was deleted, create a new one
+            identifier = AlgorithmManagement.createIdentifier()
+            createAlgorithm(req,res, route, identifier, imageName)
+          when 500
+            DockerManagement.removeImage(status.image_name, (error) ->
+              if(not error?)
+                identifier = AlgorithmManagement.createIdentifier()
+                AlgorithmManagement.updateIdentifier('/'+route, identifier)
+                createAlgorithm(req, res, route, identifier, imageName)
+            )
+          else
+            response =
+              statusCode: status.status.statusCode
+              identifier: status.identifier
+              statusMessage: status.status.statusMessage
+            sendResponse res, null, response
       else
         identifier = AlgorithmManagement.createIdentifier()
         AlgorithmManagement.generateFolders(route)


refactor(vkApi): retry request if response wasn't json

If cannot parse response as JSON, retry the request.

--- app/scripts/services/vkApi.coffee
+++ app/scripts/services/vkApi.coffee
@@ -118,11 +118,15 @@
 					url: requestUrl
 					qs: data
 				, ( error, event, rawResult ) ->
-					result = JSON.parse rawResult
-					if result.error?.error_code is 6
+					try
+						result = JSON.parse rawResult
+					catch
 						setTimeout retry, context._retryDelay
-					else
-						callback result
+					finally
+						if result.error?.error_code is 6
+							setTimeout retry, context._retryDelay
+						else
+							callback result

 	request: ({ method, data, callback } = {}) ->
 		throw Error "vkApi.request - method is missing!" if not method


tiny style change

tiny style change

--- app/js/classes/publications.coffee
+++ app/js/classes/publications.coffee
@@ -1,6 +1,6 @@
 # data models

-@App.Publication = DS.Model.extend {
+@App.Publication = DS.Model.extend
   id: DS.attr 'number'
   name: DS.attr 'string'
   title: DS.attr 'string'
@@ -8,15 +8,15 @@
   url: DS.attr 'string'
   editions: DS.hasMany 'App.Edition'
   sections: DS.hasMany 'App.Section'
-}

-@App.Section = DS.Model.extend {
+
+@App.Section = DS.Model.extend
   id: DS.attr 'number'
   label: DS.attr 'string'
   intro: DS.attr 'string'
   order: DS.attr 'number'
   publication: DS.belongsTo 'App.Publication'
-}
+

 @App.Publication.FIXTURES = [
   {


turn on notifier only if server is start

--- app/templates/gulp/gulpfile.coffee
+++ app/templates/gulp/gulpfile.coffee
@@ -69,7 +69,7 @@
     )

   gulp.src PROP.path.templates()
-    .pipe $.plumber {errorHandler}
+    .pipe $.if PROP.isSrv, $.plumber {errorHandler}
     .pipe $.ignore.exclude(condition)
     .pipe $.jade jade_options
     .pipe gulp.dest PROP.path.templates("dest")
@@ -106,9 +106,9 @@

   linter = []
   gulp.src PROP.path.scripts()
-    .pipe $.plumber {errorHandler}
+    .pipe $.if PROP.isSrv, $.plumber {errorHandler}
     .pipe $.coffeelint('.coffeelintrc')
-    .pipe through2.obj ((file, enc, cb)->
+    .pipe $.if PROP.isSrv, through2.obj ((file, enc, cb)->
       c = file.coffeelint
       if c.errorCount or c.warningCount
         linter.push [c, file.relative]
@@ -209,7 +209,7 @@
   csswring = require "csswring"
   autoprefixer = require "autoprefixer-core"
   gulp.src PROP.path.styles()
-    .pipe $.plumber {errorHandler}
+    .pipe $.if PROP.isSrv, $.plumber {errorHandler}
     .pipe $.sass includePaths: [PROP.path.styles("path")]
     .pipe $.sourcemaps.init()
     .pipe $.if !PROP.isDev, $.rev.css PROP.path.styles("dest")


Clean up script paths

Clean up script paths

--- app/scripts/lib/LazerScript.coffee
+++ app/scripts/lib/LazerScript.coffee
@@ -223,13 +223,11 @@
       location: {}

     super
-      .then ->
-        console.log 'success'
       .catch =>
-        console.log 'fail'
         @alternatePath
-      .finally ->
-        console.log 'ended'
+      .finally =>
+        if @enemy.alive
+          @entity.destroy()

   spawn: ->

@@ -240,13 +238,8 @@
       @currentSequence = Math.random()
       @entity.unbind(eventName, eventHandler)
       @alternatePath = WhenJS(sequenceFunction.apply(this, args)(@currentSequence))
-        .then ->
-          console.log 'success'
         .catch =>
-          console.log 'fail'
           @alternatePath
-        .finally ->
-          console.log 'alternate path ended'
     @entity.bind(eventName, eventHandler)

   moveTo: (location, extraSettings = {}) ->


fixes #355

fixes #355

--- resource/translators/reference.coffee
+++ resource/translators/reference.coffee
@@ -248,8 +248,8 @@

     # sort attachments for stable tests, and to make non-snapshots the default for JabRef to open (#355)
     attachments.sort((a, b) ->
-      return -1 if a.mimetype == 'text/html' && b.mimetype != 'text/html'
-      return 1  if b.mimetype == 'text/html' && a.mimetype != 'text/html'
+      return 1  if a.mimetype == 'text/html' && b.mimetype != 'text/html'
+      return -1 if b.mimetype == 'text/html' && a.mimetype != 'text/html'
       return a.path.localeCompare(b.path)
     )


Don't pass a default generated element which will get attached to the prototype itself, instead create the element on the fly when the call to set imageAddress is made.

--- app/assets/javascripts/cartilage/views/image_view.js.coffee
+++ app/assets/javascripts/cartilage/views/image_view.js.coffee
@@ -22,8 +22,8 @@
   #
   @property "imageAddress", set: (url) ->
     @_imageAddress = url
-    ($ @_imageElement).attr("src", @_imageAddress)
-
+    @_imageElement = ($ "<img />").attr('src', @imageAddress)
+
   #
   # Denotes whether or not the image has finished loading.
   #
@@ -37,7 +37,7 @@
   #
   # The image element that this view manages.
   #
-  @property "imageElement", access: READONLY, default: ($ "<img/>")
+  @property "imageElement", access: READONLY

   # --------------------------------------------------------------------------

@@ -46,16 +46,17 @@
     # Initialize the View
     super(options)

-  render: ->
-    ($ @el).html @_imageElement
-
     # Bind to Events manually because event delegation will not work for
     # image load and error events...
     ($ @imageElement).load @handleLoadEvent
     ($ @imageElement).error @handleErrorEvent

+  render: ->
+    super()
+    ($ @el).html @_imageElement
+
     @
-
+
   cleanup: ->
     @clear { silent: true }
     super()


module output a liitle more distinctive

module output a liitle more distinctive

--- Framework/Framework.coffee
+++ Framework/Framework.coffee
@@ -24,18 +24,18 @@
       @include file

   includeModule: (moduleName) ->
-    Ti.API.info("Including module ..... #{moduleName}")
+    Ti.API.info("Including module ..... [#{moduleName}]")
     root.moduleNames.push moduleName
     root[moduleName] = {}
     @includePath("Common/Modules/#{moduleName}", true)

   includeDynamicModule: (moduleName) ->
-    Ti.API.info("Including Dynamic module ..... #{moduleName}")
+    Ti.API.info("Including Dynamic module ..... [#{moduleName}]")
     @unloadedModules.push moduleName

   loadDynamicModule: (moduleName) ->
     if moduleName in @unloadedModules
-      Ti.API.info("Loading Dynamic Module ..... #{moduleName}")
+      Ti.API.info("Loading Dynamic Module ..... [#{moduleName}]")
       @includeModule moduleName
       @unloadedModules = @unloadedModules.without moduleName


Use `getLoggedInUserId`

Use `getLoggedInUserId`

--- services/web/app/coffee/Features/User/UserInfoController.coffee
+++ services/web/app/coffee/Features/User/UserInfoController.coffee
@@ -3,12 +3,14 @@
 UserDeleter = require("./UserDeleter")
 UserUpdater = require("./UserUpdater")
 sanitize = require('sanitizer')
+AuthenticationController = require('../Authentication/AuthenticationController')

 module.exports = UserController =
 	getLoggedInUsersPersonalInfo: (req, res, next = (error) ->) ->
-		logger.log user: req.user, "reciving request for getting logged in users personal info"
-		return next(new Error("User is not logged in")) if !req.user?
-		UserGetter.getUser req.user._id, {
+		user_id = AuthenticationController.getLoggedInUserId(req)
+		logger.log user_id: user_id, "reciving request for getting logged in users personal info"
+		return next(new Error("User is not logged in")) if !user_id?
+		UserGetter.getUser user_id, {
 			first_name: true, last_name: true,
 			role:true, institution:true,
 			email: true, signUpDate: true
@@ -38,6 +40,3 @@
 			role: user.role
 			institution: user.institution
 		}
-
-
-


added controller constructor

added controller constructor

--- public/dreamcatcher/controllers/stream_controller.coffee
+++ public/dreamcatcher/controllers/stream_controller.coffee
@@ -1,3 +1,10 @@
 $.Controller 'Dreamcatcher.Controllers.Stream',

-  init: ->+  init: ->
+
+    $('#entry-filter, #users-filter').change( (event) =>
+      @stream.load().then (data) =>
+        @streamView.update(data.html)
+    )
+
+


Don't wait for request in http spec.

Don't wait for request in http spec.

This spec is used to crash atom-shell, we don't care if http request
succeeds.

--- spec/web/http.coffee
+++ spec/web/http.coffee
@@ -1,7 +1,4 @@
 describe 'http', ->
   describe 'sending request of http protocol urls', ->
-    it 'should not crash', (done) ->
-      $.ajax
-        url: 'http://127.0.0.1'
-        success: -> done()
-        error: -> done()
+    it 'should not crash', ->
+      $.get 'https://api.github.com/zen'


fix viz bug

fix viz bug

--- lib/markdown-preview-enhanced-view.coffee
+++ lib/markdown-preview-enhanced-view.coffee
@@ -123,7 +123,6 @@
       {@parseMD, @buildScrollMap} = require './md'
       require '../dependencies/wavedrom/default.js'
       require '../dependencies/wavedrom/wavedrom.min.js'
-      @Viz = require('../dependencies/viz/viz.js')

       @presentationConfig = @loadPresentationConfig()
       @presentationConfig.width = 960 if not @presentationConfig.width
@@ -475,12 +474,15 @@
   renderViz: ()->
     els = @element.getElementsByClassName('viz')

-    for el in els
-      if el.getAttribute('data-processed') != 'true'
-        try
-          el.innerHTML = @Viz(el.getAttribute('data-original')) # default svg
-        catch error
-          el.innerHTML = error
+    if els.length
+      @Viz ?= require('../dependencies/viz/viz.js')
+      for el in els
+        if el.getAttribute('data-processed') != 'true'
+          try
+            el.innerHTML = @Viz(el.getAttribute('data-original')) # default svg
+            el.setAttribute 'data-processed', true
+          catch error
+            el.innerHTML = error

   renderMathJax: ()->
     return if @mathRenderingOption != 'MathJax'


Fixes #2207 -- unambiguous immediate implicit closes don't close implicit objects

--- rewriter.coffee
+++ rewriter.coffee
@@ -105,17 +105,21 @@
     startsLine  = null
     sameLine    = yes
     startIndent = 0
+    startIndex  = 0

     condition = (token, i) ->
       [one, two, three] = @tokens[i + 1 .. i + 3]
       return no if 'HERECOMMENT' is one?[0]
       [tag] = token
       sameLine = no if tag in LINEBREAKS
-      ((tag in ['TERMINATOR', 'OUTDENT'] or (tag in IMPLICIT_END and sameLine)) and
-          ((!startsLine and @tag(i - 1) isnt ',') or
+      return (
+        (tag in ['TERMINATOR', 'OUTDENT'] or
+          (tag in IMPLICIT_END and sameLine and not (i - startIndex is 1))) and
+        ((!startsLine and @tag(i - 1) isnt ',') or
           not (two?[0] is ':' or one?[0] is '@' and three?[0] is ':'))) or
         (tag is ',' and one and
-          one[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT'])
+          one[0] not in ['IDENTIFIER', 'NUMBER', 'STRING', '@', 'TERMINATOR', 'OUTDENT']
+      )

     action = (token, i) ->
       tok = @generate '}', '}', token[2]
@@ -131,6 +135,7 @@
       return 1 unless tag is ':' and
         ((ago = @tag i - 2) is ':' or stack[stack.length - 1]?[0] isnt '{')
       sameLine = yes
+      startIndex = i + 1
       stack.push ['{']
       idx =  if ago is '@' then i - 2 else i - 1
       idx -= 2 while @tag(idx - 2) is 'HERECOMMENT'


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/point.coffee
+++ test/point.coffee
@@ -10,7 +10,9 @@
   test "copy constructor", ->
     p = Point(3, 7)

-    p2 = Point
+    p2 = Point(p)
+
+    equal

   test "#add", ->
     p1 = Point(5, 6)


removing AND OR NOT IS ISNT from the grammar


Tidying up tabs

Tidying up tabs

--- app/assets/javascripts/darkswarm/controllers/tabs_controller.js.coffee
+++ app/assets/javascripts/darkswarm/controllers/tabs_controller.js.coffee
@@ -1,6 +1,6 @@
 Darkswarm.controller "TabsCtrl", ($scope, $rootScope, $location, OrderCycle) ->
   $scope.active = (path)->
-    if !OrderCycle.selected() and $location.hash() == "" and path == "/about"
+    if !OrderCycle.selected() and $location.hash() == "" and path == "about"
       true
     else
       $location.hash() == path
@@ -9,10 +9,10 @@
   $scope.tabs = ["contact", "about", "groups", "producers"]
   for tab in $scope.tabs
     $scope[tab] =
-      path: "/" + tab
+      path: tab

   $scope.select = (tab)->
     if $scope.active(tab.path)
-      $location.hash "/"
+      $location.hash ""
     else
       $location.hash tab.path


ComputeUtils: cosmetic code tidy up

ComputeUtils: cosmetic code tidy up

--- workers/social/lib/social/models/computeproviders/computeutils.coffee
+++ workers/social/lib/social/models/computeproviders/computeutils.coffee
@@ -282,7 +282,7 @@
   #  - provider must be equal to provided provider
   #  - user and group must be same and user must be owner of the machine
   #  - label needs to start with provider name and ends with "-vm-{0-9}" ~ GG
-  selector   =
+  selector       =
     provider     : provider
     users        :
       $elemMatch :
@@ -294,10 +294,10 @@
         id       : group.getId()
     label        : ///^#{provider}-vm-[0-9]*$///

-  options    =
-    limit       : 1
-    sort        :
-      createdAt : -1
+  options        =
+    limit        : 1
+    sort         :
+      createdAt  : -1

   JMachine.one selector, options, (err, machine) ->

@@ -305,7 +305,6 @@
     unless machine?
       callback null, "#{provider}-vm-0"
     else
-
       index = +(machine.label.split "#{provider}-vm-")[1]
       callback null, "#{provider}-vm-#{index+1}"


[app][activity] replaced " with \"

[app][activity] replaced " with \"

--- client/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/app/Applications/Activity.kdapplication/AppController.coffee
@@ -19,7 +19,7 @@
   @clearQuotes = clearQuotes = (activities)->

     return activities = for activityId, activity of activities
-      activity.snapshot = activity.snapshot?.replace /"/g, '"'
+      activity.snapshot = activity.snapshot?.replace /"/g, '\\\"'
       activity

   constructor:(options={})->


Teamwork: Put a flag for syncWorkspace method to avoid creating panel over and over again.

--- client/landing/CollaborativeWorkspace/collaborativeworkspace.coffee
+++ client/landing/CollaborativeWorkspace/collaborativeworkspace.coffee
@@ -42,6 +42,9 @@
     @sessionKeysRef = @firebaseRef.child  "session_keys"

   syncWorkspace: ->
+    return if @workspaceSynced
+    @workspaceSynced = yes
+
     @workspaceRef.once "value", (snapshot) =>
       if @getOptions().sessionKey
         unless @reviveSnapshot(snapshot)?.keys


secure callback

secure callback

--- BackofficeBundle/Resources/public/coffee/tab/TabElementFormView.coffee
+++ BackofficeBundle/Resources/public/coffee/tab/TabElementFormView.coffee
@@ -22,5 +22,6 @@
     )

   onViewReady: ->
-  	@options.callback(this)
+    if @options.callback
+      @options.callback this
 )


Fixed response parsing

Fixed response parsing

--- implementations/hook.io-smsgw.labyrintti/lib/sender.coffee
+++ implementations/hook.io-smsgw.labyrintti/lib/sender.coffee
@@ -83,8 +83,8 @@
       return sendResponse result

   _parseResultString: (msg, body, result) ->
-    body = decodeURIComponent body
-    lines = body.split("\r\n")
+    body = decodeURIComponent body
+    lines = body.toString().split("\r\n")

     result.msg = body
     result.statuses = []
@@ -92,10 +92,13 @@
       return unless line or line.length
       line_parts = line.match /^(\+[0-9]+) (\w+) (\d+) (.+)$/

+      return unless line_parts.length
       _.each msg.recipients, (recipient) ->
-        if recipient == line_parts[1]
+        recipient = recipient.substr(1)
+        if line_parts[1].match(recipient)
           rec_status = {
             number: line_parts[1]
+            matched_number: recipient
             status: line_parts[2]
             code: parseInt line_parts[3]
             msg: line_parts[4]


Default guideIcons to an empty object (#3724)

--- app/pages/project/index.cjsx
+++ app/pages/project/index.cjsx
@@ -30,7 +30,7 @@
     background: null
     error: null
     guide: null
-    guideIcons: null
+    guideIcons: {}
     loading: false
     loadingSelectedWorkflow: false
     owner: null


Remove useless parentheses

Remove useless parentheses

--- src/Ratestate.coffee
+++ src/Ratestate.coffee
@@ -27,7 +27,7 @@
       return

     if entityId not in @_entityIds
-      @_entityIds.push(entityId)
+      @_entityIds.push entityId

     @_desiredHashes[entityId] = desiredHash
     @_desiredStates[entityId] = desiredState


OHM-224: Added check to prevent root from requesting a password change

--- src/api/users.coffee
+++ src/api/users.coffee
@@ -71,6 +71,11 @@
 ###
 exports.userPasswordResetRequest = (email) ->
   email = unescape email
+
+  if email is 'root@openhim.org'
+    this.body = "Cannot request password reset for 'root@openhim.org'"
+    this.status = 403
+    return

   # Generate the new user token here
   # set expiry date = true


graph: set subscribeable false on buckets

--- workers/social/lib/social/models/graph/fetch.coffee
+++ workers/social/lib/social/models/graph/fetch.coffee
@@ -78,6 +78,7 @@
         if @bucketNames()[value.type]
           oldSnapshot = JSON.parse(value.snapshot)
           oldSnapshot._id = randomId
+          oldSnapshot.subscribeable = false
           value.snapshot = JSON.stringify oldSnapshot

         @cacheObjects[randomId] = value


Social: remove default channel cache

Social: remove default channel cache

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -269,7 +269,6 @@
       # channelId for mapping social API
       # to internal usage
       socialApiChannelId: String
-      socialApiDefaultChannelId: String
       avatar        : String
       slug          :
         type        : String


refactored the adjusting permissions upon creation of private groups code as requested

--- workers/social/lib/social/models/group/index.coffee
+++ workers/social/lib/social/models/group/index.coffee
@@ -293,16 +293,14 @@
       # remove permissions for guest which made sense for public but not for private
       if group.privacy is 'private'
         toBeRemoved = ['read activity', 'read tags', 'list members']
-        i = permissionSet.permissions.length
-        while i--
-          if permissionSet.permissions[i].role is 'guest'
-            j = permissionSet.permissions[i].permissions.length
-            while j--
-              if permissionSet.permissions[i].permissions[j] in toBeRemoved
-                permissionSet.permissions[i].permissions.splice j, 1
-                if permissionSet.permissions[i].permissions.length <= 0
-                  permissionSet.permissions.splice i, 1
-                  break
+        for perm, i in permissionSet.permission by -1 when perm.role is 'guest'
+          for permission, j in perm.permissions by -1 when permission in toBeRemoved
+            perm.permissions.splice j, 1
+            if perm.permissions.length <= 0
+              permissionSet.permissions.splice i, 1
+              perm = null
+              break
+          permissionSet.permissions[i] = perm  if perm

       queue = [
         -> group.useSlug group.slug, (err, slug)->


remove useless user fields

remove useless user fields

--- db/schema.coffee
+++ db/schema.coffee
@@ -2,9 +2,6 @@
 User = define 'User', ->
     property 'email', String
     property 'timezone', String, default: "Europe/Paris"
-    property 'password', String
-    property 'owner', Boolean, default: false
-    property 'activated', Boolean, default: false

 Alarm = define 'Alarm', ->

@@ -57,4 +54,4 @@
                 repeat
             )?
             description?
-    ###+    ###


Minor color fix

Minor color fix

--- dev/standard.cson
+++ dev/standard.cson
@@ -193,7 +193,7 @@
     name: 'go left or right'
     elements: [
       { type: 'circle-bg', value: 'blue' }
-      { type: 'highway-both', value: 'blue' }
+      { type: 'highway-both', value: 'white' }
     ]

   prohibitory_no_u_turn:


oauth: better error msg

oauth: better error msg

--- client/Core/oauthcontroller.coffee
+++ client/Core/oauthcontroller.coffee
@@ -34,5 +34,5 @@
       mainController.emit "ForeignAuthSuccess.#{provider}"

   notify = (err)->
-    message = if err then "#{err}" else "Something went wrong"
+    message = if err then err.message else "Something went wrong"
     new KDNotificationView title : message


updated the links in vm settings popup

updated the links in vm settings popup

--- client/Main/guideslinksview.coffee
+++ client/Main/guideslinksview.coffee
@@ -3,7 +3,7 @@
   Links      =
     'Firewalls'    : 'http://learn.koding.com/guides/enable-ufw/'
     'ssh'          : 'http://learn.koding.com/guides/ssh-into-your-vm/'
-    'sudo'         : 'http://learn.koding.com/faq/what-is-my-sudo-password/'
+    'kpm'          : 'http://learn.koding.com/guides/getting-started-kpm/'
     'MySQL'        : 'http://learn.koding.com/guides/installing-mysql/'
     'Collaboration': 'http://learn.koding.com/guides/collaboration/'


Tests: Login: Fixed selector for loginFromSignupModal

--- client/test/lib/login/login.coffee
+++ client/test/lib/login/login.coffee
@@ -74,7 +74,7 @@
       .waitForElementVisible  '[testpath=main-header]', 50000
       .click                  'nav:not(.mobile-menu) [testpath=login-link]'
       .waitForElementVisible  '[testpath=login-container]', 50000
-      .click                  '[testpath=login-container] a.register'
+      .click                  '.login-footer .signup-link a.register'
       .setValue               '.main-part [testpath=register-form-email]', user.email
       .setValue               '.main-part input[name=password]', user.password
       .click                  '.main-part [testpath=signup-button]'


Add loading indicators, hide UI pre-load for /play

--- app/views/play/CampaignView.coffee
+++ app/views/play/CampaignView.coffee
@@ -70,7 +70,7 @@
     @sessions = @supermodel.loadCollection(new LevelSessionsCollection(), 'your_sessions', {cache: false}, 0).model
     @listenToOnce @sessions, 'sync', @onSessionsLoaded
     unless @terrain
-      @campaigns = @supermodel.loadCollection(new CampaignsCollection(), 'campaigns', null, 0).model
+      @campaigns = @supermodel.loadCollection(new CampaignsCollection(), 'campaigns', null, 1).model
       @listenToOnce @campaigns, 'sync', @onCampaignsLoaded
       return

@@ -126,6 +126,15 @@
     @particleMan?.destroy()
     clearInterval @portalScrollInterval
     super()
+
+  showLoading: ($el) ->
+    unless @campaign
+      @$el.find('.game-controls, .user-status').addClass 'hidden'
+      @$el.find('.portal .campaign-name span').text $.i18n.t 'common.loading'
+
+  hideLoading: ->
+    unless @campaign
+      @$el.find('.game-controls, .user-status').removeClass 'hidden'

   getLevelPlayCounts: ->
     return unless me.isAdmin()


Stopped preloading sessions for now, since it's buggy.

--- app/views/play/CampaignView.coffee
+++ app/views/play/CampaignView.coffee
@@ -369,10 +369,10 @@
     level = new Level().setURL levelURL
     level = @supermodel.loadModel(level, 'level', null, 0).model
     sessionURL = "/db/level/#{levelSlug}/session"
-    @preloadedSession = new LevelSession().setURL sessionURL
-    @preloadedSession.levelSlug = levelSlug
-    @preloadedSession.fetch()
-    @listenToOnce @preloadedSession, 'sync', @onSessionPreloaded
+    #@preloadedSession = new LevelSession().setURL sessionURL
+    #@preloadedSession.levelSlug = levelSlug
+    #@preloadedSession.fetch()
+    #@listenToOnce @preloadedSession, 'sync', @onSessionPreloaded

   onSessionPreloaded: (session) ->
     levelElement = @$el.find('.level-info-container:visible')


Minify templates.

Minify templates.

--- bebop.coffee
+++ bebop.coffee
@@ -8,8 +8,9 @@

   fn = jade.compile opts.source,
     compileDebug: false
-    debug: false
-    filename: opts.filename
+    debug:        false
+    filename:     opts.filename
+    pretty:       false

   cb null, """
   module.exports = #{JSON.stringify fn()}


collision with regular bounds

collision with regular bounds

--- src/collision.coffee
+++ src/collision.coffee
@@ -215,7 +215,6 @@
     @returns {Boolean} true if the line intersects the rectangle, false otherwise
     ###
     rayRectangle: (source, direction, target) ->
-      debugger
       unless target.xw? and target.yw?
         if target.width? and target.height?
           xw = target.width/2


activity: deprecate skip procedure in `CommentListViewController::instantiateListItems` method

--- client/Social/Activity/views/comments/commentlistviewcontroller.coffee
+++ client/Social/Activity/views/comments/commentlistviewcontroller.coffee
@@ -31,34 +31,9 @@
     windowController.on "ReceivedMouseUpElsewhere", @bound 'mouseUpHappened'

-  instantiateListItems: (items, keepDeletedComments = no) ->
+  instantiateListItems: (items) ->

-    newItems = []
-
-    items.sort (a, b) ->
-      a = a.meta.createdAt
-      b = b.meta.createdAt
-      if a<b then -1 else if a>b then 1 else 0
-
-    for comment, i in items
-
-      nextComment = items[i+1]
-
-      skipComment = no
-      if nextComment? and comment.deletedAt
-        if Date.parse(nextComment.meta.createdAt) > Date.parse(comment.deletedAt)
-          skipComment = yes
-
-      if not nextComment and comment.deletedAt
-        skipComment = yes
-
-      skipComment = no if keepDeletedComments
-
-      unless skipComment
-        commentView = @getListView().addItem comment
-        newItems.push commentView
-
-    return newItems
+    super items.sort (a, b) -> a.meta.createdAt - b.meta.createdAt

   startListeners: ->


fix(spec): fix contact store spec

fix(spec): fix contact store spec

Since it's not Promise-based anymore. It was just the spec that relied on
this.

--- spec/stores/contact-store-spec.coffee
+++ spec/stores/contact-store-spec.coffee
@@ -52,9 +52,9 @@

     it "triggers a sort on a contact refresh", ->
       spyOn(ContactStore, "_sortContactsCacheWithRankings")
-      waitsForPromise ->
-        ContactStore.__refreshCache().then -> # Non debounced version
-          expect(ContactStore._sortContactsCacheWithRankings).toHaveBeenCalled()
+      ContactStore.__refreshCache()
+      advanceClock(100)
+      expect(ContactStore._sortContactsCacheWithRankings).toHaveBeenCalled()

     it "sorts the contact cache by the rankings", ->
       spyOn(ContactRankingStore, 'value').andReturn


Fix autocomplete if it fails.

Fix autocomplete if it fails.

--- lib/completion-provider.coffee
+++ lib/completion-provider.coffee
@@ -84,6 +84,7 @@
             resultHandler: (result)->
               if result.error
                 console.log result.error
+                resolve []
               else
                 completions = window.protoRepl.parseEdn(result.value)
                 suggestions = (completionToSuggestion(prefix, c) for c in completions)


center handles in viewing area by using scaled width

--- app/assets/javascripts/components/mark/tools/text-row-tool/index.cjsx
+++ app/assets/javascripts/components/mark/tools/text-row-tool/index.cjsx
@@ -39,11 +39,11 @@
     y: DEFAULT_HEIGHT/2

   getUpperHandlePosition: ->
-    x: 100-@props.mark.x
+    x: @props.ref.props.width * @props.xScale - @props.mark.x
     y: -DEFAULT_HEIGHT

   getLowerHandlePosition: ->
-    x: 100-@props.mark.x
+    x: @props.ref.props.width * @props.xScale - @props.mark.x
     y: 0

   render: ->


Options to set written as a single line input

--- lib/written/app/assets/javascripts/written/core/content.coffee
+++ lib/written/app/assets/javascripts/written/core/content.coffee
@@ -5,10 +5,12 @@
     @element = ->
       return el

+    if options.multiline is undefined
+      options.multiline = true
     @element().addEventListener 'dragover', @over
     @element().addEventListener('drop', @preventDefaults)

-    @element().addEventListener('keypress', @linefeed)
+    @element().addEventListener('keypress', @linefeed.bind(this, options.multiline))
     @element().addEventListener('keydown', @undo)
     @element().addEventListener('keydown', @redo)
     @element().addEventListener('keydown', @cursor)
@@ -65,10 +67,11 @@
   cursor: =>
     @history.current.cursor = new Written.Cursor(@element(), window.getSelection(), @parsers)

-  linefeed: (e) =>
+  linefeed: (allowed = true, e) =>
     return unless e.which == 13
     e.preventDefault()
     e.stopPropagation()
+    return unless allowed

     cursor = new Written.Cursor(@element(), window.getSelection(), @parsers)
     @observer.pause =>


Browse reports by borough Add radio buttons to filter subject sets by borough.

--- app/choose-subject-set.cjsx
+++ app/choose-subject-set.cjsx
@@ -1,13 +1,40 @@
 React = require 'react'
+
+BOROUGHS = [
+  'Battersea'
+  'Bermondsey'
+  'Camberwell'
+]

 module.exports = React.createClass
   displayName: 'ChooseSubjectSet'

   getInitialState: ->
     subject_sets: []
+    borough: 'Battersea'

   componentWillMount: ->
-    @props.workflow?.get 'subject_sets', page_size: 40
+    @loadSubjectSets(@state.borough)
+
+
+  render: ->
+

+
Choose a report to work on

+

+        {
<input name="borough" type="radio" checked={@state.borough is borough} role="tab" aria-selected={@state.borough is borough} onChange={@selectBorough} value={borough}/>{borough}
 for borough in BOROUGHS}</
+

+

+        {
{subject_set.metadata.BOROUGH.replace(' (London, England)', '')}
{subject_set.metadata.Date}
 for subject_set in @state.subject_sets}
+

+

+
+  selectBorough: (e) ->
+    borough = e.target.value
+    @setState {borough}
+    @loadSubjectSets(borough)
+
+  loadSubjectSets: (borough) ->
+    @props.workflow?.get 'subject_sets', {page_size: 40, "metadata.BOROUGH": borough + ' (London, England)'}
       .then (subject_sets) =>
         subject_sets.sort (a, b) ->
           return 1 if a.metadata.BOROUGH > b.metadata.BOROUGH
@@ -17,14 +44,6 @@
           return 0
         @setState {subject_sets}

-  render: ->
-

-
Choose a report to work on

-

-        {
{subject_set.metadata.BOROUGH.replace(' (London, England)', '')}
{subject_set.metadata.Date}
 for subject_set in @state.subject_sets}
-

-

-
   update: (e) ->
     subject_set_id = e.currentTarget.href.split('/').pop()
     @props.onChange subject_set_id


ComponentTests: Call done() on errors

ComponentTests: Call done() on errors

--- spec/ComponentTests.coffee
+++ spec/ComponentTests.coffee
@@ -34,6 +34,9 @@
                     # TODO: map back from internal to exported port names
                     [e, node, port, type, data] = arguments
                     onReceived port, type, data
+                else if event == 'ERROR'
+                    args = Array.prototype.slice.call arguments
+                    done new Error args.join ', '
             simulator.device.open (err) ->
                 chai.expect(err).to.not.exist
                 simulator.uploadFBP prog, (err) ->


Fix accidental lowercase links on comments (#4568)

Fix accidental lowercase links on comments

--- resources/assets/coffee/react/_components/comment.coffee
+++ resources/assets/coffee/react/_components/comment.coffee
@@ -337,7 +337,7 @@
       component = a
       params =
         href: meta.url
-        className: 'comment__action'
+        className: 'comment__link'
     else
       component = span
       params = null
@@ -392,7 +392,7 @@
     if @props.linkParent
       component = a
       props.href = laroute.route('comments.show', comment: parent.id)
-      props.className = 'comment__action'
+      props.className = 'comment__link'
     else
       component = span


Fixed typo

Fixed typo

--- app/assets/javascripts/rglossa/components/centre/main_area.jsx.coffee
+++ app/assets/javascripts/rglossa/components/centre/main_area.jsx.coffee
@@ -1,5 +1,5 @@
 #= require rglossa/utils
-#= reqruie rglossa/models/corpus
+#= require rglossa/models/corpus
 #= require ./main_area_top
 #= require ./main_area_bottom


Fixed undefined function

Fixed undefined function

--- app/client/game/play.coffee
+++ app/client/game/play.coffee
@@ -110,7 +110,7 @@
   else
     # otherwise go to the next question
     Session.set('currentQuestion', question_counter + 1)
-    Template.question.startCountdown()
+    startCountdown()

 # helpers


fix repl path

fix repl path

--- lib/connection/terminal.coffee
+++ lib/connection/terminal.coffee
@@ -1,6 +1,7 @@
 child_process = require 'child_process'

 client = require './client'
+proc = require './process'

 module.exports =

@@ -30,9 +31,7 @@
     else
       'x-terminal-emulator -e'

-  jlpath: -> atom.config.get("julia-client.juliaPath")
-
-  repl: -> @term "#{@escpath @jlpath()}"
+  repl: -> @term "#{@escpath proc.jlpath()}"

   client: (port) ->
     client.booting()


Require missing helpers

Require missing helpers

--- assets/scripts/app/helpers.coffee
+++ assets/scripts/app/helpers.coffee
@@ -9,6 +9,10 @@
 require 'helpers/label'
 require 'helpers/input'
 require 'helpers/tipsy'
+require 'helpers/travis-errors'
+require 'helpers/travis-field'
+require 'helpers/travis-field'
+require 'helpers/filter-input'
 require 'helpers/capitalize'
 require 'helpers/github_commit_link'
 require 'helpers/format_time'
@@ -19,7 +23,6 @@
 require 'helpers/format_config'
 require 'helpers/short_compare_shas'
 require 'helpers/mb'
-require 'helpers/filter-input'

 Ember.Handlebars.registerHelper('label', Travis.Handlebars.label)
 Ember.Handlebars.registerHelper('input', Travis.Handlebars.input)


Disable atom rdio equalizer (make my macbook so slow)

--- apps/atom/atom.symlink/config.cson
+++ apps/atom/atom.symlink/config.cson
@@ -20,3 +20,5 @@
   'projectHome': '/Users/MoOx/Sync/Development'
 'autosave': {}
 'autocomplete-plus': {}
+'Rdio':
+  'showEqualizer (WindowResizePerformanceIssue )': false


Redirect old teachers/units dashboard to new dashboard (#589)

Blocks user from accidentally navigating back to the old dashboard.
Instead user is redirected to new dashboard.

--- app/core/Router.ozar.coffee
+++ app/core/Router.ozar.coffee
@@ -287,8 +287,8 @@
     'teachers/projects/:classroomId': go('core/SingletonAppVueComponentView')
     'teachers/classes/:classroomID/:studentID': go('teachers/TeacherStudentView', { redirectStudents: true, teachersOnly: true })
     'teachers/classes/:classroomID': teacherProxyRoute(go('courses/TeacherClassView', { redirectStudents: true, teachersOnly: true }))
-    'teachers/courses': redirect('/teachers/units') # Redirected 8/20/2019
-    'teachers/units': go('courses/TeacherCoursesView', { redirectStudents: true })
+    'teachers/courses': redirect('/teachers') # Redirected 8/20/2019
+    'teachers/units': redirect('/teachers') # Redirected 9/10/2020
     'teachers/course-solution/:courseID/:language': go('teachers/TeacherCourseSolutionView', { redirectStudents: true })
     'teachers/demo': redirect('/teachers/quote')
     'teachers/enrollments': redirect('/teachers/licenses')


Fixed #45 per @phopkins recommendation.

Fixed #45 per @phopkins recommendation.

Really unsure whether this will have an undesirable effect, as
I don't have it in my head right now how async support is being
added for Jasmine 1.x in the first place here.

--- app/js/jasmine-given.coffee
+++ app/js/jasmine-given.coffee
@@ -54,7 +54,7 @@
     mostRecentExpectations = expectations = [expectationFunction]
     mostRecentStacks = stacks = [errorWithRemovedLines("failed expectation", 3)]

-    itFunction "then #{label ? stringifyExpectation(expectations)}", doneWrapperFor expectationFunction, (jasmineDone) ->
+    itFunction "then #{label ? stringifyExpectation(expectations)}", (jasmineDone) ->
       userCommands = [].concat(whenList, invariantList, wrapAsExpectations(expectations, stacks))
       new Waterfall(userCommands, jasmineDone).flow()


update expected wallet verion

update expected wallet verion

--- app/js/services/info.coffee
+++ app/js/services/info.coffee
@@ -5,7 +5,7 @@

     is_refreshing : false

-    expected_client_version: "0.0.3"
+    expected_client_version: "0.0.1"

     get : () ->
         if Object.keys(@info).length > 0


Update vector.coffee

Update vector.coffee

Make Vector do the right thing if you forget new,

--- app/lib/world/vector.coffee
+++ app/lib/world/vector.coffee
@@ -10,7 +10,9 @@
   isVector: true
   apiProperties: ['x', 'y', 'z', 'magnitude', 'heading', 'distance', 'dot', 'equals', 'copy', 'distanceSquared', 'rotate']

-  constructor: (@x=0, @y=0, @z=0) ->
+  constructor: (x=0, y=0, z=0) ->
+     return new Vector(x,y,z) unless this instanceof Vector
+     [@x, @y, @z] = [x,y,z]

   copy: ->
     new Vector(@x, @y, @z)


in boot.coffee: on login-success, redirects to first group that user is a member of

--- app/boot.coffee
+++ app/boot.coffee
@@ -8,7 +8,9 @@

   authSuccess = (event, user) ->
     global.cobudgetApp.currentUserId = user.id
-    Records.memberships.fetchMyMemberships().then ->
+    Records.memberships.fetchMyMemberships().then (data) ->
+      if !global.cobudgetApp.currentGroupId
+        global.cobudgetApp.currentGroupId = data.groups[0].id
       membershipsLoadedDeferred.resolve(true) # when me have all of the memberships, resolve the promise -- the controller loads

   $rootScope.$on 'auth:validation-success', (event, user) ->
@@ -16,6 +18,4 @@

   $rootScope.$on 'auth:login-success', (event, user) ->
     authSuccess(event, user).then ->
-      # TODO: later, this will be the first group that the user is a member of
-      global.cobudgetApp.currentGroupId = 1
       $location.path("/groups/#{global.cobudgetApp.currentGroupId}")


Trigger command directly on atom.workspaceView

--- lib/grammar-status-view.coffee
+++ lib/grammar-status-view.coffee
@@ -11,7 +11,7 @@
     @subscribe atom.workspaceView, 'editor:grammar-changed', @updateGrammarText

     @subscribe this, 'click', =>
-      atom.workspaceView.getActiveView().trigger('grammar-selector:show')
+      atom.workspaceView.trigger('grammar-selector:show')
       false

   attach: ->


Link the demo subject set to a workflow to copy

--- app/pages/lab/workflow.cjsx
+++ app/pages/lab/workflow.cjsx
@@ -195,11 +195,8 @@
         @props.workflow.removeLink 'subject_sets', subjectSet.id

   addDemoSubjectSet: ->
-    @props.project.addLink 'subject_sets', [DEMO_SUBJECT_SET_ID]
-      .then =>
-        @props.project.get 'subject_sets'
-      .then ([subjectSet]) =>
-        @props.workflow.addLink 'subject_sets', [subjectSet.id]
+    @props.project.uncacheLink 'subject_sets'
+    @props.workflow.addLink 'subject_sets', [DEMO_SUBJECT_SET_ID]

   afterDelete: ->
     @props.project.uncacheLink 'workflows'


fix typo

fix typo

--- app/pages/lab/workflow.cjsx
+++ app/pages/lab/workflow.cjsx
@@ -353,8 +353,8 @@
             </p>
             <p className="form-help">
               <small>
-              When using "Retirement Count" the completeness will increase after each imge retires.  Since the images are
-              {' '}shown to users in a random order, this completeness estimage will be slow to increase until the project is close to being finished.
+              When using "Retirement Count" the completeness will increase after each image retires.  Since the images are
+              {' '}shown to users in a random order, this completeness estimate will be slow to increase until the project is close to being finished.
               {' '}If your project does not have a constant retirement limit (e.g. it uses a custom retiment rule) and/or subject sets
               {' '}have been unlinked from a live workflow, this estimate will be the most accurate.
               </small>


Fix orientation bug

Fix orientation bug

--- framer/Animation.coffee
+++ framer/Animation.coffee
@@ -45,7 +45,7 @@

 		super options

-		@options = _.defaults options,
+		@options = _.clone _.defaults options,
 			layer: null
 			properties: {}
 			curve: "linear"
@@ -141,7 +141,7 @@

 	reverse: ->
 		# TODO: Add some tests
-		options = _.clone @options
+		options = _.clone(@options)
 		options.properties = @_originalState
 		animation = new Animation options
 		animation


Add toString() and is for every layer

Add toString() and is for every layer

--- framer/BaseClass.coffee
+++ framer/BaseClass.coffee
@@ -4,8 +4,10 @@

 {EventEmitter} = require "./EventEmitter"

+CounterKey = "_ObjectCounter"
 DefinedPropertiesKey = "_DefinedPropertiesKey"
 DefinedPropertiesValuesKey = "_DefinedPropertiesValuesKey"
+

 class exports.BaseClass extends EventEmitter

@@ -23,6 +25,12 @@

 		Object.defineProperty @prototype, propertyName, descriptor
 		Object.__
+
+	@SimpleProperty = (name, fallback, exportable=true) ->
+		exportable: exportable
+		default: fallback
+		get: ->  @_getPropertyValue name
+		set: (value) -> @_setPropertyValue name, value

 	_setPropertyValue: (k, v) =>
 		@[DefinedPropertiesValuesKey][k] = v
@@ -53,18 +61,31 @@
 					if @constructor[DefinedPropertiesKey].exportable isnt false
 						@[k] = v

+	@define "id",
+		get: -> @_id
+
+	toString: =>
+		properties = _.map(@[DefinedPropertiesValuesKey], ((v, k) -> "#{k}:#{v}"), 4)
+		"[#{@constructor.name} id:#{@id} #{properties.join " "}]"
+

 	#################################################################
 	# Base constructor method

-	constructor: (options) ->
+	constructor: (options={}) ->

 		super

+		# Create a holde for the property values
 		@[DefinedPropertiesValuesKey] = {}

-		options ?= {}
+		# Count the creation for these objects and set the id
+		@constructor[CounterKey] ?= 0
+		@constructor[CounterKey] += 1

+		@_id = @constructor[CounterKey]
+
+		# Set the default values for this object
 		_.map @constructor[DefinedPropertiesKey], (descriptor, name) =>
 			@[name] = Utils.valueOrDefault options[name], @_getPropertyDefaultValue name


Update fs spec for new traverseTree callbacks

--- spec/stdlib/fs-spec.coffee
+++ spec/stdlib/fs-spec.coffee
@@ -62,7 +62,7 @@
       fs.makeTree("/tmp/a/b/c")
       expect(fs.exists("/tmp/a/b/c")).toBeTruthy()

-  describe ".traverseTree(path, fn)", ->
+  describe ".traverseTree(path, onFile, onDirectory)", ->
     fixturesDir = null

     beforeEach ->
@@ -70,19 +70,21 @@

     it "calls fn for every path in the tree at the given path", ->
       paths = []
-      fs.traverseTree fixturesDir, (path) ->
+      onPath = (path) ->
         paths.push(fs.join(fixturesDir, path))
         true
+      fs.traverseTree fixturesDir, onPath, onPath
       expect(paths).toEqual fs.listTree(fixturesDir)

     it "does not recurse into a directory if it is pruned", ->
       paths = []
-      fs.traverseTree fixturesDir, (path, prune) ->
+      onPath = (path) ->
         if path.match(/\/dir$/)
           false
         else
           paths.push(path)
           true
+      fs.traverseTree fixturesDir, onPath, onPath

       expect(paths.length).toBeGreaterThan 0
       for path in paths


fix default setting of sort order

fix default setting of sort order

--- app/assets/javascripts/hanuman/components/new_question.js.coffee
+++ app/assets/javascripts/hanuman/components/new_question.js.coffee
@@ -6,7 +6,7 @@

   setNewModel: ->
     model = @get('surveyStep').get('questions').content.createRecord(
-      sortOrder: @get('surveyStep').get('questions.length')
+      sortOrder: @get('surveyStep').get('questions.length') + 1
       questionText: ''
     )
     @set('model', model)


[BEAL][chrome] small code style tweak

[BEAL][chrome] small code style tweak

--- src/coffee/beal/chrome/content.coffee
+++ src/coffee/beal/chrome/content.coffee
@@ -18,6 +18,6 @@
     exports.getLastError = -> chrome.runtime.lastError

     exports.getURL = (rel) ->
-        chrome.extension.getURL(rel)
+        chrome.extension.getURL rel

 )(iidentity or (iidentity = window.iidentity = {}), window.chrome)


add gridtool project redirects (#5974)

add gridtool project redirects (#5974)

--- app/router.cjsx
+++ app/router.cjsx
@@ -173,6 +173,9 @@
     <Route path="/projects/mainehistory/beyond-borders-transcribing-historic-maine-land-documents" component={() => <RELOAD newUrl='https://fe-project.zooniverse.org/projects/mainehistory/beyond-borders-transcribing-historic-maine-land-documents' />} />
     <Route path="/projects/mainehistory/beyond-borders-transcribing-historic-maine-land-documents/classify" component={() => <RELOAD newUrl='https://fe-project.zooniverse.org/projects/mainehistory/beyond-borders-transcribing-historic-maine-land-documents/classify' />} />

+    <Route path="/projects/zookeeper/galaxy-zoo-weird-and-wonderful" component={() => <RELOAD newUrl='https://fe-project.zooniverse.org/projects/zookeeper/galaxy-zoo-weird-and-wonderful' />} />
+    <Route path="/projects/zookeeper/galaxy-zoo-weird-and-wonderful/classify" component={() => <RELOAD newUrl='https://fe-project.zooniverse.org/zookeeper/galaxy-zoo-weird-and-wonderful/classify' />} />
+
     <Route path="projects/:owner/:name" component={require('./pages/project').default}>
       <IndexRoute component={ProjectHomePage} />
       <Route path="home" component={ONE_UP_REDIRECT} />


Infinite cache

Infinite cache

--- app/src/wallet/cache.coffee
+++ app/src/wallet/cache.coffee
@@ -5,7 +5,7 @@
     @hdwallet = hdwallet

   initialize: (callback) ->
-    cacheLimitSize = @hdwallet.getAccountsCount() * 100
+    cacheLimitSize = 1 << 31 >>> 0
     @hdwallet._store.get ['cache'], (result) =>
       if result.cache?
         @_cache = LRUCache.fromJson(result.cache, cacheLimitSize)


Throw an exception if you try to pass in a model that is not in the storage manager if one exists

--- vendor/assets/javascripts/brainstem/loaders/model-loader.coffee
+++ vendor/assets/javascripts/brainstem/loaders/model-loader.coffee
@@ -6,6 +6,11 @@

   _createObjects: ->
     id = @loadOptions.only[0]
+
+    cachedModel = @storageManager.storage(@_getCollectionName()).get(id)
+
+    if cachedModel && @loadOptions.model && cachedModel != @loadOptions.model
+      throw "model already in storage manager"

     @internalObject = @storageManager.createNewModel @loadOptions.name
     @internalObject.set('id', id)


Move toggle-todo ajax logic to action

Move toggle-todo ajax logic to action

--- app/assets/javascripts/components/todos/flux.js.coffee
+++ app/assets/javascripts/components/todos/flux.js.coffee
@@ -33,24 +33,8 @@
       @emit('change')

     onToggleTodo: (payload) ->
-      params = todo:
-                 completed: payload.completed
-      $.ajax
-        method: "PATCH"
-        url: "/todos/" + payload.id
-        data: params
-      .done (data, textStatus, jqXHR) =>
-        title = if params.todo.completed then "Completed" else "Not completed"
-        todo =
-          id:        data.id
-          content:   data.content
-          completed: data.completed
-        @todos[data.id] = todo
-        @emit('change')
-        $.growl.notice title: title, message: data.content
-      .fail (jqXHR, textStatus, errorThrown) =>
-        $.growl.error title: "Error", message: "Error toggleing todo completion"
-        console.error textStatus, errorThrown.toString()
+      @todos[payload.id].completed = payload.completed
+      @emit('change')

     onUpdateTodo: (payload) ->
       params = todo:
@@ -89,6 +73,7 @@

   actions =

+    # Creates a new todo to database, and updates UI on success.
     addTodo:    (content) ->
       params = todo:
                  content: content
@@ -108,7 +93,19 @@
         console.error textStatus, errorThrown.toString()

     toggleTodo: (id, completed) ->
-      @dispatch(constants.TOGGLE_TODO, id: id, completed: completed)
+      params = todo:
+                 completed: completed
+      $.ajax
+        method: "PATCH"
+        url: "/todos/" + id
+        data: params
+      .done (data, textStatus, jqXHR) =>
+        title = if data.completed then "Completed" else "Not completed"
+        @dispatch(constants.TOGGLE_TODO, id: data.id, completed: data.completed)
+        $.growl.notice title: title, message: data.content
+      .fail (jqXHR, textStatus, errorThrown) =>
+        $.growl.error title: "Error", message: "Error toggleing todo completion"
+        console.error textStatus, errorThrown.toString()

     updateTodo: (id, new_content) ->
       @dispatch(constants.UPDATE_TODO, id: id, new_content: new_content)


Fix multiple phone or address when creating new user.

--- app/assets/javascripts/users/user.controller.js.coffee
+++ app/assets/javascripts/users/user.controller.js.coffee
@@ -11,7 +11,7 @@
   $scope.user.addresses.push $scope.user.addresses.$build() if $scope.user.addresses.length == 0

   $scope.add = (field)->
-    $scope.user[field].push {}
+    $scope.user[field].push $scope.user[field].$build()

   $scope.remove = (field, index)->
     $scope.user[field].splice(index, 1)


ComputeProviders::Koding processNonce checks nonce and updates it as used

--- workers/social/lib/social/models/computeproviders/koding.coffee
+++ workers/social/lib/social/models/computeproviders/koding.coffee
@@ -4,6 +4,38 @@
 JVM               = require '../vm'

 module.exports = class Koding extends ProviderInterface
+
+
+  @processNonce = (nonce, callback)->
+
+    unless nonce
+      return callback new KodingError
+        message : "Payment requirements missing."
+
+    JPaymentFulfillmentNonce  = require '../payment/nonce'
+    JPaymentSubscription      = require '../payment/subscription'
+    JPaymentPack              = require '../payment/pack'
+
+    JPaymentFulfillmentNonce.one { nonce }, (err, nonceObject)->
+
+      return callback err  if err
+
+      unless nonceObject
+        return callback message: "Unrecognized nonce!", nonce
+
+      if nonceObject.action isnt "debit"
+        return callback message: "Invalid nonce!", nonce
+
+      { subscriptionCode } = nonceObject
+
+      JPaymentSubscription.isFreeSubscripton subscriptionCode, \
+      (err, isFreeSubscripton)=>
+        return callback err if err
+
+        nonceObject.update $set: action: "used", (err) =>
+          return callback err  if err
+
+          callback null, { isFreeSubscripton, nonceObject }

   @ping = (client, callback)->


fail with name attribute (NO CAMELCASE)

fail with name attribute (NO CAMELCASE)

--- api/movie.coffee
+++ api/movie.coffee
@@ -20,7 +20,7 @@
         if error
           response.json message: error.message, error.code
         else
-          response.json result
+          response.json movies: result.Search

   server.get "/api/movie/info", (request, response) ->


crypto change

crypto change

--- apiclient.coffee
+++ apiclient.coffee
@@ -12,9 +12,9 @@
 		hmac.digest 'base64'

 	signPassword: (val, secret)->
-		cipher = crypto.createCipher 'aes192', secret
-		coded = cipher.update val, 'utf8', 'hex'
-		coded += cipher.final 'hex'
+		cipher = crypto.createCipher 'aes-256-cbc', secret
+		coded = cipher.update val, 'utf8', 'base64'
+		coded += cipher.final 'base64'
 		coded

 	decodeBody: (val, secret)->


Ensure data is json encoded

Ensure data is json encoded

--- client/lanes/data/Sync.coffee
+++ client/lanes/data/Sync.coffee
@@ -29,7 +29,7 @@
     start   : 's'
 }

-Lanes.Data.Sync = (method, model, options)->
+Lanes.Data.Sync = (method, model, options={})->

     query = {}
     for key, value of options
@@ -48,10 +48,10 @@
     params.headers = {
         X_CSRF_TOKEN: Lanes.Data.Config.csrf_token
     }
-    # Ensure that we have the appropriate request data.
-    if !options.data? && model && _.contains([ "create", "update", "patch" ], method )
-        params.contentType = "application/json"
-        params.data = JSON.stringify( model.dataForSave(options) )
+    params.contentType = "application/json"
+    if options.data || _.contains(['create','update','patch'], method)
+        params.data = JSON.stringify( options.data || model.dataForSave(options) )
+        delete options.data

     # Don't process data on a non-GET request.
     #params.processData = false if params.type isnt "GET"


app-settings-menu: Removed ace header bar.

--- client/landing/app/Applications/Ace.kdapplication/AppView.coffee
+++ client/landing/app/Applications/Ace.kdapplication/AppView.coffee
@@ -14,22 +14,6 @@
     super

     @listenWindowResize()
-
-    @editorHeader = new KDView
-      cssClass : "editor-header header-buttons"
-
-    @editorHeader.addSubView @headerButtonContainer = new KDView
-      cssClass : "header-buttons"
-
-    @saveButton = new KDButtonViewWithMenu
-      title         : "Save"
-      style         : "editor-button save-menu"
-      type          : "contextmenu"
-      delegate      : @
-      menu          : @getSaveMenu.bind @
-      callback      : =>
-        @ace.requestSave()
-    @saveButton.disable()

     @caretPosition = new KDCustomHTMLView
       tagName       : "div"
@@ -50,47 +34,8 @@
       menu          : @getAdvancedSettingsMenuItems.bind @
     @advancedSettings.disable()

-    publicUrlCheck = /.*\/(.*\.koding.com)\/website\/(.*)/
-    @previewButton = new KDButtonView
-      style     : "editor-button"
-      icon      : yes
-      iconOnly  : yes
-      iconClass : "preview"
-      callback  : =>
-        publicPath = @getData().path.replace publicUrlCheck, 'http://$1/$2'
-        return if publicPath is @getData().path
-        KD.getSingleton("appManager").open "Viewer", (appInstance)->
-          appInstance.open publicPath
-
-    @previewButton.hide() unless publicUrlCheck.test(@getData().path)
-    @previewButton.disable()
-
-    @compileAndRunButton = new KDButtonView
-      style     : "editor-button"
-      title     : "Compile & Run"
-      loader    :
-        color   : "#444444"
-        diameter: 12
-      callback  : =>
-        manifest = KodingAppsController.getManifestFromPath @getData().path
-        @ace.notify "Compiling...", null, yes
-        @getSingleton('kodingAppsController').compileApp manifest.name, (err)=>
-          if not err
-            @ace.notify "App compiled!", "success"
-          else
-            @ace.notify "Trying to run old version..."
-          @getSingleton('kodingAppsController').runApp manifest
-          @compileAndRunButton.hideLoader()
-
-    @compileAndRunButton.hide() unless /\.kdapp\//.test @getData().path
-    @compileAndRunButton.disable()
-
     @findAndReplaceView = new AceFindAndReplaceView delegate: @
     @findAndReplaceView.hide()
-
-    @headerButtonContainer.addSubView @compileAndRunButton
-    @headerButtonContainer.addSubView @previewButton
-    @headerButtonContainer.addSubView @saveButton

     @setViewListeners()

@@ -122,6 +67,24 @@
       else
         @getData().emit "file.requests.save", contents

+  preview: ->
+    publicUrlCheck = /.*\/(.*\.koding.com)\/website\/(.*)/
+    publicPath = @getData().path.replace publicUrlCheck, 'http://$1/$2'
+    return if publicPath is @getData().path
+    KD.getSingleton("appManager").open "Viewer", (appInstance)->
+      appInstance.open publicPath
+
+  compileAndRun: ->
+    manifest = KodingAppsController.getManifestFromPath @getData().path
+    @ace.notify "Compiling...", null, yes
+    @getSingleton('kodingAppsController').compileApp manifest.name, (err)=>
+      if not err
+        @ace.notify "App compiled!", "success"
+      else
+        @ace.notify "Trying to run old version..."
+      @getSingleton('kodingAppsController').runApp manifest
+      @compileAndRunButton.hideLoader()
+
   viewAppended:->

     super
@@ -130,7 +93,6 @@
   pistachio:->

     """
-    {{> @editorHeader}}

       {{> @ace}}


Let jQuery start the application.

Let jQuery start the application.

--- app/index.coffee
+++ app/index.coffee
@@ -1,8 +1,7 @@
-($ ".arena").hide()
-($ ".arena").append $ "<form>"
-($ "body").append ($ "
").text "Revision " + REVISION
-
-make_menu_bar()
-open_clients()
-
-#alert (generate_xml_from_schema "app")[0].innerHTML
+$ ->
+  ($ ".arena").hide()
+  ($ ".arena").append $ "<form>"
+  ($ "body").append ($ "
").text "Revision " + REVISION
+  make_menu_bar()
+  open_clients()
+  #alert (generate_xml_from_schema "app")[0].innerHTML


fix api url when using location hash

fix api url when using location hash

--- app/index.coffee
+++ app/index.coffee
@@ -30,7 +30,7 @@
       when "#howe" then do howeMode

 apiUrl = (call) ->
-  "#{window.location.href}api/#{call}"
+  "#{window.location.origin}/api/#{call}"

 getJson = (apiCall, message) ->
   new Promise (resolve) ->
@@ -102,7 +102,8 @@
   console.info "Starting Lines Mode."
   getJson "get-lines.json", "Requesting Lines..."
     # .then vis.addLines
-    .then (d) -> vis.getVisType("LinesVis").start(d)
+    .then (d) ->
+      vis.getVisType("LinesVis").start(d)

 chainMode = ->
   console.info "Starting Chain Mode."


Added quotes

Added quotes

--- lib/written/app/assets/javascripts/written/parsers/block/quote.coffee
+++ lib/written/app/assets/javascripts/written/parsers/block/quote.coffee
@@ -42,6 +42,24 @@

     node

+  html: =>
+    node = "

".toHTML()
+    for line, index in @content
+      p = "
".toHTML()
+
+      for text in line
+        if text.html?
+          p.appendChild(text.html())
+        else
+          p.appendChild(document.createTextNode(text.toString()))
+
+      if index < @content.length - 1
+        p.insertAdjacentHTML('beforeend', '\n')
+      node.appendChild(p)
+
+    node
+
+
 Quote.rule = /^(>\s)(.*)/i

 Written.Parsers.Block.register Quote


Round prices to 2 decimal points

Round prices to 2 decimal points

--- example.coffee
+++ example.coffee
@@ -267,8 +267,8 @@
     quote = quotes[ticker]
     output += "
"
     output += "#{ticker}	"
-    output += "#{quote.last}	"
-    output += "#{quote.change} (#{r2(quote.change_pct)}%)	"
+    output += "#{r2(quote.last)}	"
+    output += "#{r2(quote.change)} (#{r2(quote.change_pct)}%)	"
     output += "#{quote.last_time}	"
     output += "#{quote.name}	"
     output += "
"


Added percentage change to title

Added percentage change to title

--- example.coffee
+++ example.coffee
@@ -161,7 +161,10 @@
   $.getJSON yql, (data) ->
     items = []
     data = $.parseJSON(data.query.results.body.p).QuickQuoteResult.QuickQuote
-    newTitle = "#{data.symbol}: #{r2(data.last)} #{r2(data.change)}"
+    change = r2(data.change)
+    last = r2(data.last)
+    percentChange = Math.round(1e4 * +change / (+last - +change)) / 100
+    newTitle = "#{data.symbol}: #{last} #{change} (#{percentChange}%)"

 # Example code for ticker box
 #$("#ticker_box").html "Ticker box goes here"


Added an Informative Error for Error 34

Added an Informative Error for Error 34

There was an exit status 34 being thrown on load from KDC, this
has been resolved.

--- app/views.coffee
+++ app/views.coffee
@@ -63,9 +63,26 @@
       title     : 'Load App'
       callback  : =>
         @options.targetApp.appName = appSelectBox.getValue()
-        @loadApp (err) ->
+        @loadApp (err) =>
           if err?
-            notify "Error during Load: #{err.message}"
+            # Remove the manifest so that other buttons know it didn't load
+            # fully or properly.
+            @options.targetApp.manifest = null
+            if err.message is 'exit status 34'
+              err.message = 'Source files are missing from selected app'
+            new KDModalView
+              title     : "Error during Load: #{err.name}"
+              width     : 700 # Pixels
+              content   :
+                """
+

+

+                  There has been an error compiling #{appName}.
+

+
#{err.message}

+
#{err.stack}

+

+                """

     @appAutoCompile = new KDMultipleChoice
       labels        : ['Auto', 'Manual']
@@ -85,7 +102,28 @@
     appCompileBtn = new KDButtonView
       title     : 'Compile and Preview'
       callback  : =>
-        @compileApp => @previewCss => @previewApp -> notify 'Success!'
+        if not @options.targetApp.manifest?
+          notify 'No App Loaded, Please Load App First'
+          return
+        bailErr = (err) ->
+          new KDModalView
+            title     : "Error during Load: #{err.name}"
+            width     : 700 # Pixels
+            content   :
+              """
+

+

+                There has been an error compiling #{appName}.
+

+
#{err.message}

+
#{err.stack}

+

+              """
+
+        @compileApp (err) =>
+          if err? then bailErr(err) else @previewCss (err) =>
+            if err? then bailErr(err) else @previewApp ->
+              notify 'Success!'

     appBtns = new KDView
       cssClass  : 'appaid-btns'
@@ -271,7 +309,7 @@
             """

-              There has been an error compiling #{appName}.
+              There has been a runtime error of #{appName}.

#{e.message}

#{e.stack}


Fix for undefined VDIs (base copy)

Fix for undefined VDIs (base copy)

--- app/modules/vm/index.coffee
+++ app/modules/vm/index.coffee
@@ -161,6 +161,8 @@
     )

     descriptor = (obj) ->
+      if !obj
+        return ''
       return obj.name_label + (if obj.name_description.length then ' - ' + obj.name_description else '')

     prepareDiskData = () ->
@@ -183,12 +185,12 @@
         if 'iso' isnt SR.SR_type
           for rVdi in SR.VDIs
             oVdi = get rVdi
-
-            VDIOpts.push({
-              sr: descriptor(SR),
-              label: descriptor(oVdi),
-              vdi: oVdi
-              })
+            if oVdi
+              VDIOpts.push({
+                sr: descriptor(SR),
+                label: descriptor(oVdi),
+                vdi: oVdi
+                })
       $scope.VDIOpts = VDIOpts

     parseBootParams = (params) ->


temporarily turn all experimental tasks on

--- app/pages/lab/workflow.cjsx
+++ app/pages/lab/workflow.cjsx
@@ -55,7 +55,8 @@
     @history.createHref("/projects/#{owner}/#{name}/classify", viewQuery)

   canUseTask: (project, task)->
-    task in project.experimental_tools
+    # task in project.experimental_tools
+    true

   render: ->
     window.editingWorkflow = @props.workflow


Add update and patch methods to ApiResource service

--- app/scripts/services.coffee
+++ app/scripts/services.coffee
@@ -2,17 +2,30 @@

 angular.module('taarifaWaterpointsApp')

-  .factory 'ApiResource', ($resource) ->
+  .factory 'ApiResource', ($resource, $http) ->
     (resource, args) ->
-      $resource "/api/#{resource}/:id"
+      Resource = $resource "/api/#{resource}/:id"
       , # Default arguments
         args
       , # Override methods
         query:
           method: 'GET'
           isArray: false
-        update:
-          method: 'PUT'
+      Resource.update = (id, data) ->
+        etag = data._etag
+        # We need to remove these special attributes since they are not defined
+        # in the schema and the data will not validate and the update be rejected
+        for attr in ['_created', '_etag', '_id', '_links', '_updated']
+          data[attr] = undefined if data[attr]
+        $http.put("/api/#{resource}/"+id, data,
+                  headers: {'If-Match': etag})
+      Resource.patch = (id, data, etag) ->
+        $http
+          method: 'PATCH'
+          url: "/api/#{resource}/"+id
+          data: data
+          headers: {'If-Match': etag}
+      return Resource

   .factory 'Waterpoint', (ApiResource) ->
     ApiResource 'waterpoints'


DateTime: Fixed a few problems related to the timezone, some introduced with a wrong fix for another problem, now it is fixed correctly and only parse the timezone when it is necessary. See #59640, #61065, #62381.

--- src/elements/DateTime/DateTime.coffee
+++ src/elements/DateTime/DateTime.coffee
@@ -267,7 +267,7 @@
 		@replace(@__calendarButton, "right")

-	format: (_s, _output_format="display", output_type=null) ->
+	format: (_s, _output_format="display", output_type=null, parseZone = false) ->
 		CUI.util.assert(_output_format in CUI.DateTime.formatTypes, "CUI.DateTime.format", "output_format must be on of \"#{CUI.DateTime.formatTypes.join(',')}\".", parm1: _s, output_format: output_format)

 		if moment.isMoment(_s)
@@ -302,7 +302,7 @@

 		switch _output_format
 			when "store"
-				return CUI.DateTime.formatMoment(mom, output_format[_output_format])
+				return CUI.DateTime.formatMoment(mom, output_format[_output_format], parseZone)
 			else
 				return CUI.DateTime.formatMomentWithBc(mom, output_format[_output_format])

@@ -359,10 +359,15 @@
 	initValue: ->
 		super()
 		value = @getValue()
-		corrected_value = @parseValue(value, "store")
-		if corrected_value and corrected_value != value
-			console.warn("CUI.DateTime.initValue: Corrected value in data:", corrected_value, "Original value:", value)
-			@__data[@_name] = corrected_value
+		parsedValue = @parseValue(value, "store")
+		if parsedValue
+			# When the parsedValue and the value are different in a display format, it means that there is something wrong.
+			# We do not compare only the store value because they can be different but represent the same value if they have different timezones.
+			_value = @format(value)
+			_parsedValue = @format(parsedValue)
+			if _parsedValue != _value
+				console.warn("CUI.DateTime.initValue: Corrected value in data:", parsedValue, "Original value:", value)
+				@__data[@_name] = parsedValue
 		@

 	getValueForDisplay: ->
@@ -623,9 +628,6 @@
 				if mom.year() > @_max_year # Year must not be greater than max year.
 					return moment.invalid()

-				# console.debug "parsing ok", mom, f, moment.locale()
-				if mom.year() > 0
-					mom.parseZone()
 				return mom

 		if not formats.some((format) -> format.support_bc)
@@ -1402,9 +1404,9 @@
 	# format the date_str
 	# output_format "display_short", "display", "store", "input"
 	# output_type "date_time", "date", "date_time_secons", "year_month",v "year"
-	@format: (datestr_or_moment, output_format, output_type) ->
+	@format: (datestr_or_moment, output_format, output_type, parseZone = false) ->
 		dt = new CUI.DateTime()
-		str = dt.format(datestr_or_moment, output_format, output_type)
+		str = dt.format(datestr_or_moment, output_format, output_type, parseZone)
 		# console.debug "DateTime.format", date, type, output_type, DateTime.__locale, str
 		str

@@ -1433,12 +1435,12 @@

 		@formatMomentWithBc(mom, dt.getCurrentFormatDisplay())

-	@formatMoment: (mom, format) ->
+	@formatMoment: (mom, format, parseZone) ->
 		if mom.bc
 			return "-"+mom.bc

-		if mom.year() > 0
-			mom.parseZone() # Only parse zone when it is not BC.
+		if parseZone and mom.year() > 0
+			mom.parseZone() # Only parseZone if necessary, in case it is wanted to keep the timezone.

 		return mom.format(format)


minor visual refactorings

minor visual refactorings

--- library/membrane/visual.coffee
+++ library/membrane/visual.coffee
@@ -172,9 +172,9 @@
         prepared = JSON.stringify _.omit(context, excess)
         installer = "#{symbol} = #{prepared}".toString()
         runtime = "(#{coffee}).apply(this)".toString()
-        em = -> _.extend @, EventEmitter2.prototype
-        applicator = "(#{em}).apply(#{symbol})"
-        _.forIn this, (value, key, object) =>
+        emp = -> _.extend @, EventEmitter2.prototype
+        applicator = try "(#{emp}).apply(#{symbol})"
+        assert _.forIn this, (value, key, object) =>
             return unless _.isObject value?.remote
             return unless src = value.remote.source
             return if (value is @constructor) is yes


A better doc and explanation for location

--- library/nucleus/service.coffee
+++ library/nucleus/service.coffee
@@ -61,9 +61,10 @@
     constructor: (@kernel) ->

     # Either obtain or set the HTTP location of the current service.
-    # If not location has been set, but the one is requested then
-    # the deduced default is returned. Default location is the first
-    # resource regular expression pattern being unescaped to string.
+    # This method is a proxy that forwards the invocation to the
+    # service constructor, for the purpose of easy access to service
+    # location when programmatically operating on the instances. Do
+    # refer to the original constructor method for more information.
     location: -> @constructor.location arguments...

     # Either obtain or set the HTTP location of the current service.


Tidy up.

Tidy up.

--- c3/app/assets/javascripts/s4_careYouProvide/g7_moreAboutTheCare.coffee
+++ c3/app/assets/javascripts/s4_careYouProvide/g7_moreAboutTheCare.coffee
@@ -1,9 +1,9 @@
-window.initEvents = (spent35HoursCaringBeforeClaimY,spent35HoursCaringBeforeClaimN,day,month,year)->
-  $("#"+spent35HoursCaringBeforeClaimY).on "click", ->
+window.initEvents = (spent35HoursCaringBeforeClaimY, spent35HoursCaringBeforeClaimN, day, month, year) ->
+  $("#" + spent35HoursCaringBeforeClaimY).on "click", ->
     $("#careStartDateWrap").slideDown 500

-  $("#"+spent35HoursCaringBeforeClaimN).on "click", ->
+  $("#" + spent35HoursCaringBeforeClaimN).on "click", ->
     $("#careStartDateWrap").slideUp 500, ->
-      $("#"+day).val("")
-      $("#"+month).val("")
-      $("#"+year).val("")+      $("#" + day).val("")
+      $("#" + month).val("")
+      $("#" + year).val("")


fix(long-polling): API changes require ignoring \ns!

--- src/flux/inbox-long-connection.coffee
+++ src/flux/inbox-long-connection.coffee
@@ -28,10 +28,10 @@
     , 1000

     @
-
+
   namespaceId: ->
     @_namespaceId
-
+
   hasCursor: ->
     !!atom.config.get(@_cursorKey)

@@ -120,6 +120,8 @@
         processBufferThrottled = _.throttle(@onProcessBuffer, 400, {leading: false})
         res.on 'close', => @retry()
         res.on 'data', (chunk) =>
+          # Ignore characters sent as pings
+          return if chunk is '\n'
           @_buffer += chunk
           processBufferThrottled()


Admin: Integrations: Delete repository option if not exist.

--- client/admin/lib/views/integrations/adminintegrationdetailsview.coffee
+++ client/admin/lib/views/integrations/adminintegrationdetailsview.coffee
@@ -24,8 +24,6 @@
     { instructions } = integration
     data.repositories or= []

-    repositories = ({ title: repository.full_name, value: repository.full_name } for repository in data.repositories)
-
     @eventCheckboxes = {}

     if instructions
@@ -42,9 +40,9 @@
     else
       @instructionsView = new KDCustomHTMLView cssClass: 'hidden'

-    channels = ({ title: channel.name, value: channel.id } for channel in data.channels)
-
-    { customName } = data.settings  if data.settings
+    repositories = ({ title: repository.full_name, value: repository.full_name } for repository in data.repositories)
+    channels     = ({ title: channel.name, value: channel.id } for channel in data.channels)
+
     formOptions         =
       cssClass          : 'AppModal-form details-form'
       callback          : @bound 'handleFormCallback'
@@ -72,17 +70,14 @@
           type          : 'select'
           selectOptions : repositories
           cssClass      : unless repositories.length then 'hidden'
+          defaultValue  : data.selectedRepository # DUMMY_DATA @canthefason
         events          :
           label         : '
Customize Events
Choose the events you would like to receive events for.'
           type          : 'hidden'
           cssClass      : unless data.settings?.events?.length then 'hidden'
         name            :
           label         : '
Customize Name
Choose the username that this integration will post as.'
-          defaultValue  : customName or integration.title
-        events          :
-          label         : '
Customize Events
Choose the events you would like to receive events for.'
-          type          : 'hidden'
-          cssClass      : unless data.settings?.events?.length then 'hidden'
+          defaultValue  : data.settings?.customName or integration.title
       buttons           :
         Save            :
           title         : 'Save Integration'
@@ -94,6 +89,8 @@
           cssClass      : 'solid green medium red'
           callback      : => @emit 'IntegrationCancelled'

+    delete formOptions.fields.repository  unless repositories.length
+
     { integrationType, isDisabled } = @getData()

     if integrationType is 'configured'
@@ -296,7 +293,7 @@

#{title}

-         #{summary}
+        #{summary}

         #{description}


Added index for federal state (#60)

Added index for federal state (#60)

--- packages/custom/transparency/coffee/server/models/organisation.coffee
+++ packages/custom/transparency/coffee/server/models/organisation.coffee
@@ -37,7 +37,7 @@
 OrganisationSchema.index(
   {
       name: 1
-      federalState_en: 1
+      federalState: 1
   },{
       unique: true
   }


don't display missing libraries/collections

--- chrome/content/zotero-better-bibtex/preferences.coffee
+++ chrome/content/zotero-better-bibtex/preferences.coffee
@@ -162,14 +162,17 @@
       else 'collection'

   exportName: (id, full) ->
-    name = switch
-      when id == '' then ''
-      when id == 'library' then Zotero.Libraries.getName()
-      when m = /^library:([0-9]+)$/.exec(id) then Zotero.Libraries.getName(m[1])
-      when m = /^search:([0-9]+)$/.exec(id) then Zotero.Searches.get(m[1])?.name
-      when full then @collectionPath(id)
-      else Zotero.Collections.get(id)?.name
-    return name || id
+    try
+      name = switch
+        when id == '' then ''
+        when id == 'library' then Zotero.Libraries.getName()
+        when m = /^library:([0-9]+)$/.exec(id) then Zotero.Libraries.getName(m[1])
+        when m = /^search:([0-9]+)$/.exec(id) then Zotero.Searches.get(m[1])?.name
+        when full then @collectionPath(id)
+        else Zotero.Collections.get(id)?.name
+      return name || id
+    catch err
+      return "not found: #{id}"

   collectionPath: (id) ->
     return '' unless id


Revert unintentional change in 41e3bbd

Revert unintentional change in 41e3bbd

--- actionview/app/assets/javascripts/rails-ujs/utils/event.coffee
+++ actionview/app/assets/javascripts/rails-ujs/utils/event.coffee
@@ -7,7 +7,7 @@
 CustomEvent = window.CustomEvent

 if typeof CustomEvent isnt 'function'
-  window.CustomEvent = (event, params) ->
+  CustomEvent = (event, params) ->
     evt = document.createEvent('CustomEvent')
     evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail)
     evt


Refactor default machine list instantiation procedure

--- client/app/lib/activity/sidebar/activitysidebar.coffee
+++ client/app/lib/activity/sidebar/activitysidebar.coffee
@@ -594,8 +594,12 @@
         cssClass: 'machines-wrapper'

     if isKoding()
-      @createMachineList 'own'
-      @createMachineList 'shared'
+      @createDefaultMachineList expandedBoxUIds
+
+
+  createDefaultMachineList: (expandedBoxUIds) ->
+    @createMachineList 'own'
+    @createMachineList 'shared'

     if environmentDataProvider.hasData()
       @addMachines_ environmentDataProvider.get(), expandedBoxUIds


Fix broken test

Fix broken test

Summary:
Fixes a test that was broken due to my unfamiliarity with
CoffeeScript :-/

Test Plan: Tests

Reviewers: bengotow

Reviewed By: bengotow

Subscribers: juan

Differential Revision: https://phab.nylas.com/D3302

--- internal_packages/worker-sync/spec/nylas-sync-worker-spec.coffee
+++ internal_packages/worker-sync/spec/nylas-sync-worker-spec.coffee
@@ -106,26 +106,26 @@
       spyOn(Math, 'random').andReturn(1.0)
       @worker.start()

-      expectThings = (resumeCallCount) ->
+      expectThings = (resumeCallCount, randomCallCount) =>
         expect(@worker.resume.callCount).toBe(resumeCallCount)
-        expect(Math.random.callCount).toBe(resumeCallCount)
-
-      expect(@worker.resume.callCount).toBe(1)
-      simulateNetworkFailure(); expectThings(1)
-      advanceClock(4000);       expectThings(2)
-      simulateNetworkFailure(); expectThings(2)
-      advanceClock(4000);       expectThings(2)
-      advanceClock(4000);       expectThings(3)
-      simulateNetworkFailure(); expectThings(3)
-      advanceClock(4000);       expectThings(3)
-      advanceClock(4000);       expectThings(3)
-      advanceClock(4000);       expectThings(4)
-      simulateNetworkFailure(); expectThings(4)
-      advanceClock(4000);       expectThings(4)
-      advanceClock(4000);       expectThings(4)
-      advanceClock(4000);       expectThings(4)
-      advanceClock(4000);       expectThings(4)
-      advanceClock(4000);       expectThings(5)
+        expect(Math.random.callCount).toBe(randomCallCount)
+
+      expect(@worker.resume.callCount).toBe(1, 1)
+      simulateNetworkFailure(); expectThings(1, 1)
+      advanceClock(4000);       expectThings(2, 1)
+      simulateNetworkFailure(); expectThings(2, 2)
+      advanceClock(4000);       expectThings(2, 2)
+      advanceClock(4000);       expectThings(3, 2)
+      simulateNetworkFailure(); expectThings(3, 3)
+      advanceClock(4000);       expectThings(3, 3)
+      advanceClock(4000);       expectThings(3, 3)
+      advanceClock(4000);       expectThings(4, 3)
+      simulateNetworkFailure(); expectThings(4, 4)
+      advanceClock(4000);       expectThings(4, 4)
+      advanceClock(4000);       expectThings(4, 4)
+      advanceClock(4000);       expectThings(4, 4)
+      advanceClock(4000);       expectThings(4, 4)
+      advanceClock(4000);       expectThings(5, 4)

     it "handles the request as a failure if we try and grab labels or folders without an 'inbox'", ->
       spyOn(@worker, 'resume').andCallThrough()


(minor) indenting.

(minor) indenting.

--- core/app/backbone/views/channels/filtered_suggested_topics_view.coffee
+++ core/app/backbone/views/channels/filtered_suggested_topics_view.coffee
@@ -45,10 +45,9 @@
   initialize: (options) ->
     utils = new CollectionUtils(this)
     @filtered_collection = utils.difference(new Backbone.Collection(),
-                                                  'slug_title',
-                                                  @collection,
-                                                  @options.addToCollection)
-
+      'slug_title',
+      @collection,
+      @options.addToCollection)
     @listenTo @filtered_collection, 'add remove reset change', @updateVisibilities

   onRender: ->


Fixed alerts update refresh bug

Fixed alerts update refresh bug

--- muleview/coffee/app/view/AlertsEditor.coffee
+++ muleview/coffee/app/view/AlertsEditor.coffee
@@ -108,7 +108,7 @@
       url: Muleview.Mule.getAlertCommandUrl(Muleview.currentKey, Muleview.currentRetention)
       method: method
       success: ->
-        Muleview.Graphs.createGraphs()
+        Muleview.event "refreshRequest"
       )

   doDelete: ->


Adding state to home page filtering

Adding state to home page filtering

--- app/assets/javascripts/darkswarm/filters/filter_hubs.js.coffee
+++ app/assets/javascripts/darkswarm/filters/filter_hubs.js.coffee
@@ -6,4 +6,4 @@
       matched.toLowerCase().indexOf(text.toLowerCase()) != -1

     hubs.filter (hub)->
-      match(hub.name) or match(hub.address.zipcode) or match(hub.address.city)
+      match(hub.name) or match(hub.address.zipcode) or match(hub.address.city) or match(hub.address.state)


changed ShareLaTeX thoughts to go into type form

--- services/web/app/coffee/Features/Email/EmailBuilder.coffee
+++ services/web/app/coffee/Features/Email/EmailBuilder.coffee
@@ -27,7 +27,7 @@
 	compiledTemplate: _.template '''

Hi <%= first_name %>,

-
I'm sorry to see you cancelled your ShareLaTeX premium account. Would you mind giving me some advice on what the site is lacking at the moment? Feedback from our users is the only way we can improve ShareLaTeX.

+
I'm sorry to see you cancelled your ShareLaTeX premium account. Would you mind giving me some advice on what the site is lacking at the moment via this survey?

Thank you in advance.


fix splash hide

fix splash hide

--- app/assets/javascripts/app/lib/app_post/interface_handle.coffee
+++ app/assets/javascripts/app/lib/app_post/interface_handle.coffee
@@ -10,7 +10,7 @@
       return

     # hide splash screen
-    $('#splash').hide()
+    $('.splash').hide()

     # init collections
     App.Collection.init()


+ dispaly the filename when load data error

--- src/load-data.coffee
+++ src/load-data.coffee
@@ -5,6 +5,7 @@
 isString    = require 'util-ex/lib/is/type/string'
 debug       = require('debug')('loopback:component:autoMigrate:loadData')
 loopback    = require 'loopback'
+path        = require 'path'

 # import data to database from /server/data/ folder
 # need promise to done.
@@ -13,9 +14,10 @@
     Promise.reject err
     .asCallback done

-  return reject(new TypeError 'The data should be an array.') unless isArray data
+  vFile = path.basename(data.$cfgPath)
+  return reject(new TypeError '%s: The data should be an array.', vFile) unless isArray data
   Model = loopback.getModel(Model) if isString Model
-  return reject(new TypeError 'Missing Model') unless Model
+  return reject(new TypeError '%s: Missing Model', vFile) unless Model

   Promise.map data, (item)->
     Model.create item
@@ -38,4 +40,7 @@
   .then (results)->
     debug Model.modelName + ': total ' + results.length + ' data created.'
     return results
+  .catch (err)->
+    err.name = vFile + ':' + err.name
+    throw err
   .asCallback done


OnboardingView: do not send template on skip

--- client/stacks/lib/views/stacks/onboarding/onboardingview.coffee
+++ client/stacks/lib/views/stacks/onboarding/onboardingview.coffee
@@ -132,7 +132,7 @@
         @destroy()
         selectedProvider = @providerSelectionView.selected?.getOption 'provider'
         if selectedProvider?
-          options = { selectedProvider, template: { content: @stackTemplate } }
+          options = { selectedProvider }
         Tracker.track Tracker.STACKS_SKIP_SETUP
         @emit 'StackOnboardingCompleted', options


Apparently lodash has rounding

Apparently lodash has rounding

--- resources/assets/coffee/react/beatmapset-page/scoreboard-first.coffee
+++ resources/assets/coffee/react/beatmapset-page/scoreboard-first.coffee
@@ -41,7 +41,7 @@
             when 'score'
               dd = @props.score.score.toLocaleString()
             when 'accuracy'
-              dd = "#{(@props.score.accuracy.toFixed 4) * 100}%"
+              dd = "#{_.round @props.score.accuracy * 100, 2}%"
             when '300'
               dd = @props.score.count300
             when '100'


stop deleting entry url when other info is edited

--- controllers/teams.coffee
+++ controllers/teams.coffee
@@ -207,7 +207,12 @@
   unless req.user?.admin
     delete req.body[attr] for attr in ['slug', 'code', 'search', 'scores']
     delete req.body.entry.url if req.body.entry
+
+  entry = req.body.entry
+  delete req.body.entry
   _.extend req.team, req.body
+  _.extend req.team.entry, entry
+
   req.team.save (err) ->
     return next err if err and err.name != 'ValidationError'
     if req.team.errors


Small fix

Small fix

--- framer/AnimationLoop.coffee
+++ framer/AnimationLoop.coffee
@@ -35,6 +35,9 @@
 		if Utils.webkitVersion() > 600 and Utils.isFramerStudio()
 			@raf = false

+		# To avoid event emitter warning
+		@maximumListeners = Infinity
+
 	start: =>

 		animationLoop = @


Lower inputThrottle on Select Lists to 50ms

--- src/app/select-list.coffee
+++ src/app/select-list.coffee
@@ -16,7 +16,7 @@

   maxItems: Infinity
   scheduleTimeout: null
-  inputThrottle: 200
+  inputThrottle: 50
   filteredArray: null
   cancelling: false


+ working sorting (although very adhoc)

+ working sorting (although very adhoc)

--- app/assets/javascripts/components/larch-tree_component.js.coffee
+++ app/assets/javascripts/components/larch-tree_component.js.coffee
@@ -8,6 +8,16 @@
   nodesSorting: ['position']
   sortedNodes: Ember.computed.sort('nodes','nodesSorting')

+  init: ->
+    @_super()
+    @ensureProperty('nodes')
+    @ensureProperty('store')
+    @ensureProperty('removeNode')
+    @ensureProperty('serverPath')
+
+  ensureProperty: (name) ->
+    throw "Missing property '#{name}' for Larch.TreeComponent" if Ember.isEmpty(@get(name))
+
   roots: (->
      @get('sortedNodes').filterBy('ancestryDepth',0)
   ).property('sortedNodes.@each.depth')
@@ -27,13 +37,38 @@

     changeParent: (item_id,parent_id,position = null) ->
       data = { menu_item: { parent_id: parent_id }}
-      @postToServer("/admin/menu_items/#{item_id}",data,type: 'PUT').then =>
+      path = @get('serverPath')
+      @postToServer("#{path}/#{item_id}",data,type: 'PUT').then =>
         console.log "Item #{item_id} changed parent."
       false

   _move: (item,params = {}) ->
     id = item.get('id')
-    @postToServer("/admin/menu_items/#{id}/move", params).then =>
+    path = @get('serverPath')
+    @postToServer("#{path}/#{id}/move", params).then =>
       console.log "Item #{id} moved."
     false
+
+
+  # moved here from Barbecue so that there is no dependency
+  postToServer: (url,data = {},options = {}) ->
+    new Promise (resolve, reject) =>
+      csrf_token = $('meta[name="csrf-token"]').attr('content')
+      csrf_param = $('meta[name="csrf-param"]').attr('content')
+      data.authenticity_token = csrf_token
+
+      try
+        $.ajax
+          url: url
+          type: options.type || 'POST'
+          data: data
+          success: (response) =>
+            console.info 'Payload', response
+            @store.pushPayload(options.serializer || 'page',response)
+            resolve(response)
+
+          error: (response) =>
+            reject(response)
+      catch e
+        reject(e)


Only allow logged in teacher users to favorite material.

[#146098683]

--- app/assets/javascripts/components/search/material_icon.js.coffee
+++ app/assets/javascripts/components/search/material_icon.js.coffee
@@ -77,6 +77,10 @@
     apiUrl 	= null
     params	= {}

+    if !Portal.currentUser.isTeacher
+        alert("You must be logged in as a teacher to favorite material.");
+        return
+
     if material.is_favorite
         apiUrl = Portal.API_V1.MATERIALS_REMOVE_FAVORITE
         params = {  favorite_id:    material.favorite_id    }