Fixed binding

Fixed binding

such that unbinding works as well

--- core/app/backbone/views/facts/react_fact_vote_area.coffee
+++ core/app/backbone/views/facts/react_fact_vote_area.coffee
@@ -10,7 +10,7 @@
 ReactOpinionatorsAvatars = React.createBackboneClass
   componentDidMount: ->
     # react.backbone.js doesn't listen to changing models
-    @model().on 'change', => @forceUpdate()
+    @model().on 'change', (-> @forceUpdate()), this

   render: ->
     _div ["fact-vote-people-#{@props.type}"],
@@ -23,7 +23,7 @@
 FactVoteButton = React.createBackboneClass
   componentDidMount: ->
     # react.backbone.js doesn't listen to changing models
-    @model().on 'change', => @forceUpdate()
+    @model().on 'change', (-> @forceUpdate()), this

   _onClick: ->
     @model().clickCurrentUserOpinion @props.type


Improve outgoing webhook logs

Improve outgoing webhook logs

--- packages/rocketchat-integrations/server/triggers.coffee
+++ packages/rocketchat-integrations/server/triggers.coffee
@@ -28,7 +28,7 @@
 					error: e

 	try
-		logger.outgoing.info 'will evaluate script'
+		logger.outgoing.info 'Will evaluate script of Trigger', integration.name
 		logger.outgoing.debug script

 		vmScript = vm.createScript script, 'script.js'
@@ -42,14 +42,14 @@

 			return compiledScripts[integration._id].script
 	catch e
-		logger.outgoing.error "[Error evaluating Script:]"
+		logger.outgoing.error '[Error evaluating Script in Trigger', integration.name, ':]'
 		logger.outgoing.error script.replace(/^/gm, '  ')
 		logger.outgoing.error "[Stack:]"
 		logger.outgoing.error e.stack.replace(/^/gm, '  ')
 		throw new Meteor.Error 'error-evaluating-script'

 	if not sandbox.Script?
-		logger.outgoing.error "[Class 'Script' not found]"
+		logger.outgoing.error '[Class "Script" not in Trigger', integration.name, ']'
 		throw new Meteor.Error 'class-script-not-found'

@@ -75,17 +75,18 @@
 		return

 	if not script[method]?
-		logger.outgoing.error "[Method '#{method}' not found]"
+		logger.outgoing.error '[Method "', method, '" not found in Trigger', integration.name, ']'
 		return

 	try
 		result = script[method](params)

-		logger.outgoing.debug 'result', result
+		logger.outgoing.debug '[Script method [', method, '] result of Trigger', integration.name, ':]'
+		logger.outgoing.debug result

 		return result
 	catch e
-		logger.incoming.error "[Error running Script:]"
+		logger.incoming.error '[Error running Script in Trigger', integration.name, ':]'
 		logger.incoming.error integration.scriptCompiled.replace(/^/gm, '  ')
 		logger.incoming.error "[Stack:]"
 		logger.incoming.error e.stack.replace(/^/gm, '  ')
@@ -227,16 +228,16 @@

 		if not result? or result.statusCode not in [200, 201, 202]
 			if error?
-				logger.outgoing.error error
+				logger.outgoing.error 'Error for trigger', trigger.name, 'to', url, error
 			if result?
-				logger.outgoing.error result
+				logger.outgoing.error 'Error for trigger', trigger.name, 'to', url, result

 			if result.statusCode is 410
 				RocketChat.models.Integrations.remove _id: trigger._id
 				return

 			if result.statusCode is 500
-				logger.outgoing.error 'Request Error [500]', url
+				logger.outgoing.error 'Error [500] for trigger', trigger.name, 'to', url
 				logger.outgoing.error result.content
 				return


--- packages/rocketchat-integrations/server/triggers.coffee
+++ packages/rocketchat-integrations/server/triggers.coffee
@@ -61,8 +61,12 @@
 				, Math.pow(10, tries+2)
 			return

-		# TODO process return and insert message if necessary
+		# process outgoing webhook response as a new message
+		else if result?.statusCode is 200 and (result.data?.text? or result.data?.attachments?)
+			user = RocketChat.models.Users.findOneByUsername(trigger.username)

+			if result.data?.text? or result.data?.attachments?
+				return processWebhookMessage trigger, result.data, user

 ExecuteTrigger = (trigger, message, room) ->


Add bootsrap.js to SearchView dependencies.

--- web/js/views/search_view.coffee
+++ web/js/views/search_view.coffee
@@ -1,4 +1,4 @@
-define ['jquery', 'underscore', 'backbone'], ($, _, Backbone) ->
+define ['jquery', 'underscore', 'backbone', 'bootstrap'], ($, _, Backbone) ->
   class SearchView extends Backbone.View

     el: $('#search')


Add apple to linked accounts tests

Add apple to linked accounts tests

--- src/desktop/apps/user/components/linked_accounts/test/view.test.coffee
+++ src/desktop/apps/user/components/linked_accounts/test/view.test.coffee
@@ -5,11 +5,8 @@
 { fabricate } = require '@artsy/antigravity'
 CurrentUser = require '../../../../../models/current_user'
 LinkedAccountsView = benv.requireWithJadeify require.resolve('../view'), ['template']
-LinkedAccountsView.__set__ 'sd', AP:
-  twitterPath: '/users/auth/twitter'
-  facebookPath: '/users/auth/facebook'

-describe 'LinkedAccountsView', ->
+describe "LinkedAccountsView", ->
   before (done) ->
     benv.setup ->
       benv.expose $: benv.require('jquery'), jQuery: benv.require('jquery')
@@ -30,42 +27,44 @@
     Backbone.sync.restore()

   describe '#toggleService', ->
-    describe 'unlink', ->
-      beforeEach ->
-        sinon.stub @user, 'isLinkedTo'
-          .returns true
-        @view.$('.js-settings-linked-accounts__service__toggle[data-service="facebook"]').click()
+    for provider in ['apple', 'facebook']
+      describe "unlink #{provider}", ->
+        beforeEach ->
+          sinon.stub @user, 'isLinkedTo'
+            .returns true

-      afterEach ->
-        @user.isLinkedTo.restore()
+          @view.$(".js-settings-linked-accounts__service__toggle[data-service='#{provider}']").click()

-      it 'destroys the authentication', ->
-        Backbone.sync.args[0][0].should.equal 'delete'
-        Backbone.sync.args[0][1].url.should.containEql '/api/v1/me/authentications/facebook'
+        afterEach ->
+          @user.isLinkedTo.restore()

-      describe 'success', ->
-        beforeEach ->
-          Backbone.sync.yieldsTo 'success'
-          @view.$('.js-settings-linked-accounts__service__toggle[data-service="facebook"]').click()
+        it 'destroys the authentication', ->
+          Backbone.sync.args[0][0].should.equal 'delete'
+          Backbone.sync.args[0][1].url.should.containEql "/api/v1/me/authentications/#{provider}"

-        it 'sets the correct button state', ->
-          @view.$('.js-settings-linked-accounts__service__toggle[data-service="facebook"]')
-            .data().should.eql service: 'facebook', connected: 'disconnected'
+        describe 'success', ->
+          beforeEach ->
+            Backbone.sync.yieldsTo 'success'
+            @view.$(".js-settings-linked-accounts__service__toggle[data-service=#{provider}]").click()

-      describe 'error', ->
-        beforeEach ->
-          Backbone.sync.yieldsTo 'error', responseJSON: error: 'Something bad.'
-          @view.$('.js-settings-linked-accounts__service__toggle[data-service="facebook"]').click()
+          it 'sets the correct button state', ->
+            @view.$(".js-settings-linked-accounts__service__toggle[data-service=#{provider}]")
+              .data().should.eql service: 'facebook', connected: 'disconnected'

-        it 'renders any errors', ->
-          @view.$('.js-form-errors').text().should.equal 'Something bad.'
+        describe 'error', ->
+          beforeEach ->
+            Backbone.sync.yieldsTo 'error', responseJSON: error: 'Something bad.'
+            @view.$(".js-settings-linked-accounts__service__toggle[data-service=#{provider}]").click()

-      describe 'callback error', ->
-        beforeEach ->
-          sd = LinkedAccountsView.__get__ 'sd'
-          LinkedAccountsView.__set__ 'sd', extend {}, sd,
-            ERROR: 'Some arbitrary error message (probably).'
+          it 'renders any errors', ->
+            @view.$('.js-form-errors').text().should.equal 'Something bad.'

-        it 'renders the ERROR', ->
-          @view.render().$('.js-form-errors').text()
-            .should.equal 'Some arbitrary error message (probably).'
+        describe 'callback error', ->
+          beforeEach ->
+            sd = LinkedAccountsView.__get__ 'sd'
+            LinkedAccountsView.__set__ 'sd', extend {}, sd,
+              ERROR: 'Some arbitrary error message (probably).'
+
+          it 'renders the ERROR', ->
+            @view.render().$('.js-form-errors').text()
+              .should.equal 'Some arbitrary error message (probably).'


Don't upload by default

Don't upload by default

--- nodejs/MicroFloComponent.coffee
+++ nodejs/MicroFloComponent.coffee
@@ -18,7 +18,7 @@
     metadata = {} unless metadata
     @devname = metadata.device or null
     @baudrate = metadata.baudrate or 9600
-    @upload = yes
+    @upload = no
     @graph = null
     @transport = null
     @ready = true


Comment symbol to allow toggling comments

--- scoped-properties/language-haskell.cson
+++ scoped-properties/language-haskell.cson
@@ -1,4 +1,5 @@
 '.source.haskell':
   'editor':
+    'commentStart': '-- '
     'increaseIndentPattern': '((^.*(=|\\bdo|\\bwhere|\\bthen|\\belse|\\bof)\\s*$)|(^.*\\bif(?!.*\\bthen\\b.*\\belse\\b.*).*$))'
     'decreaseIndentPattern': '^\\s*$'


US804 - Fix button not displaying after back pressed

--- c3/app/assets/javascripts/s1_carers_allowance/g6_approve.coffee
+++ c3/app/assets/javascripts/s1_carers_allowance/g6_approve.coffee
@@ -1,12 +1,12 @@
 window.initialButtonState = (answerY, answerN) ->
-  if (!$("#" + answerN).prop('checked') && !$("#" + answerN).prop('checked'))
+  if (!$("#" + answerY).prop('checked') && !$("#" + answerN).prop('checked'))
     $("#showAppropriateButtonWrap").css('display', "none")

   if ($("#" + answerN).prop('checked'))
     $("#actionButtonId").text("Finished")
     $("#showAppropriateButtonWrap").css('display', "block")

-  if ($("#" + answerN).prop('checked'))
+  if ($("#" + answerY).prop('checked'))
     $("#actionButtonId").text("Continue")
     $("#showAppropriateButtonWrap").css('display', "block")


improving CoffeeScript in browser script activation, and updating docs

--- coffee-script.coffee
+++ coffee-script.coffee
@@ -41,5 +41,10 @@
 # Activate CoffeeScript in the browser by having it compile and eval
 # all script tags with a content-type of text/coffeescript.
 if document? and document.getElementsByTagName
-  for tag in document.getElementsByTagName('script') when tag.type is 'text/coffeescript'
-    eval exports.compile tag.innerHTML
+  process_scripts: ->
+    for tag in document.getElementsByTagName('script') when tag.type is 'text/coffeescript'
+      eval exports.compile tag.innerHTML
+  if window.addEventListener
+    window.addEventListener 'load', process_scripts, false
+  else if window.attachEvent
+    window.attachEvent 'onload', process_scripts


Fixes #3047 -- Fixes module.paths when running directly with no explicit passed-in files.

--- coffee-script.coffee
+++ coffee-script.coffee
@@ -107,7 +107,11 @@
   mainModule.moduleCache and= {}

   # Assign paths for node_modules loading
-  mainModule.paths = require('module')._nodeModulePaths path.dirname fs.realpathSync options.filename or '.'
+  dir = if options.fileName
+    path.dirname fs.realpathSync options.filename
+  else
+    fs.realpathSync '.'
+  mainModule.paths = require('module')._nodeModulePaths dir

   # Compile.
   if not helpers.isCoffee(mainModule.filename) or require.extensions


Add new API key for UTno

Add new API key for UTno

--- coffee/server.coffee
+++ coffee/server.coffee
@@ -51,6 +51,7 @@
   dnt: 'DNT'
   nrk: 'NRK'
   '30ad3a3a1d2c7c63102e09e6fe4bb253': 'TurApp'
+  '0fe3cf9a548f7e158a4a0f5f22a9e8bd': 'UTno'

 app.get '/', (req, res) ->
   res.json message: 'Here be dragons'


Frontend fixes for subcomments

Frontend fixes for subcomments

--- core/app/backbone/views/sub_comments/sub_comments_view.coffee
+++ core/app/backbone/views/sub_comments/sub_comments_view.coffee
@@ -10,7 +10,7 @@

         (  {{ creator.authority }} )

-
{{text}}

+
{{content}}

     """

   templateHelpers: => creator: @model.creator().toJSON()
@@ -64,7 +64,7 @@

   addModelError: -> @alertError()
   addModelSuccess: (model) ->
-    @textModel.set 'text', ''
+    @textModel().set 'text', ''
     @alertHide()

   text: -> @textModel().get('text')


only comment builds for the fgpv repo

only comment builds for the fgpv repo

--- scripts/gitter-activity-notifier.coffee
+++ scripts/gitter-activity-notifier.coffee
@@ -162,25 +162,27 @@
             branch = store[sha].branch
             description = body.description
             travis_url = body.target_url
+            repo = body.name
             if body.state == "success"
                 icon = travisOk

-                 # Comment demos on PR
-                demourl = 'http://fgpv-app.azureedge.net/demo/users/' + user + '/' + branch
-                commentString = """
-                    Hey, I updated your PR Demo:
-
-                    | Dev Builds                      | Prod Builds                     |
-                    | ------------------------------- | ------------------------------- |
-                    | [index-one.html](#{demourl}/dev/samples/index-one.html)    | [index-one.html](#{demourl}/prod/samples/index-one.html)    |
-                    | [index-mobile.html](#{demourl}/dev/samples/index-mobile.html)    | [index-mobile.html](#{demourl}/prod/samples/index-mobile.html)    |
-                    | [index-samples.html](#{demourl}/dev/samples/index-samples.html)    | [index-samples.html](#{demourl}/prod/samples/index-samples.html)    |
-                    | [index-fgp-en.html](#{demourl}/dev/samples/index-fgp-en.html) | [index-fgp-en.html](#{demourl}/prod/samples/index-fgp-en.html) |
-                    | [index-fgp-fr.html](#{demourl}/dev/samples/index-fgp-fr.html) | [index-fgp-fr.html](#{demourl}/prod/samples/index-fgp-fr.html) |
-
-                    Is it working as expected?
-                    """
-                glitchpy.comment("fgpv-vpgf", "fgpv-vpgf", prNum, commentString)
+                 # Comment demos on PR for FGPV repo only
+                if repo == "fgpv-vpgf/fgpv-vpgf"
+                    demourl = 'http://fgpv-app.azureedge.net/demo/users/' + user + '/' + branch
+                    commentString = """
+                        Hey, I updated your PR Demo:
+
+                        | Dev Builds                      | Prod Builds                     |
+                        | ------------------------------- | ------------------------------- |
+                        | [index-one.html](#{demourl}/dev/samples/index-one.html)    | [index-one.html](#{demourl}/prod/samples/index-one.html)    |
+                        | [index-mobile.html](#{demourl}/dev/samples/index-mobile.html)    | [index-mobile.html](#{demourl}/prod/samples/index-mobile.html)    |
+                        | [index-samples.html](#{demourl}/dev/samples/index-samples.html)    | [index-samples.html](#{demourl}/prod/samples/index-samples.html)    |
+                        | [index-fgp-en.html](#{demourl}/dev/samples/index-fgp-en.html) | [index-fgp-en.html](#{demourl}/prod/samples/index-fgp-en.html) |
+                        | [index-fgp-fr.html](#{demourl}/dev/samples/index-fgp-fr.html) | [index-fgp-fr.html](#{demourl}/prod/samples/index-fgp-fr.html) |
+
+                        Is it working as expected?
+                        """
+                    glitchpy.comment("fgpv-vpgf", "fgpv-vpgf", prNum, commentString)
             else
                 icon = travisBroken
                 store[sha].message += ":rotating_light: EMERGENCY ALERT :rotating_light: `#{user}` has broken the :construction: build :construction: :construction_worker: :broken_heart: and owes muffins now!!! :cake:\n"


Check cache overview before calling reverse on it

--- client/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/app/Applications/Activity.kdapplication/AppController.coffee
@@ -178,7 +178,7 @@
     {CStatusActivity} = KD.remote.api
     eventSuffix = "#{@getFeedFilter()}_#{@getActivityFilter()}"
     CStatusActivity.fetchPublicActivityFeed options, (err, cache)=>
-      cache.overview.reverse()  if cache.overview
+      cache.overview.reverse()  if cache?.overview and not err

       return @emit "activitiesCouldntBeFetched", err  if err


removed logging

removed logging

--- client/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/app/Applications/Activity.kdapplication/AppController.coffee
@@ -213,7 +213,7 @@
       skip        : skip  or= @activityListController.getItemCount()
       sort        :
         createdAt : -1
-    log "fetching teasers"
+
     @fetchTeasers selector, options, (activities)=>
       if activities
         for activity in activities


fix for terminal command

fix for terminal command

--- client/app/Applications/WebTerm.kdapplication/webtermappview.coffee
+++ client/app/Applications/WebTerm.kdapplication/webtermappview.coffee
@@ -25,7 +25,7 @@
         if not pane.isDestroyed and @tabView.getActivePane() is pane
           @tabView.removePane pane

-  showApprovalModal: (command)->
+  showApprovalModal: (remote, command)->
     modal = new KDModalView
       title   : "Warning!"
       content : """
@@ -62,7 +62,7 @@
       {webTermView} = pane.getOptions()
       webTermView.once 'WebTermConnected', (remote)=>
         command = decodeURIComponent query.command
-        @showApprovalModal command
+        @showApprovalModal remote, command

   _windowDidResize:->
     # 10px being the application page's padding


Finder: Disable actions if finder is read only.

--- client/finder/lib/filetree/controllers/nfindertreecontroller.coffee
+++ client/finder/lib/filetree/controllers/nfindertreecontroller.coffee
@@ -49,6 +49,8 @@

   highlightFile:(view)->

+    return  if @isReadOnly
+
     @selectNode @nodes[view.data.path], null, no

     { ace } = view
@@ -76,6 +78,8 @@
   ###

   openItem:(nodeView, callback)->
+
+    return  if @isReadOnly

     options  = @getOptions()
     nodeData = nodeView.getData()
@@ -95,7 +99,9 @@

   openFile:(nodeView)->

+    return  if @isReadOnly
     return unless nodeView
+
     file = nodeView.getData()
     # @appManager.openFile file
     @getDelegate().emit "FileNeedsToBeOpened", file
@@ -103,6 +109,8 @@
   tailFile: (nodeView) ->

     return  unless nodeView
+    return  if @isReadOnly
+
     @getDelegate().emit "FileNeedsToBeTailed", { file: nodeView.getData() }

@@ -569,7 +577,10 @@

     @openItem nodeView

+
   contextMenu:(nodeView, event)->
+
+    return  if @isReadOnly

     if @getOptions().contextMenu
       @createContextMenu nodeView, event
@@ -660,7 +671,8 @@

   keyEventHappened:(event)->

-    super
+    super  unless @isReadOnly
+

   performDownKey:(nodeView, event)->


Remove pointless tests

Remove pointless tests

--- spec/javascripts/lib/mobile/autocomplete_mobile_spec.js.coffee
+++ spec/javascripts/lib/mobile/autocomplete_mobile_spec.js.coffee
@@ -54,46 +54,6 @@
         expect(AutoComplete.prototype.init).not.toHaveBeenCalled()
         expect(@myAutoComplete.el).toBeNull()

-    describe 'keypress actions', ->
-      beforeEach ->
-        @myAutoComplete = new AutoComplete({id: 'my_search'})
-        spyOn @myAutoComplete, '_highlightDown'
-        spyOn @myAutoComplete, '_highlightUp'
-        spyOn @myAutoComplete, '_selectHighlighted'
-        spyOn @myAutoComplete, '_removeResults'
-        @eventSpy = new jasmine.createSpy()
-
-      it 'calls highlight down on a down arrow key', ->
-        @myAutoComplete._handleKeypress {keyCode: 40, preventDefault: @eventSpy} # down arrow keycode
-
-        expect(@eventSpy).toHaveBeenCalled()
-        expect(@myAutoComplete._highlightDown).toHaveBeenCalled()
-
-      it 'calls highlight up on an up arrow key', ->
-        @myAutoComplete._handleKeypress {keyCode: 38, preventDefault: @eventSpy} # down arrow keycode
-
-        expect(@eventSpy).toHaveBeenCalled()
-        expect(@myAutoComplete._highlightUp).toHaveBeenCalled()
-
-      it 'calls to remove list when ESC key pressed', ->
-        @myAutoComplete._handleKeypress {keyCode: 27, preventDefault: @eventSpy} # down arrow keycode
-
-        expect(@eventSpy).not.toHaveBeenCalled()
-        expect(@myAutoComplete._removeResults).toHaveBeenCalled()
-
-      it 'selects the currently selected item when enter key pressed and cancels event', ->
-        @myAutoComplete._handleKeypress {keyCode: 13, preventDefault: @eventSpy} # down arrow keycode
-
-        expect(@eventSpy).toHaveBeenCalled()
-        expect(@myAutoComplete._selectHighlighted).toHaveBeenCalled()
-
-      it 'selects the currently selected item when enter key pressed and keeps event bubbling when in list mode', ->
-        @myAutoComplete.args.listOnly = true
-        @myAutoComplete._handleKeypress {keyCode: 13, preventDefault: @eventSpy} # down arrow keycode
-
-        expect(@eventSpy).not.toHaveBeenCalled()
-        expect(@myAutoComplete._selectHighlighted).toHaveBeenCalled()
-
     describe 'navigating list with keys', ->
       beforeEach ->
         loadFixtures('autocomplete_mobile.html')


Fix spec failure

Fix spec failure

--- spec/javascripts/unit/admin/bulk_product_update_spec.js.coffee
+++ spec/javascripts/unit/admin/bulk_product_update_spec.js.coffee
@@ -681,7 +681,7 @@
         testVariant = {unit_value_with_description: "1234.5"}
         $scope.packVariant(testProduct, testVariant)
         expect(testVariant).toEqual
-          unit_value: 34998.075
+          unit_value: 1234.5
           unit_description: ''
           unit_value_with_description: "1234.5"


Add a wait to prevent races here, will need to look them later

--- client/app/MainApp/filetree/controllers/findercontroller.coffee
+++ client/app/MainApp/filetree/controllers/findercontroller.coffee
@@ -140,12 +140,16 @@

     vmItem = @getVmNode vmName
     if fetchContent and vmItem
-      @treeController.expandFolder vmItem, (err)=>
-        if err?.name is 'VMNotFoundError'
-          return @unmountVm vmName
-        @treeController.selectNode vmItem
-        if @getOptions().useStorage then @reloadOldStructure vmName
-      , yes
+      # Without this, it fails to fetch Finder settings before creating
+      # Fileitems o_0 FIXME ~ GG
+      @utils.wait 1000, =>
+        @treeController.expandFolder vmItem, (err)=>
+          if err?.name is 'VMNotFoundError'
+            return @unmountVm vmName
+          @treeController.selectNode vmItem
+          @utils.defer =>
+            if @getOptions().useStorage then @reloadOldStructure vmName
+        , yes

   unmountVm:(vmName)->
     vmItem = @getVmNode vmName


addes space

addes space

--- server/configuration/accounts_meld.coffee
+++ server/configuration/accounts_meld.coffee
@@ -3,6 +3,7 @@

 	if serviceName not in ['facebook', 'github', 'gitlab', 'google', 'meteor-developer', 'linkedin', 'twitter', 'sandstorm'] and serviceData._OAuthCustom isnt true
 		return
+

 	if serviceName is 'meteor-developer'
 		if _.isArray serviceData?.emails


Update rubric template

Update rubric template

--- common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee
+++ common/lib/xmodule/xmodule/js/src/combinedopenended/edit.coffee
@@ -2,11 +2,16 @@
   # TODO really, these templates should come from or also feed the cheatsheet
   @rubricTemplate : """
                     [rubric]
-                    + Ideas and Content
-                    - Difficult for the reader to discern the main idea.  Too brief or too repetitive to establish or maintain a focus
-                    - Attempts a main idea.  Sometimes loses focus or ineffectively displays focus
+                    + Ideas
+                    - Difficult for the reader to discern the main idea.  Too brief or too repetitive to establish or maintain a focus.
+                    - Attempts a main idea.  Sometimes loses focus or ineffectively displays focus.
                     - Presents a unifying theme or main idea, but may include minor tangents.  Stays somewhat focused on topic and task.
                     - Presents a unifying theme or main idea without going off on tangents.  Stays completely focused on topic and task.
+                    + Content
+                    - Includes little information with few or no details or unrelated details.  Unsuccessful in attempts to explore any facets of the topic.
+                    - Includes little information and few or no details.  Explores only one or two facets of the topic.
+                    - Includes sufficient information and supporting details. (Details may not be fully developed; ideas may be listed.)  Explores some facets of the topic.
+                    - Includes in-depth information and exceptional supporting details that are fully developed.  Explores all facets of the topic.
                     + Organization
                     - Ideas organized illogically, transitions weak, and response difficult to follow.
                     - Attempts to logically organize ideas.  Attempts to progress in an order that enhances meaning, and demonstrates use of transitions.
@@ -22,7 +27,7 @@
                     [rubric]
                     """

-  @tasksTemplate: "[tasks]\n(Self), ({3-9}AI), ({7-9}Peer)\n[tasks]\n"
+  @tasksTemplate: "[tasks]\n(Self), ({4-12}AI), ({9-12}Peer)\n[tasks]\n"
   @promptTemplate: """
                   [prompt]\n

Censorship in the Libraries


Add hack to force re-render on sidebar as found on: http://stackoverflow.com/questions/3485365/how-can-i-force-webkit-to-redraw-repaint-to-propagate-style-changes

--- servers/www/assets/js/pages/editor.coffee
+++ servers/www/assets/js/pages/editor.coffee
@@ -26,7 +26,17 @@
     if path is "/" then scratch.reset()
     else
       source = path.slice(1)
-      scratch.loadFrom(source) unless scratch.plunk.id is source
-
+      unless scratch.plunk.id is source then scratch.loadFrom source, ->
+        # Hack to force a repaint after AngularJS does first rendering
+        setTimeout ->
+          console.log "Re-render hack"
+          el = $(".plnk-sidebar")[0]
+          el.style.display = "none"
+          el.offsetHeight
+          el.style.display = "block"
+        , 1
+
   $scope.scratch = scratch
+
+
 ]


Made APIError more readable

Made APIError more readable

--- picoCTF-web/web/coffee/dependencies.coffee
+++ picoCTF-web/web/coffee/dependencies.coffee
@@ -5,7 +5,7 @@
   $.ajax {url: url, type: type, data: data, cache: false}
   .fail (jqXHR, text) ->
     ga('send', 'event', 'Error', 'APIOffline')
-    $.notify "API is offline. :(", "error"
+    $.notify "The picoCTF server is currently down. We will work to fix this error right away.", "error"

 @redirectIfNotLoggedIn = ->
   apiCall "GET", "/api/user/status", {}


plan-viz: Make row scale comparable between plans.

--- community/browser/lib/visualization/components/queryPlan.coffee
+++ community/browser/lib/visualization/components/queryPlan.coffee
@@ -1,4 +1,7 @@
 neo.queryPlan = (element)->
+
+  maxComparableRows = 1000000 # link widths are comparable between plans if all operators are below this row count
+  maxChildOperators = 2 # Fact we know about the cypher compiler

   operatorWidth = 180
   operatorCornerRadius = 4
@@ -138,8 +141,8 @@

     linkWidth = do ->
       scale = d3.scale.log()
-      .domain([1, d3.max(operators, (operator) -> rows(operator) + 1)])
-      .range([2, (operatorWidth - operatorCornerRadius * 2) / d3.max(operators, (operator) -> operator.children.length)])
+      .domain([1, Math.max(d3.max(operators, (operator) -> rows(operator) + 1), maxComparableRows)])
+      .range([2, (operatorWidth - operatorCornerRadius * 2) / maxChildOperators])
       (operator) ->
         scale(rows(operator) + 1)


Restructured guards per @RSO's suggestion

--- core/app/backbone/views/tour/tour_interesting_users_view.coffee
+++ core/app/backbone/views/tour/tour_interesting_users_view.coffee
@@ -83,11 +83,13 @@

   userListItemWidth: ->
     # Fixed width from options overrides calculation
-    return @options.userListItemWidth if @options.userListItemWidth?
+    if @options.userListItemWidth?
+      return @options.userListItemWidth

     # Return some random number so on subsequent renders the
     # TourUserViews are not clipped
-    return 500 if @shuffledCollection.isEmpty()
+    if @shuffledCollection.isEmpty()
+      return 500

     # width of TourUserView including margin
     @listView().children.first().$el.outerWidth(true)


Removing SLI Admin from default realm

Removing SLI Admin from default realm

--- sli/admin-tools/admin-rails/app/assets/javascripts/realms.js.coffee
+++ sli/admin-tools/admin-rails/app/assets/javascripts/realms.js.coffee
@@ -198,7 +198,6 @@
                 for (var i in SLI_ROLES) {
                       rMap.push([SLI_ROLES[i], SLI_ROLES[i]]);
                 }
-                rMap.push(["SLI Administrator", "SLI Administrator"]);
                 var success = function(data) {
                         rMap = getTableData(data.mappings);
                         sortTable(rMap, sortCol, sortOrder[sortCol]);


Fix referring wrong elements for tabs

Fix referring wrong elements for tabs

It uses last content of the variable, not the one during definition time.
There's coffeescript way to fix it but apparently event.target works as well.

    do (tabs) =>
        $(tabs).sortable ...

--- resources/assets/coffee/react/profile-page/extra.coffee
+++ resources/assets/coffee/react/profile-page/extra.coffee
@@ -37,20 +37,17 @@
       handle: '.js-profile-page-extra--sortable-handle'
       revert: 150
       scrollSpeed: 10
-      update: =>
-        @updateOrder @refs.pages
+      update: @updateOrder

     for tabType in ['tabs', 'fixedTabs']
-      tabs = @refs[tabType]
-      $(tabs).sortable
+      $(@refs[tabType]).sortable
         items: '[data-page-id]'
         tolerance: 'pointer'
         cursor: 'move'
         disabled: !@props.withEdit
         revert: 150
         scrollSpeed: 0
-        update: =>
-          @updateOrder tabs
+        update: @updateOrder

   componentWillUnmount: =>
@@ -73,8 +70,8 @@
     @setState(tabsSticky: newState) if newState != @state.tabsSticky

-  updateOrder: (elems) =>
-    $elems = $(elems)
+  updateOrder: (event) =>
+    $elems = $(event.target)

     newOrder = $elems.sortable('toArray', attribute: 'data-page-id')


Add client-side support for Severity.SUCCESS

--- tapestry-core/src/main/coffeescript/META-INF/modules/core/alert.coffee
+++ tapestry-core/src/main/coffeescript/META-INF/modules/core/alert.coffee
@@ -20,6 +20,7 @@
   (dom, console, messages, builder, ajax, _) ->

     severityToClass =
+      success: "alert alert-success"
       warn: "alert alert-warning"
       error: "alert alert-error"


Split environments bundled test set

Split environments bundled test set

--- scripts/test-instance/parallel-sets.coffee
+++ scripts/test-instance/parallel-sets.coffee
@@ -76,6 +76,9 @@

   [
     'environments vm'
+  ]
+
+  [
     'environments paidaccount'
   ]


Properly comment out test set

Properly comment out test set

--- scripts/test-instance/parallel-sets.coffee
+++ scripts/test-instance/parallel-sets.coffee
@@ -97,8 +97,8 @@
     { name: 'teams teamslikeunlike' }
   ]

-  [
-    # { name: 'environments vm-advanced' }
-  ]
+  # [
+  #   { name: 'environments vm-advanced' }
+  # ]

 ]


refactor(helper): append the word Help onto the task helper

--- init/rapid.coffee
+++ init/rapid.coffee
@@ -3,7 +3,7 @@
 module.exports = (gulp, config) ->
 	q            = require 'q'
 	gulpSequence = require('gulp-sequence').use gulp
-	task         = require("#{config.req.helpers}/tasks") gulp
+	taskHelp     = require("#{config.req.helpers}/tasks") gulp
 	defer        = q.defer()

 	# default
@@ -36,7 +36,7 @@
 			"#{config.rb.prefix.task}common-test-client"
 			"#{config.rb.prefix.task}run-client-tests"
 			cb
-		) -> defer.resolve() unless task.wasCalledFrom config.rb.tasks['test']
+		) -> defer.resolve() unless taskHelp.wasCalledFrom config.rb.tasks['test']

 	# test default - server
 	# =====================
@@ -47,7 +47,7 @@
 			"#{config.rb.prefix.task}common-test-server"
 			"#{config.rb.prefix.task}stop-server"
 			cb
-		) -> defer.resolve() unless task.wasCalledFrom config.rb.tasks['test']
+		) -> defer.resolve() unless taskHelp.wasCalledFrom config.rb.tasks['test']

 	# dev
 	# ===
@@ -115,7 +115,7 @@
 				"#{config.rb.prefix.task}minify-server"
 			]
 			cb
-		) -> defer.resolve() unless task.wasCalledFrom config.rb.tasks['prod:server']
+		) -> defer.resolve() unless taskHelp.wasCalledFrom config.rb.tasks['prod:server']

 	# prod server
 	# ===========
@@ -145,7 +145,7 @@
 			"#{config.rb.prefix.task}run-client-tests"
 			"#{config.rb.prefix.task}clean-client-test-dist"
 			cb
-		) -> defer.resolve() unless task.wasCalledFrom config.rb.tasks['prod:test']
+		) -> defer.resolve() unless taskHelp.wasCalledFrom config.rb.tasks['prod:test']

 	# test prod - server
 	# ==================
@@ -158,7 +158,7 @@
 			"#{config.rb.prefix.task}clean-server-test-dist"
 			"#{config.rb.prefix.task}stop-server"
 			cb
-		) -> defer.resolve() unless task.wasCalledFrom config.rb.tasks['prod:test']
+		) -> defer.resolve() unless taskHelp.wasCalledFrom config.rb.tasks['prod:test']

 	# return
 	# ======


DEMO: add vertically stacked buttonbar example.

--- demo/src/demos/ButtonDemo.coffee
+++ demo/src/demos/ButtonDemo.coffee
@@ -799,6 +799,45 @@
 		@__demo_table.addExample("example 4 flat, icon and optional text, mini", [ CUI.dom.append(CUI.dom.append(CUI.dom.append(CUI.dom.div(), CUI.dom.div("cui-buttonbar-demo-margin-testers")), bb.DOM), CUI.dom.div("cui-buttonbar-demo-margin-testers"))] )

+		bb = new CUI.Buttonbar(
+			stack: "vertical"
+			buttons: [
+				new CUI.Button(
+					text: "Vertical"
+					appearance: "flat",
+					icon_left: new CUI.Icon(class: "fa-plus"),
+				)
+				new CUI.Button(
+					text: "Stack"
+					appearance: "flat",
+					icon_left: new CUI.Icon(class: "fa-plus"),
+				)
+				new CUI.Button(
+					text: "Hinzufügen"
+					appearance: "flat",
+					bordered: true
+					icon_left: new CUI.Icon(class: "fa-plus"),
+				)
+				new CUI.Button(
+					text: "Stack"
+					appearance: "flat",
+					bordered: true
+					icon_left: new CUI.Icon(class: "fa-plus"),
+				)
+				new CUI.Button(
+					appearance: "flat",
+					icon_left: new CUI.Icon(class: "fa-cog"),
+				)
+				new CUI.Button(
+					appearance: "flat",
+					bordered: true
+					icon_left: new CUI.Icon(class: "fa-cog"),
+				)
+			]
+		)
+		@__demo_table.addExample("example 5, vertically stacked buttonbar", [ CUI.dom.append(CUI.dom.append(CUI.dom.append(CUI.dom.div(), CUI.dom.div("cui-buttonbar-demo-margin-testers")), bb.DOM), CUI.dom.div("cui-buttonbar-demo-margin-testers"))] )
+
+
 		@__addDivider("Using Styles on Buttons inside buttonbar")

 		bb = new CUI.Buttonbar(


improved contact us form progress feedback

--- services/web/public/coffee/main/universties-site.coffee
+++ services/web/public/coffee/main/universties-site.coffee
@@ -5,13 +5,20 @@
 	App.controller 'UniverstiesContactController', ($scope, $modal) ->

 		$scope.form = {}
+		$scope.sent = false
+		$scope.sending = false
 		$scope.contactUs = ->
+			if !$scope.form.email?
+				console.log "email not set"
+				return
+			$scope.sending = true
 			params =
 				name: $scope.form.name || $scope.form.email
 				email: $scope.form.email
-				labels: $scope.form.type
+				labels: $scope.form.source
 				message: "Please contact me with more details"
 				subject: $scope.form.subject
-				about : "#{$scope.form.position || ''} #{$scope.form.university || ''} #{$scope.form.source || ''}"
+				about : "#{$scope.form.position || ''} #{$scope.form.university || ''}"

 			Groove.createTicket params, (err, json)->
+				$scope.sent = true


Scripts: Also call $(document).ready when turbolinks changes page content

--- app/assets/javascripts/app.coffee
+++ app/assets/javascripts/app.coffee
@@ -27,7 +27,11 @@

-$(document).ready ->
+ready ->
   triviaInit()
   $('table.nav .menu-btn a').click ->
     $('table.nav .items, table.nav .search').toggleClass('isOpen')
+
+$(document).ready(ready)
+# For turbolinks
+$(document).on('page:load', ready)


JMachine::shareWith method { user: yes, owner: no, target: "gokmen"}

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -39,6 +39,8 @@
       instance          :
         reviveUsers     :
           (signature Function)
+        shareWith     :
+          (signature Object, Function)
         setProvisioner  :
           (signature String, Function)
         setLabel        :
@@ -357,3 +359,86 @@
           @update $set: { slug, label }, (err)-> kallback err, slug
       else
         @update $set: { label }, (err)-> kallback err, slug
+
+
+  addUser: (user, owner, callback)->
+
+    userId = user.getId()
+    users  = []
+
+    for u in @users
+      users.push u  unless userId.equals u.id
+
+    users.push { id: userId, owner }
+
+    @update $set: { users }, callback
+
+
+  removeUser: (user, callback)->
+
+    userId = user.getId()
+    users  = []
+
+    for u in @users
+      users.push u  unless userId.equals u.id
+
+    @update $set: { users }, callback
+
+
+  shareWith: (options, callback)->
+
+    { target, user, owner } = options
+    user  ?= yes
+    owner ?= no
+
+    unless target?
+      return callback new KodingError "Target required."
+
+    JUser = require '../user'
+    JName = require '../name'
+
+    JName.fetchModels target, (err, result)=>
+
+      if err or not result?
+        return callback new KodingError "Target not found."
+
+      [ target ] = result.models
+
+      if target instanceof JUser
+
+        if user
+        then @addUser target, owner, callback
+        else @removeUser target, callback
+
+      else
+        callback new KodingError "Target does not support machines."
+
+
+  # .share can be used like this:
+  #
+  # JMachineInstance.shareWith { user: yes, owner: no, target: "gokmen"}, cb
+  #                                                user slug -> ^^^^^^
+
+  shareWith$: permit 'populate users',
+
+    success: revive
+
+      shouldReviveClient   : yes
+      shouldReviveProvider : no
+
+    , (client, options, callback)->
+
+      { r: { user } } = client
+
+      unless isOwner user, this
+        return callback new KodingError "Access denied"
+
+      { target } = options
+
+      # Owners cannot unassign them from a machine
+      # Only another owner can unassign any other owner
+      if user.username is target
+        return callback \
+          new KodingError "It's not allowed to change owner's state!"
+
+      JMachine::shareWith.call this, options, callback


FIX: Add in forward looking tasks on top tasks

--- src/app/tasks/project-top-tasks-list/project-top-tasks-list.coffee
+++ src/app/tasks/project-top-tasks-list/project-top-tasks-list.coffee
@@ -75,7 +75,7 @@
       #
       # Step 3: ... up to date, so look forward
       #
-      toAdd = _.filter sortedTasks, (task) -> _.includes(taskService.toBeWorkedOn, task.status) && taskService.daysFromTarget(task) <= 0
+      toAdd = _.filter sortedTasks, (task) -> _.includes(taskService.toBeWorkedOn, task.status) && taskService.daysUntilTargetDate(task) >= 0
       # Add tasks by grade... pass is always done first!
       for grade in gradeService.gradeValues
         toAddGradeTasks = _.map (_.filter toAdd, (task) -> task.definition.target_grade == grade), (task) ->


small refactor

small refactor

--- src/math3d.coffee
+++ src/math3d.coffee
@@ -419,6 +419,12 @@
             @boundingBox.geometry.boundingBox = obj.geometry.boundingBox.clone()
         @boundingBox.update @boundingBox

+    _finalizeObj: (obj, in_frame) ->
+        if in_frame
+            @updateBoundingBox obj
+        @scene.add obj
+        return obj
+
     addText: (opts) ->
         opts = defaults opts,
             text        : required
@@ -460,9 +466,9 @@

         material.color.setRGB opts.texture.color...

-        mesh = new THREE.Mesh geometry, material
-        mesh.position.copy(@vector opts.loc...)
-        mesh.rotation.set opts.rotation...
+        text = new THREE.Mesh geometry, material
+        text.position.copy(@vector opts.loc...)
+        text.rotation.set opts.rotation...

         geometry.computeBoundingBox()

@@ -470,8 +476,8 @@
         tmp = new THREE.Vector3()

         # will be called on render, this is used to make
-        # mesh.rotation be centered on the center of the text
-        mesh.updateMatrix = ->
+        # text.rotation be centered on the center of the text
+        text.updateMatrix = ->
             @matrix.makeRotationFromQuaternion @quaternion
             @matrix.scale @scale

@@ -480,10 +486,7 @@

             @matrixWorldNeedsUpdate = true

-        if opts.in_frame
-            @updateBoundingBox mesh
-        @scene.add mesh
-        return mesh
+        return @_finalizeObj text, opts.in_frame

     addLine: (opts) ->
         opts = defaults opts,
@@ -500,10 +503,7 @@
         line = new THREE.Line geometry, new THREE.LineBasicMaterial(linewidth:opts.thickness)
         line.material.color.setRGB opts.texture.color...

-        if opts.in_frame
-            @updateBoundingBox line
-        @scene.add line
-        return line
+        return @_finalizeObj line

     addSphere: (opts) ->
         opts = defaults opts,
@@ -534,10 +534,7 @@
         sphere = new THREE.Mesh geometry, material
         sphere.position.copy(@vector opts.loc...)

-        if opts.in_frame
-            @updateBoundingBox sphere
-        @scene.add sphere
-        return sphere
+        return @_finalizeObj sphere, opts.in_frame

     addPoint: (opts) ->
         opts = defaults opts,
@@ -647,10 +644,7 @@
         mesh = new THREE.Mesh geometry, material
         mesh.position.set 0, 0, 0

-        if opts.in_frame
-            @updateBoundingBox mesh
-        @scene.add mesh
-        return mesh
+        return @_finalizeObj mesh, opts.in_frame

     addGroup: (opts) ->
         opts = defaults opts,


removing window reference for exports

removing window reference for exports

--- src/matrix.coffee
+++ src/matrix.coffee
@@ -306,6 +306,6 @@
     Object.freeze Matrix.VERTICAL_FLIP

   # Export to window
-  window["Matrix"] = Matrix
+  (exports ? this)["Matrix"] = Matrix
 )()


kubernikus: Specify format for event datetime to avoid parser warnings

--- plugins/kubernetes/app/assets/javascripts/kubernetes/components/clusters/events.coffee
+++ plugins/kubernetes/app/assets/javascripts/kubernetes/components/clusters/events.coffee
@@ -27,11 +27,11 @@
             div key: event.firstTimestamp,
               i className: "event-type #{event.type.toLowerCase()}"
               strong null,
-                moment(event.firstTimestamp).format("HH:mm:ss")
+                moment(event.firstTimestamp, 'YYYY-MM-DD HH:mm:ss ZZ Z').format("HH:mm:ss")
                 if (event.count > 1)
                   span null,
                     " - "
-                    moment(event.lastTimestamp).format("HH:mm:ss")
+                    moment(event.lastTimestamp, 'YYYY-MM-DD HH:mm:ss ZZ Z').format("HH:mm:ss")
                     " (#{event.count} times)"

               p null,


simpler public interface for Batman.RenderContext

--- src/batman.coffee
+++ src/batman.coffee
@@ -4179,6 +4179,8 @@

   get: (key) -> @findKey(key)[0]

+  contextForKey: (key) -> @findKey(key)[1]
+
   # Below are the three primitives that all the `Batman.DOM` helpers are composed of.
   # `descend` takes an `object`, and optionally a `scopedKey`. It creates a new `RenderContext` leaf node
   # in the tree with either the object available on the stack or the object available at the `scopedKey`
@@ -4354,7 +4356,7 @@
       context.descendWithKey(key, localName)

     view: (node, bindKey, contextKey, context) ->
-      [_, parent] = context.findKey contextKey
+      parent = context.contextForKey(contextKey)
       view = null
       parent.observeAndFire contextKey, (newValue) ->
         view ||= Batman.data node, 'view'
@@ -4708,7 +4710,7 @@

   # The `keyContext` accessor is
-  @accessor 'keyContext', -> @renderContext.findKey(@key)[1]
+  @accessor 'keyContext', -> @renderContext.contextForKey(@key)

   bindImmediately: true
   shouldSet: true
@@ -5116,8 +5118,7 @@
       @reapplyOldStyles()
       for own key, keyValue of value
         # Check whether the value is an existing keypath, and if so bind this attribute to it
-        [keypathValue, keypathContext] = @renderContext.findKey(keyValue)
-        if keypathValue
+        if keypathValue = @renderContext.get(keyValue)
           @bindSingleAttribute key, keyValue
           @setStyle key, keypathValue
         else
@@ -5394,8 +5395,7 @@
             $insertBefore @parentNode(), node, @siblingNode

         if addItem = node.getAttribute 'data-additem'
-          [_, context] = @renderer.context.findKey addItem
-          context?[addItem]?(item, node)
+          @renderer.context.contextForKey(addItem)?[addItem]?(item, node)

       @actions[options.actionNumber].item = item
     @processActionQueue()
@@ -5547,7 +5547,7 @@
     return if not string
     values = {}
     for k, v of interpolationKeypaths
-      values[k] = @findKey(v)[0]
+      values[k] = @get(v)
       if !values[k]?
         Batman.developer.warn "Warning! Undefined interpolation key #{k} for interpolation", string
         values[k] = ''


converted #374 to backbone

converted #374 to backbone

--- app/assets/javascripts/admin/views/task/task_create_from_nml_view.coffee
+++ app/assets/javascripts/admin/views/task/task_create_from_nml_view.coffee
@@ -30,7 +30,41 @@
       </div>
     </div>
   </div>
+
   """)

-  #events :
-  # put submit event here
+  events :
+    # track file picker changes
+    "change input[name=nmlFile]" : "updateFilenames"
+
+
+  ui :
+    # .file-info shows names of selected files
+    "fileInfo" : ".file-info"
+
+  ###*
+   * Event handler which updates ui so user can see filenames he selected
+   *
+   * @method updateFilenames
+   ###
+  updateFilenames : (evt) ->
+
+    # grab file list from event
+    files = evt.target.files
+
+    # do nothing if nothing selected
+    if files
+
+      # concat files comma separated
+      if files.length > 1
+
+        filePath = ""
+        for index in [0..file.length]
+          filePath += @files[index].name + ", "
+
+      # display a single file
+      else
+        filePath = files[0].name
+
+      # update ui
+      @ui.fileInfo.val(filePath)


put shabbat schedule in a try-catch

put shabbat schedule in a try-catch

--- source/javascripts/shabbat/vatikin.coffee
+++ source/javascripts/shabbat/vatikin.coffee
@@ -35,8 +35,12 @@
   """

 update_table = ->
+  value = this.value
+  window.catching_errors 'Shabbat', value, -> update_table_in_try_catch(value)
+
+update_table_in_try_catch = (value) ->
   $("table.vatikin-schedule tr").not(":nth-child(1)").remove()
-  year = parseInt(this.value)
+  year = parseInt(value)
   $("table.vatikin-schedule tr:nth-child(1) th:nth-child(1)").html(year)
   hebrewDate =  new HebrewDate(new RoshHashana(year).getGregorianDate())
   while hebrewDate.getYearFromCreation() == year


Classifier: Load tutorial translations on props change (#5153)

* Load tutorial translations on props change
Add translations.load actions for tutorials and minicourses if they are reloaded after a props change in the ClassifierWrapper.
Remove componentWillReceiveProps from the ClassifierWrapper and replace it with componentDidUpdate.

* Start tutorial on state change
Start the tutorial, if necessary, after tutorial state has changed.

--- app/classifier/index.cjsx
+++ app/classifier/index.cjsx
@@ -71,7 +71,6 @@
     Tutorial.find @props.workflow
     .then (tutorial) =>
       {user, preferences} = @props
-      Tutorial.startIfNecessary tutorial, user, preferences, @context.geordi, @context.store
       @setState {tutorial}
       this.props.actions.translations.load('tutorial', tutorial.id, this.props.translations.locale) if tutorial?
     MiniCourse.find @props.workflow
@@ -79,29 +78,32 @@
       @setState {minicourse}
       this.props.actions.translations.load('minicourse', minicourse.id, this.props.translations.locale) if minicourse?

-  componentDidUpdate: (prevProps) ->
+  componentDidUpdate: (prevProps, prevState) ->
     { tutorial, minicourse } = @state
     if prevProps.translations.locale isnt this.props.translations.locale
       this.props.actions.translations.load('tutorial', tutorial.id, this.props.translations.locale) if tutorial?
       this.props.actions.translations.load('minicourse', minicourse.id, this.props.translations.locale) if minicourse?

-  componentWillReceiveProps: (nextProps) ->
-    if nextProps.workflow isnt @props.workflow
-      Tutorial.find nextProps.workflow
+    if prevProps.workflow isnt @props.workflow
+      Tutorial.find @props.workflow
       .then (tutorial) =>
-        {user, preferences} = nextProps
-        Tutorial.startIfNecessary tutorial, user, preferences, @context.geordi, @context.store
+        {user, preferences} = @props
         @setState {tutorial}
-      MiniCourse.find nextProps.workflow
+        this.props.actions.translations.load('tutorial', tutorial.id, this.props.translations.locale) if tutorial?
+      MiniCourse.find @props.workflow
       .then (minicourse) =>
         @setState {minicourse}
-
-    if @props.user isnt nextProps.user
+        this.props.actions.translations.load('minicourse', minicourse.id, this.props.translations.locale) if minicourse?
+
+    if tutorial isnt prevState.tutorial
+      Tutorial.startIfNecessary tutorial, @props.user, @props.preferences, @context.geordi, @context.store
+
+    if @props.user isnt prevProps.user
       @setState expertClassifier: null
-      @checkExpertClassifier nextProps
-
-    unless nextProps.classification is @props.classification
-      @loadClassificationsCount nextProps.subject
+      @checkExpertClassifier @props
+
+    unless prevProps.classification is @props.classification
+      @loadClassificationsCount @props.subject

   onComplete: ->
     classificationsThisSession += 1


Update version

Update version

--- index.cjsx
+++ index.cjsx
@@ -11,7 +11,7 @@
   description: "远征信息查询 & 成功条件检查"
   author: "马里酱"
   link: "https://github.com/malichan"
-  version: "1.2.1"
+  version: "1.2.2"
   reactClass: React.createClass
     getInitialState: ->
       fs = require "fs-extra"


add bucket url to config

add bucket url to config

--- config/server.coffee
+++ config/server.coffee
@@ -6,5 +6,5 @@

 config.PRODUCTION = process.env.NODE_ENV is "production"

-# add this when we have a production URL
-config.BASE_URL  = if config.PRODUCTION then "http://codedoodl.es" else "http://#{config.express.ip}:#{config.express.port}"
+config.BASE_URL   = if config.PRODUCTION then "http://codedoodl.es" else "http://#{config.express.ip}:#{config.express.port}"
+config.BUCKET_URL = 'http://source.codedoodl.es'


add automatic resize of main map on window resize

--- app/assets/javascripts/modules/home/base.js.coffee
+++ app/assets/javascripts/modules/home/base.js.coffee
@@ -1,5 +1,11 @@
 $(document).ready( ->
+  $(window).resize( ->
+    $('.map--main').css('height', (window.innerHeight/100)*70)
+  )
+
   $('.js-close-explore').click( (ev) ->
     $('.js-explore-target').fadeOut()
   )
+
+  $(window).trigger('resize')
 )


fix error that showed on pages without map

--- app/assets/javascripts/map.coffee
+++ app/assets/javascripts/map.coffee
@@ -2,6 +2,7 @@
 $(->
   # map setup
   map_div  = document.getElementById("map")
+  return unless map_div
   map_data = $(map_div).data()
   mode     = map_data.mode


fixed another ambiguity

fixed another ambiguity

--- app/assets/javascripts/active_admin/lib/dropdown-menu.js.coffee
+++ app/assets/javascripts/active_admin/lib/dropdown-menu.js.coffee
@@ -9,7 +9,7 @@
       onClickActionItemCallback: null
     }

-    @options = $.extend defaults, options
+    @options = $.extend defaults, @options
     @isOpen  = false

     @$menuButton = @$element.find '.dropdown_menu_button'


Refactor clearing of textfield

Refactor clearing of textfield

--- app/assets/javascripts/backbone/views/rooms/show_view.js.coffee
+++ app/assets/javascripts/backbone/views/rooms/show_view.js.coffee
@@ -17,15 +17,19 @@

   doSubmit: (e) ->
     # Get the body of the message from the input
-    body = $("#body").val()
-    $("#body").val('')
-
-
+    input = $("#body")
+    body = input.val()
+
     # Create a new message
     @collection.create({
       body: body,
       room_id: room.id
-    }, {silent: true})
+    }, {
+      silent: true,
+      success: ->
+        # Clear the input field
+        input.val('')
+    })

     e.preventDefault()
     return false


Fix unit service specifier.

Fix unit service specifier.

Previously the code actually never filtered
using the root service.

--- src/models.coffee
+++ src/models.coffee
@@ -343,20 +343,20 @@

         getSpecifierText: (selectedServices) ->
             specifierText = ''
-            services = @get 'services'
-            unless services?
+            unitServices = @get 'services'
+            unless unitServices?
                 return specifierText

             if selectedServices?.size() > 0
                 selectedIds = selectedServices.pluck 'id'
-                services = _.filter services, (s) =>
+                services = _.filter unitServices, (s) =>
                     s.id in selectedIds
                 if services.length == 0
                     roots = selectedServices.pluck 'root'
-                    services = _.filter services, (s) =>
+                    services = _.filter unitServices, (s) =>
                         s.root in roots
                 if services.length == 0
-                    services = @get 'services'
+                    services = unitServices
             level = null
             for service in services
                 if not level or service.level < level


Replace html chechbox with font-awesome alternative to avoid react's error

--- app/assets/javascripts/react_components/todo_list/app.js.coffee
+++ app/assets/javascripts/react_components/todo_list/app.js.coffee
@@ -21,21 +21,20 @@
       id:       id
       text:     payload.text
       complete: false
-
     @todos[id] = todo
-    @emit 'change'
+    @emit('change')

   onToggleTodo: (payload) ->
     id = payload.id
     @todos[id].complete = not @todos[id].complete
-    @emit 'change'
+    @emit('change')

   onClearTodos: ->
     todos = @todos
     Object.keys(todos).forEach (key) ->
       if todos[key].complete
-        delete todos[key]
-    @emit 'change'
+        delete(todos[key])
+    @emit('change')

   getState: ->
     todos: @todos
@@ -43,14 +42,14 @@
   _nextTodoId: ->
     @todoId += 1

-# Semantic actions
+# Registering our semantic actions

 actions =
-  addTodo:    (text) -> @dispatch constants.ADD_TODO,    text: text
-  toggleTodo: (id)   -> @dispatch constants.TOGGLE_TODO, id:   id
-  clearTodos:        -> @dispatch constants.CLEAR_TODOS
+  addTodo:    (text) -> @dispatch(constants.ADD_TODO,    text: text)
+  toggleTodo: (id)   -> @dispatch(constants.TOGGLE_TODO, id:   id)
+  clearTodos:        -> @dispatch(constants.CLEAR_TODOS)

-# instantiating our stores
+# Instantiating our stores

 stores =
   TodoStore: new TodoStore
@@ -133,12 +132,11 @@

   # Its style will be determined based on the completion state.
   render: ->
-
-      <input onClick={@onClick}
-             type="checkbox"
-             checked={if @props.todo.complete then "checked" else ""}/>
+    checkbox = if @props.todo.complete then "fa fa-check-square-o" else "fa fa-square-o"
+

+
       {@props.todo.text}
-
+

   # Clicking on a todo item will toggle the completion state.
   onClick: ->
@@ -147,4 +145,4 @@
 # Rendering the whole component
 document.addEventListener 'DOMContentLoaded', (e) ->
   React.render <Application flux={flux} />,
-                document.getElementById 'react_mountPoint'
+                document.getElementById("react_mountPoint")


woops random colon

woops random colon

--- app/components/confirm-account-page/confirm-account-page.coffee
+++ app/components/confirm-account-page/confirm-account-page.coffee
@@ -1,5 +1,5 @@
 module.exports =
-  url: '/confirm_account?confirmation_token&:group_id'
+  url: '/confirm_account?confirmation_token&group_id'
   template: require('./confirm-account-page.html')
   controller: ($scope, $auth, LoadBar, $location, $stateParams, Records, Toast) ->


fix: -d invalid

fix: -d invalid

--- src/npm-up.coffee
+++ src/npm-up.coffee
@@ -21,7 +21,7 @@
         install: no
         lock: no
         all: no # w + i + l
-        devDep: yes, dep: yes, optional: yes
+        dev: yes, dep: yes, optional: yes
         silent: no
         lockAll: false
         cache: true
@@ -91,7 +91,7 @@
     deps = []
     if option.dep
         deps = deps.concat formatPackages globalPackage.dependencies, 'S'
-    if option.devDep
+    if option.dev
         deps = deps.concat formatPackages globalPackage.devDependencies, 'D'
     if option.optional
         deps = deps.concat formatPackages globalPackage.optionalDependencies, 'O'


Blaze support.

Blaze support.

--- shareit.coffee
+++ shareit.coffee
@@ -1,3 +1,7 @@
+if Package.ui
+  ->
+    Handlebars = Package.ui.Handlebars
+
 Handlebars.registerHelper "shareit", ->
   new Handlebars.SafeString(Template.shareit(this))


Keep a disabled select disabled when options change.

--- src/chosen.coffee
+++ src/chosen.coffee
@@ -46,7 +46,14 @@
       options[snakeCase(key)] = scope.$eval(value) if key in CHOSEN_OPTION_WHITELIST

     startLoading = -> element.addClass('loading').attr('disabled', true).trigger('chosen:updated')
-    stopLoading = -> element.removeClass('loading').attr('disabled', false).trigger('chosen:updated')
+
+    stopLoading = ->
+      element.removeClass('loading')
+      if angular.isDefined attr.disabled
+        element.attr 'disabled', attr.disabled
+      else
+        element.attr 'disabled', false
+      element.trigger('chosen:updated')

     chosen = null
     defaultText = null


serverNotify ftw. Please bower update.

serverNotify ftw. Please bower update.

--- app/client/js/localstorage.coffee
+++ app/client/js/localstorage.coffee
@@ -116,7 +116,7 @@
       # TODO(steida): Try/Catch in case of error. Report error to server.
       json = (`/** @type {Object} */`) JSON.parse browserEvent.newValue
       store.fromJson json
-      store.notify()
+      store.serverNotify()

       # NOTE(steida): Reload browser if user login state has changed.
       if store instanceof app.user.Store


refactor strategy

refactor strategy

--- src/player.coffee
+++ src/player.coffee
@@ -2,7 +2,8 @@

 pkg = require '../package.json'

-decodeRank = require './decodeRank'
+getMinBet = require './getMinBet'
+analyzeHand = require './analyzeHand'

 module.exports =
   version: ->
@@ -10,42 +11,29 @@
   betRequest: (gameState, next) ->
     if gameState.testBet
       return next null, gameState.testBet
-    bigBlind = gameState.small_blind * 2
-    minBet = bigBlind
-    bet = gameState.current_buy_in
-    bet = minBet unless bet > minBet

-    me = gameState?.players?[gameState?.in_action]
-    if me.hole_cards?.length == 1
-      card = me.hole_cards[0]
-      value = decodeRank card.rank
-      if value < 10
-        return next null, 0
+    commitment = gameState.players[gameState.in_action]?.bet
+    minBet = getMinBet gameState
+    seriousness = minBet / (gameState.small_blind * 2)

-    unless me.hole_cards?.length > 1
-      return next null, bet
+    myHand = analyzeHand gameState

-    cards = _.map me.hole_cards, (card) ->
-      suit: card.suit
-      rank: decodeRank card.rank
-
-    communityCards = _.map (me.community_cards ? []), (card) ->
-      suit: card.suit
-      rank: decodeRank card.rank
-
-    if cards[0]?.rank == cards[0]?.rank
-      return next null, bigBlind
-
-    allCards = cards.concat communityCards
-
-    pairs = _ allCards
-    .groupBy (card) -> String card.rank
+    pairs = _ myHand.all
+    .groupBy (card) -> card.rankString
     .filter (group) -> group.length > 1
     .value()

+    if commitment == 0 and seriousness > 2
+      unless pairs.length > 0
+        console.log 'too serious'
+        return next null, 0
+
     if pairs.length > 0
-      return next null, bigBlind
+      return next null, minBet * 10

-    next null, bet
+    if seriousness > 5
+      return next null, 0
+
+    next null, minBet
   showdown: (gameState, next) ->
     next()


Fix Player#cameraFocus position not matching sprite's.

Account for physics offset by using #physics.position. Use more Point
methods.

--- src/player.coffee
+++ src/player.coffee
@@ -344,8 +344,10 @@
       # Follow with easing.
       kEasing = @cameraFocusFollowResistance
       kEasing /= 3 if @_isFullyFalling()
-      @cameraFocus.x += (@sprite.x - @cameraFocus.x) // kEasing
-      @cameraFocus.y += (@sprite.y - @cameraFocus.y) // kEasing
+      step = @physics.position.clone()
+        .subtractPoint @cameraFocus.position
+        .divide kEasing, kEasing
+      @cameraFocus.position.addPoint step

   _.extend Player::, AnimationMixin, DebugMixin


Update client.coffee

Update client.coffee

--- src/client.coffee
+++ src/client.coffee
@@ -6,7 +6,7 @@
     @cappingMinimumTimeInterval: 0
     @timeout: 0

-    @get: (url, headers, timeout, cb) ->
+    @get: (url, headers, timeout, logger, cb) ->
         now = +new Date()

         # Check totalCallsTimeout (first call + 1 hour), if older than now,
@@ -28,7 +28,7 @@

         # TODO: handle request timeout

-        VASTParser.parse url, headers, timeout, (response) =>
+        VASTParser.parse url, headers, timeout, logger, (response) =>
             cb(response)


referral: fix selected recipient invitation procedure

--- client/app/Applications/Account.kdapplication/views/referrermodal.coffee
+++ client/app/Applications/Account.kdapplication/views/referrermodal.coffee
@@ -96,11 +96,9 @@
       title   : "Send invitation(s)"
       callback: =>
         recipients = listController.getItemsOrdered().filter (view) =>
-          return  view.isSelected and not contact.invited
+          return  view.isSelected and not view.getData().invited

         recipients.forEach (view) ->
-          contact = view.getData()
-          return if not view.isSelected or contact.invited
           view.getData().invite (err) =>
             return log "invite", err  if err
             view.emit "InvitationSent"


Remove trailing whitespace.

Remove trailing whitespace.

--- src/Deferred.coffee
+++ src/Deferred.coffee
@@ -1,9 +1,9 @@
-###
+###
 Standalone Deferred
-Copyright 2012 Otto Vehviläinen
+Copyright 2012 Otto Vehviläinen
 Released under MIT license

-This is a standalone implementation of the wonderful jQuery.Deferred API.
+This is a standalone implementation of the wonderful jQuery.Deferred API.
 The documentation here is only for quick reference, for complete api please
 see the great work of the original project:

@@ -31,19 +31,19 @@
 flatten = (args) ->
   return [] unless args
   flatted = []
-  args.forEach (item) ->
+  args.forEach (item) ->
     if item
       if typeof item == 'function'
         flatted.push(item)
       else
-        args.forEach (fn) ->
+        args.forEach (fn) ->
           if typeof fn == 'function'
             flatted.push(fn)
   flatted

 ###
-Promise object functions as a proxy for a Deferred, except
+Promise object functions as a proxy for a Deferred, except
 it does not let you modify the state of the Deferred
 ###
 class Promise
@@ -75,19 +75,19 @@
     this

 class root.Deferred
-
-  ###
-  Initializes a new Deferred. You can pass a function as a parameter
-  to be executed immediately after init. The function receives
+
+  ###
+  Initializes a new Deferred. You can pass a function as a parameter
+  to be executed immediately after init. The function receives
   the new deferred object as a parameter and this is also set to the
   same object.
-  ###
+  ###
   constructor: (fn) ->
     @_state = 'pending'
     fn.call(this, this) if typeof fn == 'function'
-
-  ###
-  Pass in functions or arrays of functions to be executed when the
+
+  ###
+  Pass in functions or arrays of functions to be executed when the
   Deferred object changes state from pending. If the state is already
   rejected or resolved, the functions are executed immediately. They
   receive the arguments that are passed to reject or resolve and this
@@ -104,12 +104,12 @@
       functions.forEach (fn) =>
         fn.apply(@_context, @_withArguments)
     this
-
-  ###
-  Pass in functions or arrays of functions to be executed when the
-  Deferred object is resolved. If the object has already been resolved,
+
+  ###
+  Pass in functions or arrays of functions to be executed when the
+  Deferred object is resolved. If the object has already been resolved,
   the functions are executed immediately. If the object has been rejected,
-  nothing happens. The functions receive the arguments that are passed
+  nothing happens. The functions receive the arguments that are passed
   to resolve and this is set to the object defined by resolveWith if that
   variant is used.
   ###
@@ -123,12 +123,12 @@
       @_doneCallbacks or= []
       @_doneCallbacks.push(functions...)
     this
-
-  ###
-  Pass in functions or arrays of functions to be executed when the
-  Deferred object is rejected. If the object has already been rejected,
+
+  ###
+  Pass in functions or arrays of functions to be executed when the
+  Deferred object is rejected. If the object has already been rejected,
   the functions are executed immediately. If the object has been resolved,
-  nothing happens. The functions receive the arguments that are passed
+  nothing happens. The functions receive the arguments that are passed
   to reject and this is set to the object defined by rejectWith if that
   variant is used.
   ###
@@ -142,7 +142,7 @@
       @_failCallbacks or= []
       @_failCallbacks.push(functions...)
     this
-
+
   ###
   Notify progress callbacks. The callbacks get passed the arguments given to notify.
   If the object has resolved or rejected, nothing will happen
@@ -150,7 +150,7 @@
   notify: (args...) ->
     @notifyWith(root, args...)
     this
-
+
   ###
   Notify progress callbacks with additional context. Works the same way as notify(),
   except this is set to context when calling the functions.
@@ -159,11 +159,11 @@
     return this if @_state != 'pending'
     @_progressCallbacks?.forEach (fn) ->
       fn.apply(context, args)
-    this
-
+    this
+
   ###
   Returns a new Promise object that's tied to the current Deferred. The doneFilter
-  and failFilter can be used to modify the final values that are passed to the
+  and failFilter can be used to modify the final values that are passed to the
   callbacks of the new promise. If the parameters passed are falsy, the promise
   object resolves or rejects normally. If the filter functions return a value,
   that one is passed to the respective callbacks. The filters can also return a
@@ -196,9 +196,9 @@
               def.rejectWith.call(def, this, failArgs...)
         else
           def.rejectWith.call(def, this, result)
-        def.rejectWith.call(def, this, args...)
+        def.rejectWith.call(def, this, args...)
       else
-        def.rejectWith.call(def, this, args...)
+        def.rejectWith.call(def, this, args...)
     def.promise()

   ###
@@ -210,13 +210,13 @@
     @_progressCallbacks or= []
     @_progressCallbacks.push(functions...)
     this
-
+
   ###
   Returns the promise object of this Deferred.
   ###
   promise: ->
     @_promise or= new Promise(this)
-
+
   ###
   Reject this Deferred. If the object has already been rejected or resolved,
   nothing happens. Parameters passed to reject will be handed to all current
@@ -225,7 +225,7 @@
   reject: (args...) =>
     @rejectWith(root, args...)
     this
-
+
   ###
   Reject this Deferred with additional context. Works the same way as reject, except
   the first parameter is used as this when calling the fail and always callbacks.
@@ -240,16 +240,16 @@
     @_alwaysCallbacks?.forEach (fn) =>
       fn.apply(@_context, args)
     this
-
+
   ###
   Resolves this Deferred object. If the object has already been rejected or resolved,
   nothing happens. Parameters passed to resolve will be handed to all current and
-  future done and always callbacks.
+  future done and always callbacks.
   ###
   resolve: (args...) =>
     @resolveWith(root, args...)
     this
-
+
   ###
   Resolve this Deferred with additional context. Works the same way as resolve, except
   the first parameter is used as this when calling the done and always callbacks.
@@ -270,7 +270,7 @@
   ###
   state: ->
     @_state
-
+
   ###
   Convenience function to specify each done, fail and progress callbacks at the same time.
   ###
@@ -282,8 +282,8 @@

 ###
 Returns a new promise object which will resolve when all of the deferreds or promises
-passed to the function resolve. The callbacks receive all the parameters that the
-individual resolves yielded as an array. If any of the deferreds or promises are
+passed to the function resolve. The callbacks receive all the parameters that the
+individual resolves yielded as an array. If any of the deferreds or promises are
 rejected, the promise will be rejected immediately.
 ###

@@ -293,11 +293,11 @@
   allReady = new Deferred()
   readyCount = 0
   allDoneArgs = []
-
+
   args.forEach (dfr, index) ->
     dfr
       .done (doneArgs...) ->
-        readyCount += 1
+        readyCount += 1
         allDoneArgs[index] = doneArgs
         if readyCount == args.length
           allReady.resolve(allDoneArgs...)


Fix fingers multi-line-limit test by adding a wait action.

--- src/Fingers/specs/multi-text-limit.coffee
+++ src/Fingers/specs/multi-text-limit.coffee
@@ -53,12 +53,12 @@
 		<input type="text" class="editable view-multi-text-limit-5" />
 		"""
 		$(".static-view").click()
+		wait 250 # fingers hooks up a click handler after a delay
 	]

 	"when type values into first 2 inputs and then presses Enter key": [
 		$("input:visible:eq(0)").type "value1"
 		$("input:visible:eq(1)").type "value2", ENTER
-		$("body").click()
 	]

 	"then the static view displays 'value1, value2'":


remove console logging for translatable

remove console logging for translatable

--- app/assets/javascripts/typus_serialize/collections/list_collection.js.coffee
+++ app/assets/javascripts/typus_serialize/collections/list_collection.js.coffee
@@ -1,23 +1,22 @@
 class Typus.Serialize.Collections.List extends Backbone.Collection

   model: Typus.Serialize.Models.Item
-
+
   initialize: (models, options) ->
     { @name, @keys, @locales } = options
     @min = options.limit.min or 0
     @max = options.limit.max or Infinity
-
+
   translatable: ->
-    console.log 'translatable'
     @locales.length > 0
-
+
   add: (models, options) ->
     if @length < @max
       super(models, options)

     if @length >= @max
       @trigger('limit:max', @)
-
+
   remove: (models, options) ->
     if @length > @min
       super(models, options)
@@ -27,7 +26,7 @@

     if @length is 1
       @trigger('limit:one', @)
-
+
   reset: (models, options) ->
     options or (options = {})

@@ -48,4 +47,3 @@

     if @length is 1
       @trigger('limit:one', @)
-


sims and cross origin fix for just now

sims and cross origin fix for just now

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -367,8 +367,16 @@
     @el.find("#toggle-fav").removeClass("toggled")

     $('#graph-container').addClass 'loading-lightcurve'
-    # jsonFile = 'offline/simulation_feedback_example.json'
-    jsonFile = @subject.selected_light_curve.location
+
+
+    if window.location.origin != "http://planethunters.org"
+      jsonFile = @subject.selected_light_curve.location.replace("http://www.planethunters.org/", "https://s3.amazonaws.com/zooniverse-static/planethunters.org/")
+    else
+      jsonFile = @subject.selected_light_curve.location
+      console.log jsonFile
+
+
+    jsonFile = 'offline/simulation_feedback_example.json'
     # console.log 'jsonFile: ', jsonFile

     # handle ui elements
@@ -557,7 +565,7 @@
     @sim_count ||= 0
     @sim_count +=1

-    if @sim_count%10 == 0
+    if @sim_count%2 == 0
       Subject.group = "5417014b3ae7400bda000002"
       Subject.fetch 1, (subjects) =>
         console.log "got sim subjects ", subjects


fix hidden popovers in tasks overview

fix hidden popovers in tasks overview

--- app/assets/javascripts/admin/views/task/task_overview_view.coffee
+++ app/assets/javascripts/admin/views/task/task_overview_view.coffee
@@ -38,7 +38,8 @@
             title: user.name,
             html: true,
             trigger: "hover",
-            content: user.tooltip
+            content: user.tooltip,
+            container: 'body'
           )

         #reset some attributes before invoking panZoom plugin


Less lodash, more native

Less lodash, more native

--- resources/assets/coffee/react/beatmap-discussions/main.coffee
+++ resources/assets/coffee/react/beatmap-discussions/main.coffee
@@ -416,7 +416,7 @@

   saveStateToContainer: =>
     # This is only so it can be stored with JSON.stringify.
-    @state.readPostIdsArray = _.toArray(@state.readPostIds)
+    @state.readPostIdsArray = Array.from(@state.readPostIds)
     @props.container.dataset.beatmapsetDiscussionState = JSON.stringify(@state)


fixed typo

fixed typo

--- app/js/models/fact.coffee
+++ app/js/models/fact.coffee
@@ -45,7 +45,7 @@
       click:      => @openFactlinkModal()

     $(@elements)
-      .on('mouseenter', (e)=> @highlight_and_open_balloon(e))
+      .on('mouseenter', (e)=> @highlightAndOpenBalloon(e))
       .on('mouseleave', => @considerStoppingWithHighlighting())
       .on('click', => @openFactlinkModal())
       .on 'inview', (event, isInView, visiblePart) =>


Update zh-HANT.coffee (#5995)

Update zh-HANT.coffee (#5995)

Co-authored-by: Valentin Bryukhanov <53545457af642b0f8712bb2cc004f120ce4436f4@gmail.com>

--- app/locale/zh-HANT.coffee
+++ app/locale/zh-HANT.coffee
@@ -34,7 +34,7 @@
     classroom_in_box_blurb3: "激勵更多的學校來創造出世界一流的電腦科學課程。"
 #    classroom_in_box_blurb4: ""
 #    covid19_banner_blurb: "We are offering free access to our full curriculum to educators and schools affected by school closures."
-#    click_here: "Click here"
+    click_here: "點擊這裡"
     creativity_rigor_title: "創造力與邏輯相遇的地方"
     creativity_rigor_subtitle1: "讓編碼變得有趣並學習到現實世界共通的技能"
     creativity_rigor_blurb1: "學生在玩遊戲時學會輸入真正的 Python 和 JavaScript 代碼，鼓勵反複試驗、批判性思考和創造力。然後讓學生通過在專題課程中開發自己的遊戲和網站，應用他們學到的編碼技能。"
@@ -766,7 +766,7 @@
 #    learning_goals: "Learning Goals"
 #    start: "Start"
 #    vega_character: "Vega Character"
-#    click_to_continue: "Click to Continue"
+    click_to_continue: "點擊繼續"
 #    fill_in_solution: "Fill in solution"

 #  apis:
@@ -1403,8 +1403,8 @@
     beautify: "利用標準格式來美化您的程式碼"
     maximize_editor: "最大化/最小化程式碼編輯器"

-#  cinematic:
-#    click_anywhere_continue: "click anywhere to continue"
+  cinematic:
+    click_anywhere_continue: "點擊任意區域繼續"

   community:
     main_title: "CodeCombat社群"


Kill /chat

Kill /chat

--- app/scripts/routes.coffee
+++ app/scripts/routes.coffee
@@ -91,9 +91,6 @@
       controller: "AccountCtrl"
     )

-    .when '/chat',
-      templateUrl: 'views/chat.html'
-      controller: 'ChatCtrl'
     .otherwise redirectTo: "/"

 ]).run([


/today

/today

--- app/scripts/routes.coffee
+++ app/scripts/routes.coffee
@@ -76,7 +76,15 @@
   "$routeProvider"
   ($routeProvider) ->

-    $routeProvider.when("/:rootId?",
+    $routeProvider
+
+    .when("/today",
+      redirectTo: do () ->
+        d = new Date()
+        "/#{d.getMonth()+1}-#{d.getDate()}-#{d.getFullYear()}"
+    )
+
+    .when("/:rootId?",
       templateUrl: "views/chat.html"
       controller: "ChatCtrl"
     )


texnotes

texnotes

--- chrome/content/zotero-better-bibtex/zotero-better-bibtex.coffee
+++ chrome/content/zotero-better-bibtex/zotero-better-bibtex.coffee
@@ -1088,8 +1088,8 @@

 Zotero.BetterBibTeX.pandoc = new class
   constructor: ->
-#    env = Components.classes["@mozilla.org/process/environment;1"].getService(Components.interfaces.nsIEnvironment)
-#
+    env = Components.classes["@mozilla.org/process/environment;1"].getService(Components.interfaces.nsIEnvironment)
+
 #    if env.exists('PATH')
 #      @searchpath = env.get('PATH').split((if Zotero.isWin then ';' else ':'))
 #    else


payment: implement priceIsVolatile feature on the client

--- client/app/Applications/Dashboard.kdapplication/views/producteditform.coffee
+++ client/app/Applications/Dashboard.kdapplication/views/producteditform.coffee
@@ -2,12 +2,12 @@

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

-    @model = data  if data.planCode
+    model = data  if data.planCode

     options.isRecurOptional ?= yes

     options.callback ?= =>
-      @emit 'SaveRequested', @model, @getProductData()
+      @emit 'SaveRequested', model, @getProductData()

     options.buttons ?=
       Save        :
@@ -70,6 +70,15 @@
           partial     : "/ #{ data.subscriptionType ? 'mo' }"
           cssClass    : 'fr'

+    if options.showPriceIsVolatile
+      options.fields.priceIsVolatile =
+        label         : "Price is volatile"
+        itemClass     : KDOnOffSwitch
+        defaultValue  : data.priceIsVolatile
+        callback      : =>
+          enabled = @inputs.priceIsVolatile.getValue()
+          do @fields.feeAmount[if enabled then 'hide' else 'show']
+
     if options.showOverage
       options.fields.overageEnabled =
         label         : "Overage enabled"
@@ -84,7 +93,9 @@

     super options, data

-  getPlanInfo: (subscriptionType) ->
+    @fields.feeAmount.hide()  if data.priceIsVolatile
+
+  getPlanInfo: (subscriptionType = @inputs.subscriptionType?.getValue()) ->
     feeUnit     : 'months'
     feeInterval : switch subscriptionType
       when 'mo'     then 1
@@ -96,18 +107,29 @@
     subscriptionType: subscriptionType

   getProductData: ->
-    { feeAmount, title, description, subscriptionType: subType } = @inputs
+    do (i = @inputs) =>
+      title           = i.title.getValue()
+      description     = i.description.getValue()
+      overageEnabled  = i.overageEnabled.getValue()
+      soldAlone       = i.soldAlone.getValue()
+      priceIsVolatile = i.priceIsVolatile.getValue()
+      feeAmount       =
+        unless priceIsVolatile
+        then i.feeAmount.getValue() * 100

-    { subscriptionType, feeUnit, feeInterval } = @getPlanInfo subType.getValue()
+      { subscriptionType, feeUnit, feeInterval } = @getPlanInfo()

-    {
-      title             : title.getValue()
-      description       : description.getValue()
-      feeAmount         : feeAmount.getValue() * 100
-      feeUnit
-      feeInterval
-      subscriptionType
-    }
+      {
+        title         : i.title.getValue()
+        description   : i.description.getValue()
+        feeAmount
+        feeUnit
+        feeInterval
+        subscriptionType
+        overageEnabled
+        soldAlone
+        priceIsVolatile
+      }

   handleSubscriptionType: ->
     subscriptionType = @inputs.subscriptionType.getValue()


groups: show default readme

groups: show default readme

--- client/landing/app/Applications/Groups.kdapplication/Views/readmeview.coffee
+++ client/landing/app/Applications/Groups.kdapplication/Views/readmeview.coffee
@@ -85,9 +85,10 @@
       else
         partial =
           if err?.message then err.message
-          else "Access denied! Please join the group."
+          else @getDefaultGroupReadme group.title

-      @readme = readme?.content or partial
+      #SA: is this line being used anywhere, this overrides the logic above
+      #@readme = readme?.content or partial
       @readmeView.updatePartial @utils.applyMarkdown partial
       @highlightCode()
       JView::viewAppended.call @


changing text for new page

changing text for new page

--- src/scripts/modules/workspace/popovers/new/modals/new-media.coffee
+++ src/scripts/modules/workspace/popovers/new/modals/new-media.coffee
@@ -25,7 +25,7 @@
       else
         content = new Page
           title: options.title
-          content: '
Please change this new Page
'
+          content: '
Enter some content here. Format content, and drag and drop elements from the toolbar.
'

       content.save()
       .fail(() -> alert('There was a problem saving. Please try again'))


Add redirect in main route

Add redirect in main route

[#94794346]

--- review_front/app/routes/application.coffee
+++ review_front/app/routes/application.coffee
@@ -4,4 +4,7 @@
   setupController: (controller, model)->
     controller.set('current_user', @store.find('user', 'me'))

+  redirect: ->
+    @transitionTo('projects')
+
 `export default Application`


tweaks

tweaks

Former-commit-id: bf0b2467443f91c5335d0da89b030411a93ba3c6 [formerly d0d687dbc522a2c75e2f026d179c8047762615e5] [formerly cf9ac50644f9be849a048a04e5d073545fd41a9f [formerly 5589e0e338a5278d8164881f53ce4c5086af74a7]] [formerly c565c5bac44e6187367a9b19c8cc116fc38f0446 [formerly 94c0a6721f7ef864d89dc409dd90b3e846d220d4] [formerly e2f4e8cabb2c5e18b65e214aa8d9321697973399 [formerly e2f4e8cabb2c5e18b65e214aa8d9321697973399 [formerly 632ed88d0295b0f927b1e2f4fdfb73ad0a4f9710]]]]
Former-commit-id: 8173b217c668173d02f55b983997b469d44d83c2 [formerly ff4a56ed326bc58a5d4090552db5250ed1c3834e] [formerly a5e5a0873ef748e903792e981f2a261c5ae305b0 [formerly 92c6669ca6744de29cd759b87e434c03840df585]]
Former-commit-id: fe2da14b35916dd9399c84616073a68a1124ed53 [formerly 9b1df0963c571b7a15529e2fee7bb6793ea94625]
Former-commit-id: 5b251a8182e70a67f7c09b6a5b4569b3cd872400
Former-commit-id: 1858b9c89b1e6fc83f811c4c79ae7a8f6a818a3a

--- @client/saas_landing_page.coffee
+++ @client/saas_landing_page.coffee
@@ -739,11 +739,18 @@
             paddingBottom: 15

           """
-          The idea for Consider.it struck one cloudy Seattle morning
-          while Travis sat on the ground outside of a bike shop. He was feeling
-          morose after spending a few dark hours reading hundreds of comments
+          The idea for Consider.it was born on a cloudy Seattle morning
+          while Travis sat on the ground outside of a """
+          A
+            href: 'https://www.google.com/maps/place/Montlake+Bicycle+Shop/@47.639382,-122.302025,3a,75y,284.92h,78.85t/data=!3m4!1e1!3m2!1sqE4cgPSn9t_eCx1xr5HsEQ!2e0!4m2!3m1!1s0x549014c486e2f9c1:0x7b96d3f907c7f742'
+            style: story_link
+            'bike shop'
+
+          """
+          . He was feeling
+          down after spending a few dark hours reading hundreds of comments
           on news articles about the Affordable Care Act. So much talking past
-          one another. So few takeaways. So much effort... wasted.
+          one another. Such wasted effort.
           """

         P
@@ -751,13 +758,12 @@
             paddingBottom: 15

           """
-          The problem is not limited to online comment boards. Email threads
-          involving close colleagues and even face to face conversations with
-          loved ones can easily degenerate. Humanity's ability
-          to listen and learn is ever so fragile, easily broken by poor habits and
-          flawed tools. Travis knew he was no exception to the problem;
-          but that day, at least, Travis was happy to turn his frustration into
-          a blueprint for improvement.
+          Humanity's ability to listen and learn is ever so fragile, easily broken
+          by poor habits and flawed tools. The problem is not limited to online
+          comment boards. Email threads involving close colleagues and even face
+          to face conversations with loved ones can easily degenerate. Travis
+          knew he was no exception to the problem; but that day, at least, Travis
+          was happy to turn his frustration into a blueprint for improvement.
           """

       DIV
@@ -962,7 +968,7 @@
             href: 'https://www.youtube.com/watch?v=RIUD4Ty2ZAE'
             'winning talk'
           """
-           at Social Innovation Fast Pitch. This excellent experience was a sort of
+           at Social Innovation Fast Pitch. This excellent experience was an
           awkward transitionary point in our history: straddling academia and the
           private sector, while representing our non-profit partner in a pitch
           competition.
@@ -1111,7 +1117,7 @@
             paddingBottom: 15

           """
-          While Mike and Travis were wrapping up their academic pursuits, they
+          While wrapping up their academic pursuits, Mike and Travis
           met Kevin Miniter. Kevin had just arrived in Seattle, eager for his next
           adventure after running the campaign for the """
           A


Removed check to give opinion before commenting

--- core/app/backbone/views/evidence/evidence_container_view.coffee
+++ core/app/backbone/views/evidence/evidence_container_view.coffee
@@ -24,24 +24,12 @@
     opinionHelpRegion: '.js-opinion-help-region'
     formRegion: '.js-form-region'

-  initialize: ->
-    @_factVotes = @collection.fact.getVotes()
-    @listenTo @_factVotes, 'change reset add remove', @_updateForm
-
   onRender: ->
     @_addEvidenceFormView = new AddEvidenceFormView collection: @collection
     @formRegion.show @_addEvidenceFormView
     @opinionHelpRegion.show new OpinionHelpView collection: @collection
     @collectionRegion.show new EvidenceCollectionView collection: @collection
     @_updateLoading()
-    @_updateForm()

   _updateLoading: ->
     @ui.loading.toggle @collection.loading()
-
-  _updateForm: ->
-    showForm = @_factVotes.opinion_for_current_user() != 'no_vote'
-
-    @ui.opinionHelpRegion.toggle !showForm
-    @ui.formRegion.toggle showForm
-    @_addEvidenceFormView.focus()


default-apps: Added openFile method to Viewer app.

--- client/app/Applications/Viewer.kdapplication/AppController.coffee
+++ client/app/Applications/Viewer.kdapplication/AppController.coffee
@@ -18,4 +18,8 @@

   open:(path)->

-    @getView().openPath path+    @getView().openPath path
+
+  openFile: (nodeView) ->
+    # TODO: Need to handle file types such as images.
+    @getView().openPath nodeView.path


listen for tasking change events

listen for tasking change events

On the full builder the main component will re-render and
ripple down to the times.  However the mini-editor is mobx
powered and doesn't bind to the store

--- tutor/src/components/task-plan/builder/tasking-date-times.cjsx
+++ tutor/src/components/task-plan/builder/tasking-date-times.cjsx
@@ -7,6 +7,7 @@
 TimeHelper  = require '../../../helpers/time'
 {default: Courses} = require '../../../models/courses-map'
 {TaskingActions, TaskingStore} = require '../../../flux/tasking'
+BindStoreMixin     = require '../../bind-store-mixin'

 Icon = require '../../icon'
 DateTime = require './date-time'
@@ -25,6 +26,12 @@

   getDefaultProps: ->
     bsSizes: { sm: 8, md: 9 }
+
+  mixins: [BindStoreMixin]
+  bindStore: TaskingStore
+  bindEvent: ->
+    type = if @props.period then @props.period.id else 'all'
+    "taskings.#{@props.id}.#{type}.changed"

   getError: ->
     return false unless @refs?.due?.hasValidInputs() and @refs?.open?.hasValidInputs()


Closes #143. Readonly inputs can now be followed using hint markers

--- extension/packages/hints.coffee
+++ extension/packages/hints.coffee
@@ -19,7 +19,7 @@
   "textarea"
   "button"
   "select"
-  "input[not(@type='hidden' or @disabled or @readonly)]"
+  "input[not(@type='hidden' or @disabled)]"
   "embed"
   "object"
 ]


Remove dead code.

Remove dead code.

--- src/router.coffee
+++ src/router.coffee
@@ -11,14 +11,6 @@
             @appRoute /^division\/?(.*?)$/, 'renderDivision'
             @appRoute /^division(\?.*?)$/, 'renderMultipleDivisions'
             @appRoute /^address\/(.*?)$/, 'renderAddress'
-
-        _parseUrlQuery: (path) ->
-            if path.match /\?.*/
-                keyValuePair = /([^=\/&?]+=[^=\/&?]+)/g
-                keyValStrings = path.match keyValuePair
-                _.object _(keyValStrings).map (s) => s.split '='
-            else
-                false

         onPostRouteExecute: ->
         executeRoute: (callback, args, context) ->


Name change. Keeping it as Frisbee.

Name change. Keeping it as Frisbee.

--- src/server.coffee
+++ src/server.coffee
@@ -26,13 +26,13 @@
       @doctype 5
       @html ->
         @head ->
-          @title 'Fling'
+          @title 'Frisbee'
           @js '/jquery.js'
           @js '/socket.io/socket.io.js'
           @js 'client.js'
           @css '/static/css/home.css'
         @body ->
-            @div -> 'Fling'
+            @div -> 'Frisbee'

     app.post "/new", @render (req) ->
         # req.params.id


another test (to see if git commit works ok with source tree)

--- src/server.coffee
+++ src/server.coffee
@@ -1,7 +1,7 @@
 express = require 'express'
 server  = express()

-server.get('/', (req, res) -> res.send('hello 123') )
+server.get('/', (req, res) -> res.send('hello 123 another test') )

 module.exports = server


Timing subtract

Timing subtract

--- src/ThreeBSP.coffee
+++ src/ThreeBSP.coffee
@@ -123,7 +123,7 @@
           geometry.faceVertexUvs[0].push vertUvs

   # CSG Operations
-  subtract: (other) => @options.timer.doTask =>
+  subtract: (other) => @options.timer.doTask => other.withTimer @options.timer, =>
     [us, them] = [@tree.clone(), other.tree.clone()]
     us
       .invert()
@@ -133,7 +133,7 @@
       .invert()
       .clipTo(us)
       .invert()
-    new ThreeBSP us.build(them.allPolygons()).invert(), @matrix
+    new ThreeBSP us.build(them.allPolygons()).invert(), @matrix, @options

   union: (other) =>
     [us, them] = [@tree.clone(), other.tree.clone()]
@@ -263,9 +263,6 @@
     node.front    = @options.timer.doTask => @front?.clone()
     node.back     = @options.timer.doTask => @back?.clone()

-
-
-
   constructor: (polygons, @options={}) ->
     if polygons? and not (polygons instanceof Array)
       @options = polygons


Added unsubscribeAll method and use it in the close method

--- src/pubsub.coffee
+++ src/pubsub.coffee
@@ -123,6 +123,32 @@
         logger.warn message
         reject new error.PubSubError message, null

+  # Unsubscribe from a channel.
+  unsubscribeAll: ->
+    new P (resolve, reject) =>
+      if @sock?
+        seq = @sequence
+        @sequence += 1
+
+        record =
+          seq: seq
+          action: 'unsubscribe'
+
+        @sock.send JSON.stringify(record)
+        .then =>
+          @outstanding.set seq,
+            resolve: resolve
+            reject: reject
+        .catch (error) ->
+          message = "Socket error while unsubscribing from channel:"
+          logger.error message, error
+          reject new error.PubSubError message, error
+
+      else
+        message = "Could not unsubscribe from channel as the socket is currently disconnected."
+        logger.warn message
+        reject new error.PubSubError message, null
+
   # Shutdown the WebSocket for good (prevents subsequent auto-reconnect)
   close: ->
     @autoReconnect = false
@@ -135,13 +161,15 @@
       finally
         @pingerRef = null

-    if @sock?
-      try
-        @sock.close()
-      catch error
-        logger.error "Error while closing WebSocket:", error
-      finally
-        @sock = null
+    @unsubscribeAll()
+    .finally ->
+      if @sock?
+        try
+          @sock.close()
+        catch error
+          logger.error "Error while closing WebSocket:", error
+        finally
+          @sock = null

   # Alias to the close() method
   disconnect: -> @close()


fix 'over-render' due to hover inspections

--- bokehjs/src/coffee/common/selection_manager.coffee
+++ bokehjs/src/coffee/common/selection_manager.coffee
@@ -11,6 +11,8 @@
     super(attrs, options)
     @selectors = {}
     @inspectors = {}
+    @empty = hittest.create_hit_test_result()
+    @last_inspection_was_empty = false

   serializable_in_document: () -> false

@@ -43,6 +45,15 @@
     indices = renderer_view.hit_test(geometry)

     if indices?
+
+      if _.isEqual(indices, @empty)
+        if @last_inspection_was_empty
+          return
+        else
+          @last_inspection_was_empty = true
+      else
+        @last_inspection_was_empty = false
+
       inspector = @_get_inspector(renderer_view)
       inspector.update(indices, true, false, true)


Test to hide artworks section when no artworks

--- apps/artist/test/templates.coffee
+++ apps/artist/test/templates.coffee
@@ -80,3 +80,5 @@
       $navLinks.last().text().should.equal 'Shows'
       $navLinks.text().should.not.containEql 'Works'

+    it 'should not display an artworks section with no artworks', ->
+      $('body').html().should.not.containEql 'artwork-section'


Revise plotframe example to include simplest tooltip

--- plotframe/example.coffee
+++ plotframe/example.coffee
@@ -1,6 +1,6 @@
 dat = [ { "x": -0.99488,"y": -1.0107 },{ "x": 0.0058051,"y": -0.40725 },{ "x": -0.41549,"y": 1.1441 },{ "x": -1.5847,"y": 0.32019 },{ "x": -0.73274,"y": -1.0639 },{ "x": -0.5257,"y": -0.22738 },{ "x": 0.35176,"y": 0.14079 },{ "x":  1.537,"y": -0.21344 },{ "x": 0.78311,"y": -0.046108 },{ "x": 0.62435,"y": 0.67313 } ]

-svgscale = plotframe dat, {height: 250, width: 500, xlab: "x axis", ylab: "y axis"}
+svgscale = plotframe dat, {xlab: "X", ylab: "Y"}

 svgscale.svg.selectAll("circle")
    .data(dat)
@@ -10,5 +10,8 @@
    .attr("cy", (d) -> svgscale.y d.y)
    .attr("r", 5)
    .attr("fill", "slateblue")
-   .on("mouseover", -> d3.select(this).transition().attr("r", 10).attr("fill", "hotpink"))
-   .on("mouseout", -> d3.select(this).transition().attr("r", 5).attr("fill", "slateblue"))
+   .on("mouseover", -> d3.select(this).transition().duration(250).attr("fill", "hotpink"))
+   .on("mouseover.tooltip", (d,i) -> svgscale.svg.append("text").text(i+1).attr("id", "tooltip")
+      .attr("x", svgscale.x(d.x)+10).attr("y", svgscale.y(d.y)).attr("fill","hotpink")
+      .attr("opacity",0).style("font-family", "sans-serif").transition().duration(250).attr("opacity", 1))
+   .on("mouseout", -> d3.select(this).transition().duration(250).attr("fill", "slateblue"); d3.selectAll("#tooltip").transition().duration(250).remove())


PR #424: Addressed PR issues

PR #424: Addressed PR issues

--- src/auditing.coffee
+++ src/auditing.coffee
@@ -19,7 +19,7 @@
     return callback err if err

     if not result?.auditMessage
-      return callback 'Document is not a valid AuditMessage'
+      return callback new Error 'Document is not a valid AuditMessage'

     audit = {}

@@ -57,7 +57,7 @@
     logger.info 'Invalid message received'
     return callback()

-  parseAuditRecordFromXML parsedMsg.message, (err, result) ->
+  parseAuditRecordFromXML parsedMsg.message, (xmlErr, result) ->
     audit = new Audit result

     audit.rawMessage = msg
@@ -66,7 +66,7 @@
     delete audit.syslog.message

     audit.save (saveErr) ->
-      if err or saveErr
-        logger.error "An error occurred while processing the audit entry: #{err}"
+      if saveErr then logger.error "An error occurred while processing the audit entry: #{saveErr}"
+      if xmlErr then logger.info "Failed to parse message as an AuditMessage XML document: #{xmlErr}"

       callback()


Is Isnt

Is Isnt

We want to check if the stdout *isnt* the "everything is okay" message.

--- help/troubleshoot/apache.coffee
+++ help/troubleshoot/apache.coffee
@@ -30,7 +30,7 @@
       out += """
       Apache does not appear to be running
       """
-    else if stdout[0...18] is "Apache2 is running"
+    else if stdout[0...18] isnt "Apache2 is running"
       out += """
       Apache Responsed with an unknown status, there may be a problem.
       Apache Status: #{JSON.stringify stdout}


function names to the imperative mood

function names to the imperative mood

http://en.wikipedia.org/wiki/Imperative_mood

--- src/config.coffee
+++ src/config.coffee
@@ -646,19 +646,19 @@
 # specification.
 Config.addSchemaEnforcers
   'integer':
-    coercion: (keyPath, value, schema) ->
+    coerce: (keyPath, value, schema) ->
       value = parseInt(value)
       throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} cannot be coerced into an int") if isNaN(value) or not isFinite(value)
       value

   'number':
-    coercion: (keyPath, value, schema) ->
+    coerce: (keyPath, value, schema) ->
       value = parseFloat(value)
       throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} cannot be coerced into a number") if isNaN(value) or not isFinite(value)
       value

   'boolean':
-    coercion: (keyPath, value, schema) ->
+    coerce: (keyPath, value, schema) ->
       switch typeof value
         when 'string'
           if value.toLowerCase() is 'true'
@@ -673,7 +673,7 @@
           throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be a boolean or the string 'true' or 'false'")

   'string':
-    coercion: (keyPath, value, schema) ->
+    coerce: (keyPath, value, schema) ->
       switch typeof value
         when 'number', 'string'
           value.toString()
@@ -682,12 +682,12 @@

   'null':
     # null sort of isnt supported. It will just unset in this case
-    coercion: (keyPath, value, schema) ->
+    coerce: (keyPath, value, schema) ->
       throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be null") unless value == null
       value

   'object':
-    coercion: (keyPath, value, schema) ->
+    coerce: (keyPath, value, schema) ->
       throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be an object") unless isPlainObject(value)
       return value unless schema.properties?

@@ -701,7 +701,7 @@
       newValue

   'array':
-    coercion: (keyPath, value, schema) ->
+    coerce: (keyPath, value, schema) ->
       throw new Error("Validation failed at #{keyPath}, #{JSON.stringify(value)} must be an array") unless Array.isArray(value)
       itemSchema = schema.items
       if itemSchema?
@@ -716,7 +716,7 @@
         value

   '*':
-    minimumAndMaximumCoercion: (keyPath, value, schema) ->
+    coerceMinimumAndMaximum: (keyPath, value, schema) ->
       return value unless typeof value is 'number'
       if schema.minimum? and typeof schema.minimum is 'number'
         value = Math.max(value, schema.minimum)
@@ -724,7 +724,7 @@
         value = Math.min(value, schema.maximum)
       value

-    enumValidation: (keyPath, value, schema) ->
+    validateEnum: (keyPath, value, schema) ->
       possibleValues = schema.enum
       return value unless possibleValues? and Array.isArray(possibleValues) and possibleValues.length