Raise coverage (dropped in #35).

Raise coverage (dropped in #35).

--- test/integration/dredd-transactions-test.coffee
+++ test/integration/dredd-transactions-test.coffee
@@ -1,3 +1,6 @@
+
+sinon = require('sinon')
+proxyquire = require('proxyquire').noPreserveCache()

 fixtures = require('../fixtures')
 {assert} = require('../utils')
@@ -155,4 +158,36 @@
       )
     )
   )
+
+  describe('When parser unexpectedly provides just error and no API Elements', ->
+    compilationResult = undefined
+    schema = createCompilationResultSchema(
+      errors: 1
+      warnings: 0
+      transactions: 0
+    )
+    source = '... dummy API description document ...'
+    message = '... dummy error message ...'
+
+    beforeEach((done) ->
+      dt = proxyquire('../../src/dredd-transactions',
+        './parse': (input, callback) ->
+          callback(new Error(message))
+      )
+      dt.compile(source, null, (args...) ->
+        [err, compilationResult] = args
+        done(err)
+      )
+    )
+
+    it('produces one error, no warnings, no transactions', ->
+      assert.jsonSchema(compilationResult, schema)
+    )
+    it('turns the parser error into a valid annotation', ->
+      assert.include(
+        JSON.stringify(compilationResult.errors),
+        message
+      )
+    )
+  )
 )


Disable unessary fields on push settings

--- packages/rocketchat-lib/server/startup/settings.coffee
+++ packages/rocketchat-lib/server/startup/settings.coffee
@@ -196,12 +196,12 @@

 RocketChat.settings.addGroup 'Push', ->
-	@add 'Push_debug', false, { type: 'boolean', public: true }
 	@add 'Push_enable', true, { type: 'boolean', public: true }
-	@add 'Push_enable_gateway', true, { type: 'boolean' }
-	@add 'Push_gateway', 'https://gateway.rocket.chat', { type: 'string' }
-	@add 'Push_production', true, { type: 'boolean', public: true }
-	@add 'Push_test_push', 'push_test', { type: 'action', actionText: 'Send_a_test_push_to_my_user' }
+	@add 'Push_debug', false, { type: 'boolean', public: true, enableQuery: { _id: 'Push_enable', value: true } }
+	@add 'Push_enable_gateway', true, { type: 'boolean', enableQuery: { _id: 'Push_enable', value: true } }
+	@add 'Push_gateway', 'https://gateway.rocket.chat', { type: 'string', enableQuery: [{ _id: 'Push_enable', value: true }, { _id: 'Push_enable_gateway', value: true }] }
+	@add 'Push_production', true, { type: 'boolean', public: true, enableQuery: [{ _id: 'Push_enable', value: true }, { _id: 'Push_enable_gateway', value: false }] }
+	@add 'Push_test_push', 'push_test', { type: 'action', actionText: 'Send_a_test_push_to_my_user', enableQuery: { _id: 'Push_enable', value: true } }

 	@section 'Certificates_and_Keys', ->
 		@add 'Push_apn_passphrase', '', { type: 'string' }


Analytics: Tune down a few log messages

Analytics: Tune down a few log messages

--- src/streammachine/master/analytics.coffee
+++ src/streammachine/master/analytics.coffee
@@ -164,7 +164,6 @@
         if @redis
             # use redis stash
             key = "duration-#{session}"
-            console.log "Adding #{duration} to #{key}"
             @redis.incrby key, Math.round(duration), (err,res) =>
                 cb err, res

@@ -240,7 +239,7 @@
     #----------

     _finalizeSession: (id,cb) ->
-        @log.debug "Finalizing session for #{ id }"
+        @log.silly "Finalizing session for #{ id }"

         # This is a little ugly. We need to take several steps:
         # 1) Have we ever finalized this session id?
@@ -263,9 +262,8 @@
                     return cb err

                 if !start
-                    err = "Failed to query session start for #{id}."
-                    @log.error err
-                    return cb err
+                    @log.debug "Attempt to finalize invalid session. No start event for #{id}."
+                    return cb null, false

                 @_selectListenTotals id, ts, (err,totals) =>
                     if err


Fix for optional argument cb in standalone mode

--- src/streammachine/modes/standalone.coffee
+++ src/streammachine/modes/standalone.coffee
@@ -61,7 +61,7 @@

         @log.debug "Standalone is listening on port #{@opts.port}"

-        cb null, @
+        cb? null, @

     #----------


don't override _content if defined as class method

--- modules/gui/lib/ViewContext.coffee
+++ modules/gui/lib/ViewContext.coffee
@@ -31,7 +31,7 @@
             if config.widget
                 @_widget = floyd.tools.gui.ck config.widget

-            if typeof (@_content = config.data.content || config.content) is 'function' && !config.data.raw
+            if !@_content && typeof (@_content = config.data.content || config.content) is 'function' && !config.data.raw
                 @_content = floyd.tools.gui.ck @_content

             return config
@@ -272,5 +272,33 @@
             fn null, floyd.tools.objects.clone item,
                 __data: @data

-
-             +
+        ##
+        ##
+        ##
+        _getBackend: (fn)->
+            return fn(null, @__BACKEND) if @__BACKEND
+
+            @lookup @data.find('backend', @data.find('origin')), @identity, (err, ctx)=>
+                return fn(err) if err
+
+                fn null, @__BACKEND = ctx
+
+        ##
+        ##
+        ##
+        _getOrigin: (fn)->
+            return fn(null, @__ORIGIN) if @__ORIGIN
+
+            @lookup @data.find('origin'), @identity, (err, ctx)=>
+                return fn(err) if err
+
+                fn null, @__ORIGIN = ctx
+
+        ##
+        ##
+        ##
+        _href: (href)->
+
+            encodeURI @data.find('hrefBase', '/')+href
+


Add in null check

Add in null check

--- services/real-time/app/coffee/Router.coffee
+++ services/real-time/app/coffee/Router.coffee
@@ -21,5 +21,5 @@
 				return

 			client.on "joinProject", (data = {}, callback) ->
-				WebsocketController.joinProject(client, user, data.project_id, callback)
+				WebsocketController.joinProject(client, user, data?.project_id, callback)


added test cases for amazon shipments

added test cases for amazon shipments

--- test/guessCarrier.coffee
+++ test/guessCarrier.coffee
@@ -80,3 +80,9 @@

     it 'detects a ups mail innovations number with spaces', ->
       expect(guessCarrier '92 7489 9999 7295 5131 2303 4457').to.include 'usps'
+
+
+  describe 'for amazon shipments', ->
+
+    it 'detects an amazon order id + shipment id combo', ->
+      expect(guessCarrier '110-4970488-4173016:2879726997123').to.include 'amazon'


fixed reply count

fixed reply count

--- html-app/app/scripts/controllers/topics.coffee
+++ html-app/app/scripts/controllers/topics.coffee
@@ -14,4 +14,4 @@
     switch postCount
       when 1 then "no replies"
       when 2 then "1 reply"
-      else "#{postCount} replies"+      else "#{postCount - 1} replies"


Tests: Helpers: CollaborationHelpers: Make assertion optional.

--- client/test/lib/helpers/collaborationhelpers.coffee
+++ client/test/lib/helpers/collaborationhelpers.coffee
@@ -40,7 +40,8 @@
         .waitForElementVisible  '.status-bar a.share.active', 20000 # Assertion

-  endSessionFromStatusBar: (browser) ->
+
+  endSessionFromStatusBar: (browser, shouldAssert = yes) ->

     statusBarSelector       = '.status-bar .collab-status'
     buttonContainerSelector = statusBarSelector + ' .button-container'
@@ -52,7 +53,7 @@
       .waitForElementVisible  buttonContainerSelector, 20000
       .click                  buttonContainerSelector + ' button.end-session'

-    @endSessionModal(browser)
+    @endSessionModal(browser, shouldAssert)

   endSessionFromChat: (browser) ->
@@ -66,7 +67,7 @@
     @endSessionModal(browser)

-  endSessionModal: (browser) ->
+  endSessionModal: (browser, shouldAssert = yes) ->

     buttonsSelector = '.kdmodal .kdmodal-buttons'

@@ -74,7 +75,10 @@
       .waitForElementVisible  '.with-buttons', 20000
       .waitForElementVisible  buttonsSelector, 20000
       .click                  buttonsSelector + ' button.green'
-      .waitForElementVisible  notStartedButtonSelector, 20000 # Assertion
+      .pause                  5000
+
+    if shouldAssert
+      browser.waitForElementVisible  notStartedButtonSelector, 20000 # Assertion

   openChatSettingsMenu: (browser) ->


add test for forms after redirect

add test for forms after redirect

--- test/history_test.coffee
+++ test/history_test.coffee
@@ -35,6 +35,15 @@

     brains.get "/assets/foo.js", (req, res)->
       res.send """window.host = "#{req.headers["host"]}"; """
+
+    brains.get "/history/form_redirect", (req, res)->
+      res.redirect "/history/form?qsval=1"
+
+    brains.get "/history/form", (req, res)->
+      res.send """<form method="post" action="/history/submit?qsval=2"><input type="submit", id="submitbtn"></input></form>"""
+
+    brains.post "/history/submit", (req, res)->
+      res.send "<title>#{req.headers["referer"]}</title>"

     browser = new Browser()
     brains.ready done
@@ -392,5 +401,31 @@
       assert.equal browser.evaluate('window.host'), "localhost:3003"

+  describe "HTML form", ->
+    before (done)->
+      browser.visit "http://localhost:3003/history/form?qsval=1", done
+
+    describe "submit", ->
+      before (done)->
+        browser.pressButton '#submitbtn', done
+
+      it "should point to first page", ->
+        browser.assert.text "title", "http://localhost:3003/history/form?qsval=1"
+        assert.equal ('' + browser.location), "http://localhost:3003/history/submit?qsval=2"
+
+
+  describe "HTML form after redirect", ->
+    before (done)->
+      browser.visit "http://localhost:3003/history/form_redirect", done
+
+    describe "submit", ->
+      before (done)->
+        browser.pressButton '#submitbtn', done
+
+      it "should point to first page", ->
+        browser.assert.text "title", "http://localhost:3003/history/form?qsval=1"
+        assert.equal browser.location.href, "http://localhost:3003/history/submit?qsval=2"
+
+
   after ->
     browser.destroy()


Check whether the hash is set, instead of checking the config

--- app.coffee
+++ app.coffee
@@ -480,7 +480,7 @@

 				writer.writeAttribute 'accessible', if (isAccessible username, version[0].package, version[0].version) then "true" else "false"
 				writer.writeAttribute 'critical', if (/pl/i.test version[0].version) then "true" else "false"
-				writer.writeComment "sha256:#{version[1].toString 'hex'}" if config.enableHash
+				writer.writeComment "sha256:#{version[1].toString 'hex'}" if version[1]?

 				# write <fromversions>
 				if version[0].fromversions?.length


On production, dump errors into console

On production, dump errors into console

--- app.coffee
+++ app.coffee
@@ -43,8 +43,10 @@

 # production error handler
 # no stacktraces leaked to user
+# but it is printed into console
 app.use (err, req, res, next) ->
-    res.status(err.status or 500)
+    console.error 'PROTECTED_S3_ERROR Uncaught error "#{err?.message}": ', err
+    res.status err.status or 500
     res.render 'error',
         message: err.message,
         error: {}


Storing incomplete work on #28

Storing incomplete work on #28

Note: does not yet work in every situation

--- annotran/static/scripts/annotator/sidebar.coffee
+++ annotran/static/scripts/annotator/sidebar.coffee
@@ -181,6 +181,7 @@
       .addClass('h-icon-chevron-left')

   checkChildren: (eleToCheck, elementsClaimed) ->
+    elementsClaimed.push(eleToCheck)
     for ele in eleToCheck.childNodes
       elementsClaimed.push(ele)
       this.checkChildren(ele, elementsClaimed)
@@ -189,14 +190,17 @@
     if eleToCheck in elementsClaimed
       return true

-    for ele in eleToCheck.childNodes
-      if ele in elementsClaimed
-        return true
-
-      if this.checkChildrenClaimed(ele, elementsClaimed)
-        return true
-
-      return false
+    if eleToCheck != null
+      for ele in eleToCheck.childNodes
+        console.log("Checking child")
+        console.log(ele)
+        if ele in elementsClaimed
+          return true
+
+        if this.checkChildrenClaimed(ele, elementsClaimed)
+          return true
+
+    return false

   createAnnotation: (annotation = {}) ->

@@ -217,6 +221,7 @@

       # convert this to a range in the current document and extract the start and end points
       range = new xpathRange.SerializedRange(packager).normalize(document.body)
+      console.log(range.toRange().getBoundingClientRect())

       start = range.start
       end = range.end
@@ -262,7 +267,7 @@

     isClaimed = false

-    # traverse the DOM stack
+    # traverse the DOM stack looking for matches
     isClaimed = this.checkChildrenClaimed(start, elementsClaimed)

     if start != end and isClaimed == false
@@ -270,16 +275,24 @@

       while nextElement != end
         isClaimed = this.checkChildrenClaimed(nextElement, elementsClaimed)
-        elementsClaimed.push(nextElement)

         if nextElement == null
           nextElement = start.parentNode
           start = nextElement

         if nextElement.nextSibling != null
+          console.log("Next sibling not null")
+          console.log(nextElement.nextSibling)
           nextElement = nextElement.nextSibling
         else
-          nextElement = nextElement.parentNode.nextSibling
+          if nextElement.parentNode != null
+            console.log("Next sibling null")
+            console.log(nextElement.parentNode.nextSibling)
+            nextElement = nextElement.parentNode.nextSibling
+          else
+            break
+
+      console.log(start != end)

     if isClaimed
       console.log("Selection overlaps")


Config for coverage reporting

Config for coverage reporting

--- test/karma.config.coffee
+++ test/karma.config.coffee
@@ -8,17 +8,18 @@
     reporters: ['mocha', 'coverage']

     files: [
-      'test/phantomjs-shims.js'
       'test/all-tests.coffee'
-
     ]

     preprocessors:
-      'src/*': ['webpack', 'coverage']
-      'test/*':  ['webpack']
+      'src/**/*.cjsx': ['webpack', 'coverage']
+      'test/*':  ['webpack', 'coverage']

     coverageReporter:
       type: 'text'
+      # type: 'html' # will create html report in ./coverage directory
+
+

     webpack:
       resolve:


Use absolute download links

Use absolute download links

--- plugins/kubernetes/app/assets/javascripts/kubernetes/components/clusters/setup.coffee
+++ plugins/kubernetes/app/assets/javascripts/kubernetes/components/clusters/setup.coffee
@@ -23,7 +23,7 @@
           for link in bin.links
             ul className: 'content-list', key: link.platform,
               li null,
-                a target: '_blank', href: "#{kubernikusBaseUrl}/#{link.link}", "Download for #{link.platform}"
+                a target: '_blank', href: link.link, "Download for #{link.platform}"

       br null


added sweetalert scripts

added sweetalert scripts

--- app/assets/javascripts/application.js.erb.coffee
+++ app/assets/javascripts/application.js.erb.coffee
@@ -8,6 +8,7 @@
 #= require growl
 #= require cheet
 #= require jquery.guillotine
+#= require sweet-alert
 #= require_tree .

 NProgress.configure


WSKernel: support prompting for input

WSKernel: support prompting for input

--- lib/ws-kernel.coffee
+++ lib/ws-kernel.coffee
@@ -6,6 +6,7 @@
 services = require('./jupyter-js-services-shim')

 Kernel = require './kernel'
+InputView = require './input-view'

 module.exports =
 class WSKernel extends Kernel
@@ -50,6 +51,20 @@
                 stream: 'status'
             onResults?(result)

+        future.onStdin = (message) =>
+            unless message.header.msg_type is 'input_request'
+                return
+
+            prompt = message.content.prompt
+
+            inputView = new InputView prompt, (input) =>
+                @session.kernel.sendInputReply(
+                    value: input
+                )
+
+            inputView.attach()
+
+
     execute: (code, onResults) ->
         @_execute code, onResults, true


not modified via state?

not modified via state?

--- resources/assets/coffee/react/profile-page/main.coffee
+++ resources/assets/coffee/react/profile-page/main.coffee
@@ -40,7 +40,6 @@
       @initialPage = page if page?

       @state =
-        currentMode: props.currentMode
         user: props.user
         userPage:
           html: props.userPage.html
@@ -137,7 +136,7 @@
       el Header,
         user: @state.user
         stats: @state.user.statistics
-        currentMode: @state.currentMode
+        currentMode: @props.currentMode
         withEdit: @props.withEdit
         userAchievements: @props.userAchievements

@@ -158,7 +157,7 @@
                   el ExtraTab,
                     page: m
                     currentPage: @state.currentPage
-                    currentMode: @state.currentMode
+                    currentMode: @props.currentMode

       div
         className: 'user-profile-pages'
@@ -210,7 +209,7 @@
           user: @state.user
           scoresBest: @state.scoresBest
           scoresFirsts: @state.scoresFirsts
-          currentMode: @state.currentMode
+          currentMode: @props.currentMode
           pagination: @state.showMorePagination
         component: TopRanks

@@ -235,7 +234,7 @@
         props:
           achievements: @props.achievements
           userAchievements: @props.userAchievements
-          currentMode: @state.currentMode
+          currentMode: @props.currentMode
           user: @state.user
         component: Medals

@@ -244,7 +243,7 @@
           beatmapPlaycounts: @state.beatmapPlaycounts
           scoresRecent: @state.scoresRecent
           user: @state.user
-          currentMode: @state.currentMode
+          currentMode: @props.currentMode
           pagination: @state.showMorePagination
         component: Historical


Fixed date issue with timezones

Fixed date issue with timezones

--- app/assets/javascripts/due_date_select.js.coffee
+++ app/assets/javascripts/due_date_select.js.coffee
@@ -26,7 +26,9 @@
       addDueDate = ->
         # Create the post date
         value = $("input[name='#{fieldName}']").val()
-        mediumDate = $.datepicker.formatDate('M d, yy', new Date(value))
+        valueSplit = value.split '-'
+        date = new Date(valueSplit[0], parseInt(valueSplit[1]) - 1, valueSplit[2])
+        mediumDate = $.datepicker.formatDate 'M d, yy', date

         data = {}
         data[abilityName] = {}


Fix too many files opening error (ulimit is not needed anymore)

--- builders/Watcher.coffee
+++ builders/Watcher.coffee
@@ -14,8 +14,14 @@
 ProgressBar     = require './node_modules/progress'
 #{parser, uglify}  = require "uglify-js"
 hat             = require "./node_modules/hat"
+async           = require "async"
 # {postProcess}   = require "pistachio-compiler"
 # qfunction      = require 'qfunction'
+
+queue = async.queue((task, callback) ->
+  fs.readFile task.path, task.encoding, (err,data)->
+    callback null, data
+, 100)

 class Watcher extends EventEmitter
   constructor:(filelistPath)->
@@ -184,8 +190,10 @@
           # @writeCache newFile,(err)->
           callback file, newFile
       else
-        # console.log "reading"+file.path
-        fs.readFile file.cachePath,'utf8',(err,data)->
+        queue.push
+          path      : file.cachePath
+          encoding  : 'utf8'
+        , (err, data) ->
           # console.log 'serving from cache',file.cachePath
           file.lastCompile = Date.now()
           file.contents = data
@@ -203,71 +211,44 @@
         console.log err
   compileFile: (file, options, callback)->
     ext = file.path.split(".").pop()
-    newContent = fs.readFileSync file.path, 'utf-8' #,(err,newContent)=>
-    # if err
-    #   console.log err
-    #   throw new Error "Couldn't open #{file.path}"
-    #   process.exit()
-    # else
-    switch ext
-      when "styl"
-        stylus(newContent).set('compress',true).use(nib()).render (err,css)=>
-          unless err
-            file.contents = css
-            writeCacheFile file.path,css
-            callback file
-          else
-            log.info "error with styl file at #{file.path}"
-      when "coffee"
-
-        try
-          file.contentsCs = newContent
-          # if file.section is "Client"
-          #   file.contents = postProcess source:(cs.compile newContent,bare:yes)
-          #   # log.debug file.contents
-          # else
-          file.contents = cs.compile newContent,bare:yes
-          writeCacheFile file.path,file.contents
-
-
-
-          #file.contents = @uglify js:file.contents,mangle:no,noMangleFunctions:yes,squeeze:no #,beautify:beautify
-        catch error
-          errd = yes
-          log.error "#{(error.stack.split "\n")[0]} at: #{file.path}"
-          @emit "CoffeeScript Compile Error",file.path,(error.stack.split "\n")[0]
-
-
-        callback file
-        @emit "coffeeFileContents",file # for sourceCodeAnalyzer.
-      else
-        file.contents = newContent
-        callback file
+
+    queue.push
+      path     : file.path
+      encoding : 'utf8'
+    , (err, newContent) =>
+
+      switch ext
+        when "styl"
+          stylus(newContent).set('compress',true).use(nib()).render (err,css)=>
+            unless err
+              file.contents = css
+              writeCacheFile file.path,css
+              callback file
+            else
+              log.info "error with styl file at #{file.path}"
+        when "coffee"
+          try
+            file.contentsCs = newContent
+            # if file.section is "Client"
+            #   file.contents = postProcess source:(cs.compile newContent,bare:yes)
+            #   # log.debug file.contents
+            # else
+            file.contents = cs.compile newContent,bare:yes
+            writeCacheFile file.path,file.contents
+
+
+
+            #file.contents = @uglify js:file.contents,mangle:no,noMangleFunctions:yes,squeeze:no #,beautify:beautify
+          catch error
+            errd = yes
+            log.error "#{(error.stack.split "\n")[0]} at: #{file.path}"
+            @emit "CoffeeScript Compile Error",file.path,(error.stack.split "\n")[0]
+
+
+          callback file
+          @emit "coffeeFileContents",file # for sourceCodeAnalyzer.
+        else
+          file.contents = newContent
+          callback file

 module.exports  = Watcher
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-


Cleanup spacing a bit

Cleanup spacing a bit

--- src/kissmetrics.coffee
+++ src/kissmetrics.coffee
@@ -1,6 +1,7 @@
 ENV = if typeof exports isnt 'undefined' then 'node' else 'browser'

 https = require 'https' if ENV is 'node'
+

 httpRequest = (args) ->
 	args.port ?= 80
@@ -23,7 +24,6 @@
 			record : 'e'
 			set    : 's'
 			alias  : 'a'
-

 	record: (action, properties = {}) ->
 		properties._n = action
@@ -57,6 +57,7 @@
 			port : @port
 			path : endpoint

+
 if ENV is 'node'
 	exports.KissmetricsClient = KissmetricsClient
 else


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/title_screen.coffee
+++ src/title_screen.coffee
@@ -1,5 +1,5 @@
 ###*
-The Title Screen class
+The Title Screen class sets up a simple

 By default, images are loaded asynchronously. A proxy object is
 returned immediately. Even though it has a draw method it will not


If sunrises aren't defined for the selected year, failover to Suncalc's sunrise.  fixes #36

--- source/javascripts/index/tableFactory.coffee
+++ source/javascripts/index/tableFactory.coffee
@@ -32,7 +32,7 @@
     @hebrewWeek = (new HebrewDate(date.toDate()) for date in @gregorianWeek)
     @zmanimWeek = (new Zmanim(day, window.coordinates) for day in @gregorianWeek)
     @shaharitWeek = for i in [0...(@gregorianWeek.length)]
-      new Shaharit(@hebrewWeek[i], new Sunrise(@gregorianWeek[i]).get(), @zmanimWeek[i].sofZmanKeriatShema())
+      new Shaharit(@hebrewWeek[i], new Sunrise(@gregorianWeek[i]).get() ? @zmanimWeek[i].sunrise(), @zmanimWeek[i].sofZmanKeriatShema())
     @minchaWeek = (@mincha(i) for i in [0...(@gregorianWeek.length)])
   dateOfNextHadlakatNerot: (i) ->
     i++ until @hebrewWeek[i].hasHadlakatNerot()


removed useless semicolon

removed useless semicolon

--- core/app/backbone/factlink/cross_fade_region.coffee
+++ core/app/backbone/factlink/cross_fade_region.coffee
@@ -11,7 +11,7 @@
       @show(newView)

   open: (view) ->
-    @$el.hide();
+    @$el.hide()
     @$el.html view.el
     @$el.fadeIn @fadeTime()


Fixed `FactBaseView`.

Fixed `FactBaseView`.

--- core/app/backbone/views/facts/fact_base_view.coffee
+++ core/app/backbone/views/facts/fact_base_view.coffee
@@ -12,9 +12,7 @@

   initialize: ->
     @bindTo @model, 'change', =>
-      @factWheelRegion.currentView?.render()
       @factBodyRegion.currentView?.render()
-    , @

   wheelView: ->
     wheel = new Wheel(@model.get("fact_base")["fact_wheel"])


updated comments in mercury, and added a license

--- app/assets/javascripts/mercury/mercury.js.coffee
+++ app/assets/javascripts/mercury/mercury.js.coffee
@@ -1,16 +1,29 @@
-# Mercury Editor is a Rails and Coffeescript based WYSIWYG editor.  Mercury
-# Editor utilizes the HTML 5 ContentEditable HTML 5 spec to allow editing
-# sections of a given page (instead of using iframes) and provides an editing
-# experience that's as realistic as possible.  By not using iframes for the
-# editable regions it allows CSS to behave naturally.
+###
+# Mercury Editor is a Coffeescript and jQuery based WYSIWYG editor.  Mercury Editor utilizes the HTML5 ContentEditable
+# spec to allow editing sections of a given page (instead of using iframes) and provides an editing experience that's as
+# realistic as possible.  By not using iframes for editable regions it allows CSS to behave naturally.
 #
-# Mercury Editor was written for the future, and doesn't attempt to support
-# legacy implementations of document editing.
+# Mercury Editor was written for the future, and doesn't attempt to support legacy implementations of document editing.
 #
 # Currently supported browsers are
 #   - Firefox 4+
 #   - Chrome 10+
-#   - Safari 5+#= require_self
+#   - Safari 5+
+#
+# Copyright (c) 2011 Jeremy Jackson
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #
 #= require_self
 #= require ./native_extensions
@@ -36,7 +49,7 @@
 #= require_tree ./dialogs
 #= require_tree ./modals
 #= require ./config
-
+###

 # Mercury static properties and utlity methods
 Mercury = {


More text positioner specs.

More text positioner specs.

--- spec/javascripts/text_positioner_spec.coffee
+++ spec/javascripts/text_positioner_spec.coffee
@@ -36,3 +36,130 @@
           t.bound_top()

           expect(object.target.setTop).not.toHaveBeenCalled()
+
+    describe '#bound_right', ->
+      describe 'when the target is outside the canvas', ->
+        it 'moves the target inside the canvas', ->
+          object = target:
+            setLeft: ->
+            getLeft: ->
+              80
+            getWidth: ->
+              50
+            canvas:
+              width: 100
+
+          t = new Target(object)
+
+          spyOn(object.target, 'setLeft')
+
+          t.bound_right()
+
+          expect(object.target.setLeft).toHaveBeenCalledWith(75)
+
+      describe 'when the target is inside the canvas', ->
+        it 'does not move the target back inside the canvas', ->
+          object = target:
+            setLeft: ->
+            getLeft: ->
+              75
+            getWidth: ->
+              50
+            canvas:
+              width: 100
+
+          t = new Target(object)
+
+          spyOn(object.target, 'setLeft')
+
+          t.bound_right()
+
+          expect(object.target.setLeft).not.toHaveBeenCalled()
+
+    describe '#bound_bottom', ->
+      describe 'when the target is outside the canvas', ->
+        it 'moves the target inside the canvas', ->
+          object = target:
+            setTop: ->
+            getTop: ->
+              45
+            getHeight: ->
+              20
+            canvas:
+              height: 50
+
+          t = new Target(object)
+
+          spyOn(object.target, 'setTop')
+
+          t.bound_bottom()
+
+          expect(object.target.setTop).toHaveBeenCalledWith(40)
+
+      describe 'when the target is inside the canvas', ->
+        it 'does not move the target back inside the canvas', ->
+          object = target:
+            setTop: ->
+            getTop: ->
+              70
+            getHeight: ->
+              20
+            canvas:
+              height: 80
+
+          t = new Target(object)
+
+          spyOn(object.target, 'setTop')
+
+          t.bound_top()
+
+          expect(object.target.setTop).not.toHaveBeenCalled()
+
+  describe '#bound_left', ->
+    describe 'when the target is outside the canvas', ->
+      it 'moves the target inside the canvas', ->
+        object = target:
+          setLeft: ->
+          getLeft: ->
+            10
+          getWidth: ->
+            30
+
+        t = new Target(object)
+
+        spyOn(object.target, 'setLeft')
+
+        t.bound_left()
+
+        expect(object.target.setLeft).toHaveBeenCalledWith(15)
+
+    describe 'when the target is inside the canvas', ->
+      it 'does not move the target back inside the canvas', ->
+        object = target:
+          setLeft: ->
+          getLeft: ->
+            10
+          getWidth: ->
+            20
+
+        t = new Target(object)
+
+        spyOn(object.target, 'setLeft')
+
+        t.bound_left()
+
+        expect(object.target.setLeft).not.toHaveBeenCalled()
+
+    describe '#bound_scale_x', ->
+
+    describe '#bound_scale_y', ->
+
+    describe '#left_pct', ->
+
+    describe '#top_pct', ->
+
+    describe '#width_pct', ->
+
+    describe '#height_pct', ->
+
+    describe '#fire', ->


Simplified, now that null and undefined are discarded.

--- Heap.coffee
+++ Heap.coffee
@@ -7,13 +7,12 @@
 class Heap
     constructor: (dataToHeapify = []) ->
         ###
-        Pass an optional array to be heapified.
+        Pass an optional array to be heapified. Takes O(n) time.
         ###
-        @_data = dataToHeapify
         # Use 1-indexed array. Simpler for calculating parent, leftChild and
-        # rightChild. Item 0 is null.
-        @_data.push @_data[0]
-        @_data[0] = null
+        # rightChild. Item 0 is a placeholder.
+        @_data = [undefined]
+        @_data.push item for item in dataToHeapify when item? # Love CoffeScript.
         if @_data.length > 1 then @_upHeap i for i in [2...@_data.length]

     add: (value) ->
@@ -49,30 +48,24 @@

     _upHeap: (index) ->
         valueHolder = @_data[index];
-        # Make undefined and null values stay at bottom.
-        if not @_data[index]? then @_data[index] = Infinity
-        while (@_data[index] < @_data[_parent index] or not @_data[_parent index]?) and index > 1
-            [@_data[index], @_data[_parent index]] = [@_data[_parent index], @_data[index]]
+        while @_data[index] < @_data[_parent index] and index > 1
+            [@_data[index], @_data[_parent index]] =
+            [@_data[_parent index], @_data[index]]
             index = _parent index
-        @_data[index] = valueHolder

     _downHeap: ->
         currentIndex = 1
-        valueHolder = @_data[1]
-        # Trickle down undefined and null values.
-        if not @_data[1]? then @_data[1] = Infinity
         while _leftChild currentIndex < @_data.length # There's a left child.
-            smallerChild = _leftChild currentIndex
-            if smallerChild < @_data.length - 1 # There's a right child.
-                # Choose right child if it's smaller or if left child is of
-                # value undefined/null.
-                if @_data[_rightChild currentIndex] < @_data[smallerChild] or not @_data[smallerChild]?
-                    smallerChild = _rightChild currentIndex
-            if @_data[smallerChild] < @_data[currentIndex]
-                [@_data[smallerChild], @_data[currentIndex]] = [@_data[currentIndex], @_data[smallerChild]]
-                currentIndex = smallerChild
+            smallerChildIndex = _leftChild currentIndex
+            if smallerChildIndex < @_data.length - 1 # There's a right child.
+                # Choose right child if it's smaller.
+                if @_data[_rightChild currentIndex] < @_data[smallerChildIndex]
+                    smallerChildIndex = _rightChild currentIndex
+            if @_data[smallerChildIndex] < @_data[currentIndex]
+                [@_data[smallerChildIndex], @_data[currentIndex]] =
+                [@_data[currentIndex], @_data[smallerChildIndex]]
+                currentIndex = smallerChildIndex
             else
-                @_data[currentIndex] = valueHolder
                 break

 _parent = (index) -> index >> 1 # Fast divide by 2 then flooring.


fix(prefs): Focus main window when open prefs and prevent dupe sheets

- Fixes #498
- Fixes #484

--- internal_packages/preferences/lib/main.cjsx
+++ internal_packages/preferences/lib/main.cjsx
@@ -2,11 +2,11 @@
  Actions,
  WorkspaceStore,
  ComponentRegistry} = require 'nylas-exports'
+{ipcRenderer} = require 'electron'

 module.exports =

   activate: ->
-    {ipcRenderer} = require 'electron'
     React = require 'react'

     Cfg = PreferencesSectionStore.SectionConfig
@@ -45,7 +45,9 @@
     ipcRenderer.on 'open-preferences', => @_openPreferences()

   _openPreferences: ->
-    Actions.pushSheet(WorkspaceStore.Sheet.Preferences)
+    ipcRenderer.send 'command', 'application:show-main-window'
+    if WorkspaceStore.topSheet() isnt WorkspaceStore.Sheet.Preferences
+      Actions.pushSheet(WorkspaceStore.Sheet.Preferences)

   deactivate: ->


Enable LiveReload in watch task.

Enable LiveReload in watch task.

--- src/lib/gruntfile.coffee
+++ src/lib/gruntfile.coffee
@@ -44,7 +44,7 @@
 	if @hasSection 'watch'
 		# TODO: check duplicates
 		subsection = @toCoffee subsection, level=3
-		@gf = @gf.replace /^\t\twatch:$/m, "\t\twatch:\n#{subsection}"
+		@gf = @gf.replace /^\t\twatch:$/m, "\t\twatch:\n\t\t\toptions:\n\t\t\t\tlivereload:true\n#{subsection}"
 	else
 		@addSection 'watch', subsection


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/level_state.coffee
+++ src/level_state.coffee
@@ -5,7 +5,7 @@
   self = GameState(I)

   self.bind "enter", ->
-    # TODO: Adu
+    # TODO: Adjustable Fad
     engine.camera().fadeIn 10

     engine.loadMap I.level, ->


Adjust delete project info alert

Adjust delete project info alert

--- src/smc-webapp/project_settings.cjsx
+++ src/smc-webapp/project_settings.cjsx
@@ -544,9 +544,9 @@

     render_expanded_delete_info : ->
         <Well>
-            <Alert bsStyle="info" style={padding:'8px', marginTop:'4px'} >
-                All of your upgrades from this project will be removed automatically. Undeleting the project will not automatically restore them.
-                <br/>
+            <Alert bsStyle="info" style={padding:'8px'} >
+                All of your upgrades from this project will be removed automatically.
+                Undeleting the project will not automatically restore them.
                 This will not affect upgrades other people have applied.
             </Alert>
             <ButtonToolbar style={textAlign:'center'} >


Add spec for download item.

Add spec for download item.

--- spec/api-session-spec.coffee
+++ spec/api-session-spec.coffee
@@ -2,6 +2,7 @@
 remote = require 'remote'
 http   = require 'http'
 path   = require 'path'
+fs     = require 'fs'
 app    = remote.require 'app'
 BrowserWindow = remote.require 'browser-window'

@@ -72,3 +73,52 @@
           quotas: ['persistent'],
         w.webContents.session.clearStorageData options, ->
           w.webContents.send 'getcount'
+
+  describe 'DownloadItem', ->
+    # A 5MB mock pdf.
+    mockPDF = new Buffer(1024*1024*5)
+    contentDisposition = 'inline; filename="mock.pdf"'
+    # TODO(hokein): Change the download directory to spec/fixtures directory.
+    # We have to use the # default download directory due to the broken
+    # session.setDownloadPath API is broken. Once the API is fixed, we can make
+    # this change.
+    defaultDownloadDir = path.join app.getPath('userData'), 'Downloads'
+    downloadFilePath = path.join defaultDownloadDir, "mock.pdf"
+    downloadServer = http.createServer (req, res) ->
+      res.writeHead 200, {
+        'Content-Length': mockPDF.length,
+        'Content-Type': 'application/pdf',
+        'Content-Disposition': contentDisposition
+      }
+      res.end mockPDF
+      downloadServer.close()
+
+    it 'can download successfully', (done) ->
+      downloadServer.listen 0, '127.0.0.1', ->
+        {port} = downloadServer.address()
+        w.loadUrl "#{url}:#{port}"
+        w.webContents.session.setOpenDownloadDialog false
+
+        w.webContents.session.once 'will-download', (e, item, webContents) ->
+          item.on 'done', (e, state) ->
+            assert.equal state, "completed"
+            assert.equal item.getContentDisposition(), contentDisposition
+            assert.equal item.getReceiveBytes(), mockPDF.length
+            assert.equal item.getTotalBytes(), mockPDF.length
+            assert fs.existsSync downloadFilePath
+            fs.unlinkSync downloadFilePath
+            done()
+          assert.equal item.getURL(), "#{url}:#{port}/"
+          assert.equal item.getMimeType(), "application/pdf"
+
+    it 'can cancel download', (done) ->
+      downloadServer.listen 0, '127.0.0.1', ->
+        {port} = downloadServer.address()
+        w.loadUrl "#{url}:#{port}/"
+        w.webContents.session.setOpenDownloadDialog false
+        w.webContents.session.once 'will-download', (e, item, webContents) ->
+          item.pause()
+          item.on 'done', (e, state) ->
+            assert.equal state, "cancelled"
+            done()
+          item.cancel()


guv-update-jobstats: Exit when done

guv-update-jobstats: Exit when done

--- src/updateconfig.coffee
+++ src/updateconfig.coffee
@@ -49,5 +49,6 @@
     transformFile configfile, transform, (err) ->
       throw err if err
       console.log 'Updated', configfile
+      process.exit(0)

 main() if not module.parent


Fix #5: Allow collected nests to renest

Fix #5: Allow collected nests to renest

I made a substantial mistake and didn’t allow collected nests to renest, which is the whole
point of forced renesting. This fixes that, allowing both abandoned nests and collected
nests to retest.

--- src/lib/nesting.coffee
+++ src/lib/nesting.coffee
@@ -62,7 +62,8 @@
       (n) -> n.nestingTime() is Bird.LATE)

   renest: () ->
-    secondNests = @_abandonedNests.filter((n) ->
+    canRenest = @_abandonedNests.concat(@_collectedNests)
+    secondNests = canRenest.filter((n) ->
       Math.random() < ModelParameters.renestingProbability)
     @_activeNests = @_activeNests.concat(secondNests)


Inline beforeEach since there is only one it block

--- spec/text-buffer-spec.coffee
+++ spec/text-buffer-spec.coffee
@@ -1051,18 +1051,13 @@

     describe "when the file is deleted", ->
-      events = []
-      beforeEach ->
-        bufferToDelete.onDidDelete -> events.push true
+      it "notifies all onDidDelete listeners ", ->
         deleteHandler = jasmine.createSpy('deleteHandler')
         bufferToDelete.onDidDelete deleteHandler
         removeSync(filePath)
+
         waitsFor "file to be deleted", ->
-          deleteHandler.callCount > 0
-
-      it "expects onDidDelete to have been called ", ->
-        expect(events).toEqual [true]
-
+          deleteHandler.callCount is 1

     it "resumes watching of the file when it is re-saved", ->
       bufferToDelete.save()


Don't focus specs

Don't focus specs

--- spec/theme-panel-spec.coffee
+++ spec/theme-panel-spec.coffee
@@ -1,7 +1,7 @@
 $ = require 'jquery'
 ThemePanel = require '../lib/theme-panel'

-fdescribe "ThemePanel", ->
+describe "ThemePanel", ->
   panel = null

   beforeEach ->


dont need to find dom node for should hide on day

--- tutor/src/components/course-calendar/month.cjsx
+++ tutor/src/components/course-calendar/month.cjsx
@@ -126,7 +126,6 @@

   shouldHideAddOnDay: (clickEvent) ->
     return if _.isEmpty(@state.activeAddDate)
-    calendar = ReactDOM.findDOMNode(@)
     unless clickEvent.target.classList.contains('rc-Day')
       @hideAddOnDay()
       clickEvent.preventDefault()


TEMP: test canvas number icons.

TEMP: test canvas number icons.

--- src/map-base-view.coffee
+++ src/map-base-view.coffee
@@ -306,15 +306,17 @@
             colors = _(serviceIds).map (val, id) =>
                 app.colorMatcher.serviceRootIdColor id

-            if MARKER_POINT_VARIANT
-                ctor = widgets.PointCanvasClusterIcon
-            else
-                ctor = widgets.CanvasClusterIcon
-            iconOpts = {}
-            if _(markers).find((m) => m?.unit?.collection?.hasReducedPriority())?
-                iconOpts.reducedProminence = true
-            new ctor count, @getIconSize(), colors, null,
-                iconOpts
+            # if MARKER_POINT_VARIANT
+            #     ctor = widgets.PointCanvasClusterIcon
+            # else
+            #     ctor = widgets.CanvasClusterIcon
+            ctor = widgets.NumberCircleCanvasIcon
+            # iconOpts = {}
+            # if _(markers).find((m) => m?.unit?.collection?.hasReducedPriority())?
+            #     iconOpts.reducedProminence = true
+            # new ctor count, @getIconSize(), colors, null,
+            #     iconOpts
+            new ctor Math.floor(100*Math.random()), @getIconSize()

         getFeatureGroup: ->
             featureGroup = L.markerClusterGroup


Unsubscribe from root view when editor is being removed

--- src/extensions/wrap-guide/src/wrap-guide.coffee
+++ src/extensions/wrap-guide/src/wrap-guide.coffee
@@ -30,7 +30,8 @@

     @updateGuide(@editor)
     @editor.on 'editor-path-change', => @updateGuide(@editor)
-    @rootView.on 'font-size-change', => @updateGuide(@editor)
+    @rootView.on 'font-size-change.wrap-guide', => @updateGuide(@editor)
+    @editor.on 'before-remove', => @rootView.off('.wrap-guide')

   updateGuide: (editor) ->
     column = @getGuideColumn(editor.getPath(), @defaultColumn)


relax image on load testing

relax image on load testing

--- test/components/tutor-popover.spec.coffee
+++ test/components/tutor-popover.spec.coffee
@@ -134,7 +134,10 @@
         expect(popper.updateOverlayPosition).to.have.been.calledOnce

         image = overlayDOM.getElementsByTagName('img')[0]
-        image.onload()
+        if image.onload?
+          image.onload()
+        else
+          overlay.imageLoaded()

         expect(overlay.state.firstShow).to.be.false
         expect(overlay.state.imageLoading).to.be.false


fixing scope and updating quesions

fixing scope and updating quesions

--- src/toaster/generators/config.coffee
+++ src/toaster/generators/config.coffee
@@ -2,8 +2,7 @@

 class Config extends Question

-	tpl = """modules =
-				\tname: '%name'
+	tpl : """module '%name'
 				\tsrc: '%src'
 				\trelease: '%release'

@@ -21,9 +20,9 @@

 		default_name = @basepath.split( "/" ).pop()

-		question1 = "\tWhat's your app name? (#{default_name})"
+		question1 = "\tWhat's your module name? (#{default_name})"
 		question2 = "\tWhere's its src folder? (i.e. src)"
-		question3 = "\tWhere do you want your release file?" +
+		question3 = "\tWhere do you want your release file? " +
 					"(i.e. release/app.js)"

 		@ask question1, /.*/, (name)=>


protection for empty tabs

protection for empty tabs

--- @client/shared.coffee
+++ @client/shared.coffee
@@ -279,8 +279,8 @@
     for cluster, index in all_clusters or []
       cluster_key = "list/#{cluster.name}"

-      fails_filter = homepage_tabs.filter? && (homepage_tabs.clusters != '*' && !(cluster.name in homepage_tabs.clusters) )
-      if fails_filter && ('*' in homepage_tabs.clusters)
+      fails_filter = homepage_tabs.filter? && (homepage_tabs.clusters != '*' && !(cluster.name in (homepage_tabs.clusters or [])) )
+      if fails_filter && ('*' in (homepage_tabs.clusters or []))
         in_others = []
         for filter, clusters of customization('homepage_tabs')
           in_others = in_others.concat clusters


Adding basic jira api access

Adding basic jira api access

--- scripts/jira-linkifier.coffee
+++ scripts/jira-linkifier.coffee
@@ -6,6 +6,8 @@
 #
 # Configuration
 #   HUBOT_JIRA_INSTANCE_URL
+#   HUBOT_JIRA_READER_USERNAME
+#   HUBOT_JIRA_READER_PASSWORD
 #
 # Commands:
 #   <mention a JIRA issue> - Get basic information about the issue
@@ -28,7 +30,14 @@
     robot.brain.set 'jira-projects', projects

     robot.hear new Regexp(shortcode + "-([0-9]*)", "i"), (mention) ->
-      mention.send("Issue at: https://jira.brandnetworksinc.com/browse/" + shortcode + "-" + mention.match[1])
+      robot.http(process.env.HUBOT_JIRA_INSTANCE_URL + "/rest/api/2/issue/" + shortcode + "-" + mention.match[1])
+        .get( (err, req) ->
+          req.auth(process.env.HUBOT_JIRA_READER_USERNAME, process.env.HUBOT_JIRA_READER_PASSWORD)
+        ) (err, res, body) ->
+          issue = JSON.parse(body)
+          mention.send(issue.key + ": " + issue.fields.summary + "(" + issue.fields.customfield_10300 + ")")
+
+      # mention.send("Issue at: https://jira.brandnetworksinc.com/browse/" + shortcode + "-" + mention.match[1])

     msg.send "Watching that project for you"


use new graphlet feature

use new graphlet feature

--- client/landing/app/Applications/Activity.kdapplication/ContentDisplays/tutorial.coffee
+++ client/landing/app/Applications/Activity.kdapplication/ContentDisplays/tutorial.coffee
@@ -347,6 +347,8 @@
       title = new KDCustomHTMLView
         tagName: "p"
         cssClass : "title-preview"
+        attributes:
+          title:data.title
         partial: data.title

       @outgoingContainer.addSubView title


Make highlights less talkative

Make highlights less talkative

--- highlights/highlight-filename-from-stdin.coffee
+++ highlights/highlight-filename-from-stdin.coffee
@@ -15,7 +15,7 @@
     name = input.trim()
     process.exit() if name == 'exit'
     file_to_hl = path.resolve(name)
-    console.error "Highlights is reading #{file_to_hl}"
+    process.stderr.write('HL')
     foo = ->
       fs.readFileSync file_to_hl, 'utf8'


engine: add posix tag to sample test

engine: add posix tag to sample test

--- packages/engine/test.sample.coffee
+++ packages/engine/test.sample.coffee
@@ -3,7 +3,8 @@
   scratch: '/tmp/nikita-test-core'
   tags:
     api: true
-    system_execute_arc_chroot: false
+    posix: true
+    system_execute_arc_chroot: false|
   ssh: [
     null
   ,


[grunt] add todo note about missing l10n support in Sass task

--- tasks/grunt-sass.coffee
+++ tasks/grunt-sass.coffee
@@ -18,6 +18,7 @@

           ###*
            * Get specified path from shared Grunt `data.path`
+           * @todo Add proper handling of localized data
            * @param  {array|string} query Query to property in `data.path`, which contains
            *                              needed path, according to https://lodash.com/docs#get
            * @return {string}             Requested path


Not-authed middleware, fixes #361

Not-authed middleware, fixes #361

--- main.coffee
+++ main.coffee
@@ -88,6 +88,12 @@
 	else
 		response.redirect '/login/'

+mustNotBeAuthed = (request, response, next) ->
+	if request.uonline.basicOpts.loggedIn is true
+		response.redirect config.defaultInstanceForUsers
+	else
+		next()
+

 app.use ((request, response) ->
 	# Read basic stuff
@@ -150,11 +156,11 @@
 	quickRender request, response, 'about'

-app.get '/register/', (request, response) ->
+app.get '/register/', mustNotBeAuthed, (request, response) ->
 	quickRender request, response, 'register'

-app.post '/register/', (request, response) ->
+app.post '/register/', mustNotBeAuthed, (request, response) ->
 	options = request.uonline.basicOpts
 	options.instance = 'register'
 	usernameIsValid = lib.validation.usernameIsValid(request.body.user)
@@ -180,11 +186,11 @@
 		response.render 'register', options

-app.get '/login/', (request, response) ->
+app.get '/login/', mustNotBeAuthed, (request, response) ->
 	quickRender request, response, 'login'

-app.post '/login/', (request, response) ->
+app.post '/login/', mustNotBeAuthed, (request, response) ->
 	if lib.user.accessGranted.sync null, dbConnection, request.body.user, request.body.pass
 		sessid = lib.user.createSession.sync null, dbConnection, request.body.user
 		response.cookie 'sessid', sessid
@@ -223,7 +229,7 @@
 	response.render 'profile', options

-app.get '/action/logout', (request, response) ->
+app.get '/action/logout', mustBeAuthed, (request, response) ->
 	# TODO: move sessid to uonline{}
 	lib.user.closeSession dbConnection, request.cookies.sessid, (error, result) ->
 		if error?


fixed typos

fixed typos

--- main.coffee
+++ main.coffee
@@ -516,9 +516,9 @@
             s.send JSON.stringify {type: 'ctfmodification'}
       else console.log msg

-server.listen config.port config.bindto
-proxyServer.listen config.etherpad_port config.bindto
-console.log "listening on port #{config.port} and #{config.etherpad_port}"
+server.listen config.port, config.bindto
+proxyServer.listen config.etherpad_port, config.bindto
+console.log "listening on port #{config.port} and #{config.etherpad_port}, bind to #{config.bindto}"

 filetype = (path,cb = ->) ->
   p = process.spawn 'file', ['-b', path]


fix test

fix test

--- apps/artwork/components/bid/test/template.coffee
+++ apps/artwork/components/bid/test/template.coffee
@@ -54,7 +54,7 @@
       @$('.artwork-auction-bid-form.js-artwork-auction-bid-form').attr('action').should.containEql '/auction/whtney-art-party/bid/skull'

     it 'displays an enabled bid button', ->
-      @$('.auction-avant-garde-black-button').should.not.containEql 'disabled'
+      @$('.auction-avant-garde-black-button').html().should.not.containEql 'disabled'
       @$('.auction-avant-garde-black-button').text().should.equal 'Bid'
     describe 'bid-status-count formatting', ->
       it 'displays singular "1 Bid" for one bid', ->
@@ -92,7 +92,7 @@
         )
         @$ = cheerio.load(@html)
         @$('.artwork-auction-bid-module__bid-status-count').text().should.containEql ', Reserve not met'
-
+
       it 'displays reserve status correctly with no bids - reserve message only', ->
         @artwork.auction.sale_artwork.counts.bidder_positions = 0
         @artwork.auction.sale_artwork.reserve_status = 'reserve_met'


fix format

fix format

--- src/commands/log_modules/message_schema_factory.coffee
+++ src/commands/log_modules/message_schema_factory.coffee
@@ -15,7 +15,7 @@
     messageId : { type : String, index : true }

     # if the text is meaningful and should be display along with medias
-    asText : { type : Boolean, index : true }
+    asText: { type : Boolean, index : true }

     isOnChannel : Boolean
     medias: [{ type: String, ref: mediaCollectionName }]


Adding read-only mode where user cannot pick a date

--- src/ng-quick-date.coffee
+++ src/ng-quick-date.coffee
@@ -31,6 +31,7 @@
       dayAbbreviations: ["Su", "M", "Tu", "W", "Th", "F", "Sa"],
       dateFilter: null
       defaultCalendarDate: null
+      readOnly: false
       parseDateFunction: (str) ->
         seconds = Date.parse(str)
         if isNaN(seconds)
@@ -253,6 +254,8 @@
     scope.toggleCalendar = (show) ->
       if isFinite(show)
         scope.calendarShown = show
+      else if scope.readOnly
+        scope.calendarShown = false
       else
         scope.calendarShown = not scope.calendarShown


Added option to pass in params to event.save method

--- models/event.coffee
+++ models/event.coffee
@@ -42,10 +42,15 @@
       modelKey: 'participants'
       itemClass: Participant

-  save: (callback = null) ->
+  save: (params = {}, callback = null) ->
+    if _.isFunction(params)
+      callback = params
+      params = {}
+
     @connection.request
       method: if @id then 'PUT' else 'POST'
       body: @toJSON()
+      qs: params
       path: if @id then "/n/#{@namespaceId}/events/#{@id}" else "/n/#{@namespaceId}/events"
     .then (json) =>
       @fromJSON(json)


Disable reverse-scan test on hbase 0.96

Disable reverse-scan test on hbase 0.96

--- test/basic_usage.coffee
+++ test/basic_usage.coffee
@@ -558,22 +558,23 @@
 						cb()
 			, done

-		it 'should reverse-scan the table', (done) ->
-			scan = client.getScanner testTable
-			scan.setReversed yes
-
-			async.eachSeries [testRows.length..0], (i, next) ->
-				if i is 0
-					scan.next (err, row) ->
-						assert.notOk err, "scan.next returned an error: #{err}"
-						assert.equal Object.keys(row), 0, "last scan should return empty object"
-						next()
-				else
-					scan.next (err, row) ->
-						assert.notOk err, "scan.next returned an error: #{err}"
-						assert.equal row.row, testRows[i-1].row, "rowKey doesn't match"
-						next()
-			, done
+		if process.env.HBASE_VER isnt "0.96"
+			it 'should reverse-scan the table', (done) ->
+				scan = client.getScanner testTable
+				scan.setReversed yes
+
+				async.eachSeries [testRows.length..0], (i, next) ->
+					if i is 0
+						scan.next (err, row) ->
+							assert.notOk err, "scan.next returned an error: #{err}"
+							assert.equal Object.keys(row), 0, "last scan should return empty object"
+							next()
+					else
+						scan.next (err, row) ->
+							assert.notOk err, "scan.next returned an error: #{err}"
+							assert.equal row.row, testRows[i-1].row, "rowKey doesn't match"
+							next()
+				, done

 		it 'should stop scanning after closing the scanner', (done) ->
 			scan = client.getScanner testTable
@@ -601,22 +602,23 @@
 					assert.equal Object.keys(row), 0, "should return empty object"
 					done()

-		it 'should reverse-scan the table with startRow and stopRow', (done) ->
-			scan = client.getScanner testTable, '4', '99'
-			scan.setReversed yes
-
-			scan.next (err, row) ->
-				assert.notOk err, "scan.next returned an error: #{err}"
-				assert.equal row.row, testRows[2].row, "rowKey doesn't match"
+		if process.env.HBASE_VER isnt "0.96"
+			it 'should reverse-scan the table with startRow and stopRow', (done) ->
+				scan = client.getScanner testTable, '4', '99'
+				scan.setReversed yes

 				scan.next (err, row) ->
 					assert.notOk err, "scan.next returned an error: #{err}"
-					assert.equal row.row, testRows[1].row, "rowKey doesn't match"
+					assert.equal row.row, testRows[2].row, "rowKey doesn't match"

 					scan.next (err, row) ->
 						assert.notOk err, "scan.next returned an error: #{err}"
-						assert.equal Object.keys(row), 0, "should return empty object"
-						done()
+						assert.equal row.row, testRows[1].row, "rowKey doesn't match"
+
+						scan.next (err, row) ->
+							assert.notOk err, "scan.next returned an error: #{err}"
+							assert.equal Object.keys(row), 0, "should return empty object"
+							done()

 		it 'should scan the table with startRow only', (done) ->
 			scan = client.getScanner testTable, '3'


add helpers to display database contents

--- cli.coffee
+++ cli.coffee
@@ -72,6 +72,20 @@

     getPassword unregister

+
+displayDatabase = ->
+    db = require('./backend/db').db
+    db.allDocs include_docs: true, (err, results) ->
+        results.rows.map (row) ->
+            console.log row.doc
+
+displayQuery = (query) ->
+    db = require('./backend/db').db
+    log.info "Query: #{query}"
+    db.query query, (err, results) ->
+        results.rows.map (row) ->
+            console.log "key: #{row.key}"
+            console.log "value #{JSON.stringify row.value}"

 displayConfig = ->
     console.log JSON.stringify config.config, null, 2
@@ -191,6 +205,16 @@
             filesystem.createDirectoryDoc dirPath, ->

 program
+    .command('display-database')
+    .description('Display database content')
+    .action displayDatabase
+
+program
+    .command('display-query <query>')
+    .description('Display database query result')
+    .action displayQuery
+
+program
     .command('display-config')
     .description('Display device configuration and exit')
     .action displayConfig


[DOC] Add documentation src/models/stat.coffee

--- src/models/stat.coffee
+++ src/models/stat.coffee
@@ -15,6 +15,7 @@

 ###

+# Define the stat model in the database.
 ModelDef =
     c_date :
         type    : String


S48785: AllowedValues using CollectionStore: IterationSummaryApp.js.

--- iterationsummary/IterationSummaryAppSpec.coffee
+++ iterationsummary/IterationSummaryAppSpec.coffee
@@ -5,32 +5,11 @@
 ]

 describe 'Rally.apps.iterationsummary.IterationSummaryApp', ->
-
-  beforeEach ->
-    @ajax.whenQuerying('iteration').respondWith([{
-        _refObjectName:"Iteration 3", Name:"Iteration 3", ObjectID:3,
-        StartDate:"2010-07-11T00:00:00.000Z", EndDate:"2010-07-15T23:59:59.000Z"
-      }
-    ], {
-      schema:
-        properties:
-          EndDate:
-            format:
-              tzOffset:0
-    })
-    # @stubDefer()
-
-  afterEach ->
-    @container?.destroy()
-
   helpers
-    _createApp: (initialValues) ->
-      @container = Ext.create('Ext.Container', {
-        renderTo:'testDiv'
-      })
-
+    _getContext: (initialValues) ->
       globalContext = Rally.environment.getContext()
-      context = Ext.create('Rally.app.Context', {
+
+      Ext.create('Rally.app.Context', {
         initialValues:Ext.merge({
           project:globalContext.getProject()
           workspace:globalContext.getWorkspace()
@@ -39,20 +18,38 @@
         }, initialValues)
       })

+    _createApp: (initialValues) ->
+      @container = Ext.create('Ext.Container', {
+        renderTo:'testDiv'
+      })
+
       app = Ext.create('Rally.apps.iterationsummary.IterationSummaryApp', {
-        context:context
+        context: @_getContext(initialValues)
       })

       @container.add(app)
       @waitForComponentReady(app)

     _stubApp: (config) ->
-      @stub(Rally.apps.iterationsummary.IterationSummaryApp.prototype, 'getScheduleStates')
-        .returns(config.scheduleStates || ["Defined", "In-Progress", "Completed", "Accepted"])
+      @stubPromiseFunction(Rally.apps.iterationsummary.IterationSummaryApp.prototype, 'getScheduleStates',
+        (config.scheduleStates || ["Defined", "In-Progress", "Completed", "Accepted"]))
       @stub(Rally.apps.iterationsummary.IterationSummaryApp.prototype, 'getStartDate').returns(config.startDate || new Date())
       @stub(Rally.apps.iterationsummary.IterationSummaryApp.prototype, 'getEndDate').returns(config.endDate || new Date())
-      @stub(Rally.apps.iterationsummary.IterationSummaryApp.prototype, 'getTzOffset').returns(config.tzOffset || 0)
+      @_stubIterationQuery(config.tzOffset || 0)
       @stub(Rally.util.Timebox, 'getToday').returns(config.today || new Date())
+
+    _stubIterationQuery: (tzOffset = 0) ->
+      @ajax.whenQuerying('iteration').respondWith([{
+          _refObjectName:"Iteration 3", Name:"Iteration 3", ObjectID:3,
+          StartDate:"2010-07-11T00:00:00.000Z", EndDate:"2010-07-15T23:59:59.000Z"
+        }
+      ], {
+        schema:
+          properties:
+            EndDate:
+              format:
+                tzOffset: tzOffset * 60
+      })

     _prepareNoneAcceptedData: ->
       @ajax.whenQuerying('userstory').respondWith([{
@@ -674,6 +671,13 @@
                 "Hello Kitty": 1
         }
       ])
+
+  beforeEach ->
+    @_stubIterationQuery()
+    # @stubDefer()
+
+  afterEach ->
+    @container?.destroy()

   it "does not call wsapidatastore if models are unavailable", ->
     @stub(Rally.data.ModelFactory, 'getModels', (options) ->
@@ -683,247 +687,74 @@
           results.Iteration = Rally.test.mock.data.ModelFactory.getModel('Iteration')
         when 'UserStory'
           results.UserStory = Rally.test.mock.data.ModelFactory.getModel('UserStory')
+        when 'AllowedAttributeValue'
+          results.AllowedAttributeValue = Rally.test.mock.data.ModelFactory.getModel('AllowedAttributeValue')

       options.success.call(options.scope, results)
     )
-    aggregateQueryResultsSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_aggregateQueryResults')
+    displayStatusRowsSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_displayStatusRows')

     @_createApp({}).then (app) =>

-      expect(aggregateQueryResultsSpy.callCount).toBe 0
+      expect(displayStatusRowsSpy).not.toHaveBeenCalled()

   it "calls wsapidatastore if models are available", ->
-    aggregateQueryResultsSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_aggregateQueryResults')
+    displayStatusRowsSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_displayStatusRows')

     @_createApp({}).then (app) =>

-      @waitForCallback(aggregateQueryResultsSpy, 4)
-
-  it "calculates # of days for past timebox", ->
-    @_stubApp({
-      startDate:new Date(2011, 4, 22),
-      endDate:new Date(2011, 4, 27, 23, 59, 59),
-      tzOffset:10
-    })
-    @_createApp({
-      workspace:{
-        WorkspaceConfiguration:{
-          WorkDays:['monday', 'tuesday', 'thursday', 'friday'].join(',')
-        }
-      }
-    }).then (app) =>
-
-      expect(app.timeboxLength).toBe 4
-      expect(app.daysRemaining).toBe 0
-
-  it "calculates # of days for future timebox", ->
-
-    @_stubApp({
-      startDate:new Date(2021, 5, 1),
-      endDate:new Date(2021, 5, 7, 23, 59, 59),
-      tzOffset:-5
-    })
-
-    @_createApp({
-      workspace:{
-        WorkspaceConfiguration:{
-          WorkDays:['sunday', 'monday', 'tuesday', 'thursday', 'friday'].join(',')
-        }
-      }
-    }).then (app) =>
-
-      expect(app.timeboxLength).toBe 5
-      expect(app.daysRemaining).toBe 0
-
-  it "calculates # of days for current timebox", ->
-
-    @_stubApp({
-      startDate:new Date(2011, 5, 10),
-      endDate:new Date(2011, 5, 17, 23, 59, 59),
-      tzOffset:-5,
-      today:new Date(2011, 5, 11, 22)
-    })
-
-    @_createApp({
-      workspace:{
-        WorkspaceConfiguration:{
-          WorkDays:['sunday', 'monday', 'tuesday', 'wednesday',
-            'thursday', 'friday', 'saturday'].join(',')
-        }
-      }
-    }).then (app) =>
-
-      expect(app.timeboxLength).toBe 8
-      expect(app.daysRemaining).toBe 7
-
-  it "calculates # of days remaining when start date is today", ->
-
-    @_stubApp({
-      startDate:new Date(2011, 5, 10),
-      endDate:new Date(2011, 5, 17, 23, 59, 59),
-      tzOffset:-5,
-      today:new Date(2011, 5, 10, 22)
-    })
-
-    @_createApp({
-      workspace:{
-        WorkspaceConfiguration:{
-          WorkDays:['sunday', 'monday', 'tuesday', 'wednesday',
-            'thursday', 'friday', 'saturday'].join(',')
-        }
-      }
-    }).then (app) =>
-
-      expect(app.timeboxLength).toBe 8
-      expect(app.daysRemaining).toBe 8
-
-  it "calculates # of days remaining when end date is today", ->
-
-    @_stubApp({
-      startDate:new Date(2011, 5, 10),
-      endDate:new Date(2011, 5, 17, 23, 59, 59),
-      tzOffset:-5,
-      today:new Date(2011, 5, 17, 17, 59)
-    })
-
-    @_createApp({
-      workspace:{
-        WorkspaceConfiguration:{
-          WorkDays:['sunday', 'monday', 'tuesday', 'wednesday',
-            'thursday', 'friday', 'saturday'].join(',')
-        }
-      }
-    }).then (app) =>
-
-      expect(app.timeboxLength).toBe 8
-      expect(app.daysRemaining).toBe 1
-
-  it "+10 timezone offset", ->
-
-    @_stubApp({
-      startDate:new Date(2011, 5, 15),
-      endDate:new Date(2011, 5, 20, 23, 59, 59),
-      tzOffset:10,
-      today:new Date(2011, 5, 18, 9, 25)
-    })
-
-    @_createApp({
-      workspace:{
-        WorkspaceConfiguration:{
-          WorkDays:['sunday', 'monday', 'tuesday', 'wednesday',
-            'thursday', 'friday', 'saturday'].join(',')
-        }
-      }
-    }).then (app) =>
-
-      expect(app.timeboxLength).toBe 6
-      expect(app.daysRemaining).toBe 3
-
-  it "-12 timezone offset", ->
-
-    @_stubApp({
-      startDate:new Date(2011, 5, 15),
-      endDate:new Date(2011, 5, 20, 23, 59, 59),
-      tzOffset:-12,
-      today:new Date(2011, 5, 17, 5, 25)
-    })
-
-    @_createApp({
-      workspace:{
-        WorkspaceConfiguration:{
-          WorkDays:['sunday', 'monday', 'tuesday', 'wednesday',
-            'thursday', 'friday', 'saturday'].join(',')
-        }
-      }
-    }).then (app) =>
-
-      expect(app.timeboxLength).toBe 6
-      expect(app.daysRemaining).toBe 4
-
-  it "-12 timezone offset end of day", ->
-
-    @_stubApp({
-      startDate:new Date(2011, 5, 15),
-      endDate:new Date(2011, 5, 20, 23, 59, 59),
-      tzOffset:-12,
-      today:new Date(2011, 5, 17, 23, 59, 59, 999)
-    })
-
-    @_createApp({
-      workspace:{
-        WorkspaceConfiguration:{
-          WorkDays:['sunday', 'monday', 'tuesday', 'wednesday',
-            'thursday', 'friday', 'saturday'].join(',')
-        }
-      }
-    }).then (app) =>
-
-      expect(app.timeboxLength).toBe 6
-      expect(app.daysRemaining).toBe 4
+      @waitForCallback(displayStatusRowsSpy)

   it "getPostAcceptedState with no before or after state", ->
-
-    @_stubApp({
-      scheduleStates:["Defined", "In-Progress", "Completed", "Accepted"]
-    })
-
+    @ajax.whenQueryingAllowedValues('userstory', 'ScheduleState').respondWith ["Defined", "In-Progress", "Completed", "Accepted"]
     @_createApp({}).then (app) =>
-
-      expect(app._getPostAcceptedState()).toBeNull()
+      app._getPostAcceptedState().always (postAcceptedState) ->
+        expect(postAcceptedState).toBeNull()

   it "getPostAcceptedState with only a before state", ->
-
-    @_stubApp({
-      scheduleStates:["Idea", "Defined", "In-Progress", "Completed", "Accepted"]
-    })
-
+    @ajax.whenQueryingAllowedValues('userstory', 'ScheduleState').respondWith ["Idea", "Defined", "In-Progress", "Completed", "Accepted"]
     @_createApp({}).then (app) =>
-
-      expect(app._getPostAcceptedState()).toBeNull()
+      app._getPostAcceptedState().always (postAcceptedState) ->
+        expect(postAcceptedState).toBeNull()

   it "getPostAcceptedState with only an after state", ->
-
-    @_stubApp({
-      scheduleStates:["Defined", "In-Progress", "Completed", "Accepted", "Released"]
-    })
-
+    @ajax.whenQueryingAllowedValues('userstory', 'ScheduleState').respondWith ["Defined", "In-Progress", "Completed", "Accepted", "Released"]
     @_createApp({}).then (app) =>
-
-      expect(app._getPostAcceptedState()).toBe "Released"
+      app._getPostAcceptedState().always (postAcceptedState) ->
+        expect(postAcceptedState).toBe "Released"

   it "getPostAcceptedState with a before and after state", ->
-
-    @_stubApp({
-      scheduleStates:["Idea", "Defined", "In-Progress", "Completed", "Accepted", "Really Really Done"]
-    })
-
+    @ajax.whenQueryingAllowedValues('userstory', 'ScheduleState').respondWith ["Idea", "Defined", "In-Progress", "Completed", "Accepted", "Really Really Done"]
     @_createApp({}).then (app) =>
-
-      expect(app._getPostAcceptedState()).toBe "Really Really Done"
+      app._getPostAcceptedState().always (postAcceptedState) ->
+        expect(postAcceptedState).toBe "Really Really Done"

   it "does not aggregate testset and defectsuite data for HS subscriptions", ->

     @_prepareFiveDefectsData()

-    @_stubApp(
-      startDate:new Date(2011, 4, 6)
-      endDate:new Date(2011, 4, 20, 23, 59, 59)
-      today:new Date(2011, 5, 16)
-    )
+    # @_stubApp(
+    #   startDate:new Date(2011, 4, 6)
+    #   endDate:new Date(2011, 4, 20, 23, 59, 59)
+    #   today:new Date(2011, 5, 16)
+    # )

     @stub(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_isHsOrTeamEdition').returns true
     testsSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getTestsConfigObject')
     defectSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getDefectsConfigObject')

-    @_createApp({}).then (app) =>
-
-      configDefects = defectSpy.getCall(0).returnValue
+    app = Ext.create('Rally.apps.iterationsummary.IterationSummaryApp',
+      context: @_getContext()
+    )
+    @waitForComponentReady(app).then ->
+
+      configDefects = defectSpy.firstCall.returnValue
       # only the 2 defects from user story - should exclude the 3 from defect suite
       expect(configDefects.title).toBe "2 Active Defects"
       expect(configDefects.status).toBe "error"
       expect(configDefects.message).toBe app.self.PAST_WITH_DEFECTS

-      expect(testsSpy.called).toBeFalsy()
+      expect(testsSpy).not.toHaveBeenCalled()

   it "refreshes app on objectUpdate of artifacts", ->
     @_createApp({}).then (app) =>
@@ -941,33 +772,27 @@

       Rally.environment.getMessageBus().publish(Rally.Message.objectUpdate, Rally.test.mock.ModelObjectMother.getRecord('Release'))

-      expect(addContentSpy.callCount).toBe 0
-
-  it "only gets tzOffset and scheduleStates once", ->
+      expect(addContentSpy).not.toHaveBeenCalled()
+
+  it "only calculates timebox info once", ->
     httpGetSpy = @spy(Rally.env.IoProvider.prototype, 'httpGet')
     @_createApp({}).then (app) =>
-
-      addContentSpy = @spy(app, 'addContent')
-      componentReadyListenter = @stub()
-
-      expect(httpGetSpy.callCount).toBe 1
-
-      modelsSpy = @spy(Rally.data.ModelFactory, 'getModels')
-      modelSpy = @spy(Rally.data.ModelFactory, 'getModel')
-
-      messageBus = Rally.environment.getMessageBus()
-      messageBus.subscribe(Rally.BrowserTest.getComponentReadyMessageName(app), componentReadyListenter)
-      messageBus.publish(Rally.Message.objectUpdate, Rally.test.mock.ModelObjectMother.getRecord('HierarchicalRequirement'))
-      @waitForCallback(componentReadyListenter).then =>
-
-        expect(httpGetSpy.callCount).toBe 1
-        expect(addContentSpy.callCount).toBe 1
-
-        # 8 because there are four artifact types getting loaded, and each
-        # one calls getModel twice, if more than 8, then the getModel call
-        # to get schedule states happened again, meaning the test failed
-        expect(modelsSpy).toHaveBeenCalledOnce()
-        expect(modelSpy).not.toHaveBeenCalled()
+      expect(httpGetSpy).toHaveBeenCalledOnce()
+
+      app.calculateTimeboxInfo().then ->
+        expect(httpGetSpy).toHaveBeenCalledOnce()
+
+  it "only gets scheduleStates once", ->
+    scheduleStates = ['Defined', 'In-Progress', 'Completed']
+    ajaxRequest = @ajax.whenQueryingAllowedValues('userstory', 'ScheduleState').respondWith scheduleStates
+    @_createApp({}).then (app) =>
+      expect(scheduleStates).toEqual scheduleStates
+      expect(ajaxRequest).toHaveBeenCalledOnce()
+
+      ajaxRequest = @ajax.whenQueryingAllowedValues('userstory', 'ScheduleState').respondWith ['Defined', 'In-Progress', 'Accepted']
+      app.getScheduleStates().then (scheduleStates2) ->
+        expect(scheduleStates).toEqual scheduleStates
+        expect(ajaxRequest).not.toHaveBeenCalled()

   it "rounds estimates to two decimal places", ->
     @ajax.whenQuerying('defectsuite').respondWith()
@@ -1051,9 +876,9 @@

       expect(summedPlanEstimate.toString().length).toBeGreaterThan 5

-      configAcceptance = acceptanceSpy.getCall(0).returnValue
-      expectedSubtitle = Ext.String.format("(0 of {0} Points)", Math.round(summedPlanEstimate * 100) / 100)
-      expect(configAcceptance.subtitle).toBe expectedSubtitle
+      acceptanceSpy.firstCall.returnValue.always (configAcceptance) ->
+        expectedSubtitle = Ext.String.format("(0 of {0} Points)", Math.round(summedPlanEstimate * 100) / 100)
+        expect(configAcceptance.subtitle).toBe expectedSubtitle

   describe 'status row', ->

@@ -1072,24 +897,63 @@

       @_createApp({}).then (app) =>

-        configAcceptance = acceptanceSpy.getCall(0).returnValue
-        expect(!!configAcceptance.title).toBeFalsy()
-        expect(!!configAcceptance.status).toBeFalsy()
-        expect(!!configAcceptance.message).toBeFalsy()
-
-        configDefects = defectSpy.getCall(0).returnValue
+        acceptanceSpy.firstCall.returnValue.then (configAcceptance) ->
+          expect(!!configAcceptance.title).toBeFalsy()
+          expect(!!configAcceptance.status).toBeFalsy()
+          expect(!!configAcceptance.message).toBeFalsy()
+
+          configDefects = defectSpy.firstCall.returnValue
+          expect(!!configDefects.title).toBeFalsy()
+          expect(!!configDefects.status).toBeFalsy()
+          expect(!!configDefects.message).toBeFalsy()
+
+          configTests = testSpy.firstCall.returnValue
+          expect(!!configTests.title).toBeFalsy()
+          expect(!!configTests.status).toBeFalsy()
+          expect(!!configTests.message).toBeFalsy()
+
+    it "displays no alarming acceptance stats when timebox has just started", ->
+
+      @_prepareNoneAcceptedData()
+
+      @_stubApp(
+        startDate:new Date(2011, 4, 13)
+        endDate:new Date(2011, 4, 20, 23, 59, 59)
+        today:new Date(2011, 4, 14)
+      )
+
+      acceptanceSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getAcceptanceConfigObject')
+
+      @_createApp({}).then (app) =>
+
+        acceptanceSpy.firstCall.returnValue.always (configAcceptance) ->
+          expect(configAcceptance.title).toBe "0% Accepted"
+          expect(configAcceptance.subtitle).toBe "(0 of 27 Points)"
+          expect(configAcceptance.status).toBe "pending"
+          expect(configAcceptance.message).toBe app.self.CURRENT_WITH_NO_ACCEPTED_WORK
+
+    it "does not display defect stats when no active defects for current timebox", ->
+
+      @_prepareNoActiveDefectsData()
+
+      @_stubApp(
+        startDate:new Date(2011, 4, 13)
+        endDate:new Date(2011, 4, 20, 23, 59, 59)
+        today:new Date(2011, 4, 14)
+      )
+
+      defectSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getDefectsConfigObject')
+
+      @_createApp({}).then (app) =>
+
+        configDefects = defectSpy.firstCall.returnValue
         expect(!!configDefects.title).toBeFalsy()
         expect(!!configDefects.status).toBeFalsy()
         expect(!!configDefects.message).toBeFalsy()

-        configTests = testSpy.getCall(0).returnValue
-        expect(!!configTests.title).toBeFalsy()
-        expect(!!configTests.status).toBeFalsy()
-        expect(!!configTests.message).toBeFalsy()
-
-    it "displays no alarming acceptance stats when timebox has just started", ->
-
-      @_prepareNoneAcceptedData()
+    it "displays defect stats for current timebox", ->
+
+      @_prepareFiveDefectsData()

       @_stubApp(
         startDate:new Date(2011, 4, 13)
@@ -1097,117 +961,135 @@
         today:new Date(2011, 4, 14)
       )

+      defectSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getDefectsConfigObject')
+
+      @_createApp({}).then (app) =>
+
+        configDefects = defectSpy.firstCall.returnValue
+        expect(configDefects.title).toBe "5 Active Defects"
+        expect(configDefects.status).toBe "warn"
+        expect(configDefects.message).toBe app.self.CURRENT_WITH_DEFECTS
+
+    it "displays acceptance warning 5 days into a long timebox", ->
+
+      @_prepareNoneAcceptedData()
+
+      @_stubApp(
+        startDate:new Date(2011, 4, 1)
+        endDate:new Date(2011, 4, 28, 23, 59, 59)
+        today:new Date(2011, 4, 20)
+      )
+
       acceptanceSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getAcceptanceConfigObject')

       @_createApp({}).then (app) =>

-        configAcceptance = acceptanceSpy.getCall(0).returnValue
-        expect(configAcceptance.title).toBe "0% Accepted"
-        expect(configAcceptance.subtitle).toBe "(0 of 27 Points)"
-        expect(configAcceptance.status).toBe "pending"
-        expect(configAcceptance.message).toBe app.self.CURRENT_WITH_NO_ACCEPTED_WORK
-
-    it "does not display defect stats when no active defects for current timebox", ->
-
-      @_prepareNoActiveDefectsData()
+        acceptanceSpy.firstCall.returnValue.always (configAcceptance) ->
+          expect(configAcceptance.title).toBe "0% Accepted"
+          expect(configAcceptance.subtitle).toBe "(0 of 27 Points)"
+          expect(configAcceptance.status).toBe "warn"
+          expect(configAcceptance.message).toBe app.self.CURRENT_WITH_SOME_UNACCEPTED_WORK
+
+    it "displays acceptance pending 5 days into a long timebox", ->
+
+      @_prepareSomeAcceptedData()
+
+      @_stubApp(
+        startDate:new Date(2011, 4, 1)
+        endDate:new Date(2011, 4, 28, 23, 59, 59)
+        today:new Date(2011, 4, 20)
+      )
+
+      acceptanceSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getAcceptanceConfigObject')
+
+      @_createApp({}).then (app) =>
+
+        acceptanceSpy.firstCall.returnValue.always (configAcceptance) ->
+          expect(configAcceptance.title).toBe "48% Accepted"
+          expect(configAcceptance.subtitle).toBe "(13 of 27 Points)"
+          expect(configAcceptance.status).toBe "pending"
+          expect(configAcceptance.message).toBe app.self.CURRENT_WITH_SOME_UNACCEPTED_WORK
+
+    it "displays acceptance pending halfway through a short timebox", ->
+
+      @_prepareSomeAcceptedData()
+
+      @_stubApp(
+        startDate:new Date(2011, 4, 2)
+        endDate:new Date(2011, 4, 6, 23, 59, 59)
+        today:new Date(2011, 4, 5)
+      )
+
+      acceptanceSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getAcceptanceConfigObject')
+
+      @_createApp({}).then (app) =>
+
+        acceptanceSpy.firstCall.returnValue.always (configAcceptance) ->
+          expect(configAcceptance.title).toBe "48% Accepted"
+          expect(configAcceptance.subtitle).toBe "(13 of 27 Points)"
+          expect(configAcceptance.status).toBe "pending"
+          expect(configAcceptance.message).toBe app.self.CURRENT_WITH_SOME_UNACCEPTED_WORK
+
+    it "displays acceptance error when all work not accepted from past timebox", ->
+
+      @_prepareSomeAcceptedData()
+
+      @_stubApp(
+        startDate:new Date(2011, 4, 2)
+        endDate:new Date(2011, 4, 20, 23, 59, 59)
+        today:new Date(2011, 5, 5)
+      )
+
+      acceptanceSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getAcceptanceConfigObject')
+
+      @_createApp({}).then (app) =>
+
+        acceptanceSpy.firstCall.returnValue.always (configAcceptance) ->
+          expect(configAcceptance.title).toBe "48% Accepted"
+          expect(configAcceptance.subtitle).toBe "(13 of 27 Points)"
+          expect(configAcceptance.status).toBe "error"
+          expect(configAcceptance.message).toBe app.self.PAST_WITH_SOME_UNACCEPTED_WORK
+
+    it "displays defect error when active defects remain from past timebox", ->
+
+      @_prepareFiveDefectsData()

       @_stubApp(
         startDate:new Date(2011, 4, 13)
         endDate:new Date(2011, 4, 20, 23, 59, 59)
-        today:new Date(2011, 4, 14)
+        today:new Date(2011, 5, 14)
       )

       defectSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getDefectsConfigObject')

       @_createApp({}).then (app) =>

-        configDefects = defectSpy.getCall(0).returnValue
+        configDefects = defectSpy.firstCall.returnValue
+        expect(configDefects.title).toBe "5 Active Defects"
+        expect(configDefects.status).toBe "error"
+        expect(configDefects.message).toBe app.self.PAST_WITH_DEFECTS
+
+    it "does not display defect stats when no active defects for past timebox", ->
+
+      @_prepareNoActiveDefectsData()
+
+      @_stubApp(
+        startDate:new Date(2011, 4, 13)
+        endDate:new Date(2011, 4, 20, 23, 59, 59)
+        today:new Date(2011, 5, 14)
+      )
+
+      defectSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getDefectsConfigObject')
+
+      @_createApp({}).then (app) =>
+
+        configDefects = defectSpy.firstCall.returnValue
         expect(!!configDefects.title).toBeFalsy()
         expect(!!configDefects.status).toBeFalsy()
         expect(!!configDefects.message).toBeFalsy()

-    it "displays defect stats for current timebox", ->
-
-      @_prepareFiveDefectsData()
-
-      @_stubApp(
-        startDate:new Date(2011, 4, 13)
-        endDate:new Date(2011, 4, 20, 23, 59, 59)
-        today:new Date(2011, 4, 14)
-      )
-
-      defectSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getDefectsConfigObject')
-
-      @_createApp({}).then (app) =>
-
-        configDefects = defectSpy.getCall(0).returnValue
-        expect(configDefects.title).toBe "5 Active Defects"
-        expect(configDefects.status).toBe "warn"
-        expect(configDefects.message).toBe app.self.CURRENT_WITH_DEFECTS
-
-    it "displays acceptance warning 5 days into a long timebox", ->
-
-      @_prepareNoneAcceptedData()
-
-      @_stubApp(
-        startDate:new Date(2011, 4, 1)
-        endDate:new Date(2011, 4, 28, 23, 59, 59)
-        today:new Date(2011, 4, 20)
-      )
-
-      acceptanceSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getAcceptanceConfigObject')
-
-      @_createApp({}).then (app) =>
-
-        configAcceptance = acceptanceSpy.getCall(0).returnValue
-        expect(configAcceptance.title).toBe "0% Accepted"
-        expect(configAcceptance.subtitle).toBe "(0 of 27 Points)"
-        expect(configAcceptance.status).toBe "warn"
-        expect(configAcceptance.message).toBe app.self.CURRENT_WITH_SOME_UNACCEPTED_WORK
-
-    it "displays acceptance pending 5 days into a long timebox", ->
-
-      @_prepareSomeAcceptedData()
-
-      @_stubApp(
-        startDate:new Date(2011, 4, 1)
-        endDate:new Date(2011, 4, 28, 23, 59, 59)
-        today:new Date(2011, 4, 20)
-      )
-
-      acceptanceSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getAcceptanceConfigObject')
-
-      @_createApp({}).then (app) =>
-
-        configAcceptance = acceptanceSpy.getCall(0).returnValue
-        expect(configAcceptance.title).toBe "48% Accepted"
-        expect(configAcceptance.subtitle).toBe "(13 of 27 Points)"
-        expect(configAcceptance.status).toBe "pending"
-        expect(configAcceptance.message).toBe app.self.CURRENT_WITH_SOME_UNACCEPTED_WORK
-
-    it "displays acceptance pending halfway through a short timebox", ->
-
-      @_prepareSomeAcceptedData()
-
-      @_stubApp(
-        startDate:new Date(2011, 4, 2)
-        endDate:new Date(2011, 4, 6, 23, 59, 59)
-        today:new Date(2011, 4, 5)
-      )
-
-      acceptanceSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getAcceptanceConfigObject')
-
-      @_createApp({}).then (app) =>
-
-        configAcceptance = acceptanceSpy.getCall(0).returnValue
-        expect(configAcceptance.title).toBe "48% Accepted"
-        expect(configAcceptance.subtitle).toBe "(13 of 27 Points)"
-        expect(configAcceptance.status).toBe "pending"
-        expect(configAcceptance.message).toBe app.self.CURRENT_WITH_SOME_UNACCEPTED_WORK
-
-    it "displays acceptance error when all work not accepted from past timebox", ->
-
-      @_prepareSomeAcceptedData()
+    it "displays positive acceptance stats when all work accepted for past timebox", ->
+      @_prepareAllAcceptedData()

       @_stubApp(
         startDate:new Date(2011, 4, 2)
@@ -1219,68 +1101,11 @@

       @_createApp({}).then (app) =>

-        configAcceptance = acceptanceSpy.getCall(0).returnValue
-        expect(configAcceptance.title).toBe "48% Accepted"
-        expect(configAcceptance.subtitle).toBe "(13 of 27 Points)"
-        expect(configAcceptance.status).toBe "error"
-        expect(configAcceptance.message).toBe app.self.PAST_WITH_SOME_UNACCEPTED_WORK
-
-    it "displays defect error when active defects remain from past timebox", ->
-
-      @_prepareFiveDefectsData()
-
-      @_stubApp(
-        startDate:new Date(2011, 4, 13)
-        endDate:new Date(2011, 4, 20, 23, 59, 59)
-        today:new Date(2011, 5, 14)
-      )
-
-      defectSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getDefectsConfigObject')
-
-      @_createApp({}).then (app) =>
-
-        configDefects = defectSpy.getCall(0).returnValue
-        expect(configDefects.title).toBe "5 Active Defects"
-        expect(configDefects.status).toBe "error"
-        expect(configDefects.message).toBe app.self.PAST_WITH_DEFECTS
-
-    it "does not display defect stats when no active defects for past timebox", ->
-
-      @_prepareNoActiveDefectsData()
-
-      @_stubApp(
-        startDate:new Date(2011, 4, 13)
-        endDate:new Date(2011, 4, 20, 23, 59, 59)
-        today:new Date(2011, 5, 14)
-      )
-
-      defectSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getDefectsConfigObject')
-
-      @_createApp({}).then (app) =>
-
-        configDefects = defectSpy.getCall(0).returnValue
-        expect(!!configDefects.title).toBeFalsy()
-        expect(!!configDefects.status).toBeFalsy()
-        expect(!!configDefects.message).toBeFalsy()
-
-    it "displays positive acceptance stats when all work accepted for past timebox", ->
-      @_prepareAllAcceptedData()
-
-      @_stubApp(
-        startDate:new Date(2011, 4, 2)
-        endDate:new Date(2011, 4, 20, 23, 59, 59)
-        today:new Date(2011, 5, 5)
-      )
-
-      acceptanceSpy = @spy(Rally.apps.iterationsummary.IterationSummaryApp.prototype, '_getAcceptanceConfigObject')
-
-      @_createApp({}).then (app) =>
-
-        configAcceptance = acceptanceSpy.getCall(0).returnValue
-        expect(configAcceptance.title).toBe "100% Accepted"
-        expect(configAcceptance.subtitle).toBe "(27 of 27 Points)"
-        expect(configAcceptance.status).toBe "success"
-        expect(configAcceptance.message).toBe ""
+        acceptanceSpy.firstCall.returnValue.always (configAcceptance) ->
+          expect(configAcceptance.title).toBe "100% Accepted"
+          expect(configAcceptance.subtitle).toBe "(27 of 27 Points)"
+          expect(configAcceptance.status).toBe "success"
+          expect(configAcceptance.message).toBe ""

     it "displays positive acceptance stats when all work accepted or released for past timebox", ->

@@ -1454,11 +1279,11 @@

       @_createApp({}).then (app) =>

-        configAcceptance = acceptanceSpy.getCall(0).returnValue
-        expect(configAcceptance.title).toBe "100% Accepted"
-        expect(configAcceptance.subtitle).toBe "(27 of 27 Points)"
-        expect(configAcceptance.status).toBe "success"
-        expect(configAcceptance.message).toBe ""
+        acceptanceSpy.firstCall.returnValue.always (configAcceptance) ->
+          expect(configAcceptance.title).toBe "100% Accepted"
+          expect(configAcceptance.subtitle).toBe "(27 of 27 Points)"
+          expect(configAcceptance.status).toBe "success"
+          expect(configAcceptance.message).toBe ""

     it "displays success acceptance stats with work items without estimates but all accepted", ->

@@ -1612,11 +1437,11 @@

       @_createApp({}).then (app) =>

-        configAcceptance = acceptanceSpy.getCall(0).returnValue
-        expect(configAcceptance.title).toBe "100% Accepted"
-        expect(configAcceptance.subtitle).toBe "(18 of 18 Points)"
-        expect(configAcceptance.status).toBe "pending"
-        expect(configAcceptance.message).toBe "3 work items have no estimate."
+        acceptanceSpy.firstCall.returnValue.always (configAcceptance) ->
+          expect(configAcceptance.title).toBe "100% Accepted"
+          expect(configAcceptance.subtitle).toBe "(18 of 18 Points)"
+          expect(configAcceptance.status).toBe "pending"
+          expect(configAcceptance.message).toBe "3 work items have no estimate."

     it "displays gently scolding for past timebox with work accepted late", ->

@@ -1632,11 +1457,11 @@

       @_createApp({}).then (app) =>

-        configAcceptance = acceptanceSpy.getCall(0).returnValue
-        expect(configAcceptance.title).toBe "100% Accepted"
-        expect(configAcceptance.subtitle).toBe "(27 of 27 Points)"
-        expect(configAcceptance.status).toBe "success"
-        expect(configAcceptance.message).toBe app.self.PAST_WITH_ACCEPTED_WORK_AFTER_END_DATE
+        acceptanceSpy.firstCall.returnValue.always (configAcceptance) ->
+          expect(configAcceptance.title).toBe "100% Accepted"
+          expect(configAcceptance.subtitle).toBe "(27 of 27 Points)"
+          expect(configAcceptance.status).toBe "success"
+          expect(configAcceptance.message).toBe app.self.PAST_WITH_ACCEPTED_WORK_AFTER_END_DATE

     it "does not display stats when there are no tests", ->

@@ -1684,7 +1509,7 @@

       @_createApp({}).then (app) =>

-        configTests = testsSpy.getCall(0).returnValue
+        configTests = testsSpy.firstCall.returnValue
         expect(!!configTests.title).toBeFalsy()
         expect(!!configTests.status).toBeFalsy()
         expect(!!configTests.message).toBeFalsy()
@@ -1703,7 +1528,7 @@

       @_createApp({}).then (app) =>

-        configTests = testsSpy.getCall(0).returnValue
+        configTests = testsSpy.firstCall.returnValue
         expect(configTests.title).toBe "33% Tests Passing"
         expect(configTests.subtitle).toBe "(3 of 9)"
         expect(configTests.status).toBe "pending"
@@ -1751,7 +1576,7 @@

       @_createApp({}).then (app) =>

-        configTests = testsSpy.getCall(0).returnValue
+        configTests = testsSpy.firstCall.returnValue
         expect(configTests.title).toBe "0% Tests Passing"
         expect(configTests.subtitle).toBe "(0 of 9)"
         expect(configTests.status).toBe "warn"
@@ -1771,7 +1596,7 @@

       @_createApp({}).then (app) =>

-        configTests = testsSpy.getCall(0).returnValue
+        configTests = testsSpy.firstCall.returnValue
         expect(configTests.title).toBe "33% Tests Passing"
         expect(configTests.subtitle).toBe "(3 of 9)"
         expect(configTests.status).toBe "pending"
@@ -1819,7 +1644,7 @@

       @_createApp({}).then (app) =>

-        configTests = testsSpy.getCall(0).returnValue
+        configTests = testsSpy.firstCall.returnValue
         expect(configTests.title).toBe "100% Tests Passing"
         expect(configTests.subtitle).toBe "(9 of 9)"
         expect(configTests.status).toBe "success"
@@ -1839,7 +1664,7 @@

       @_createApp({}).then (app) =>

-        configTests = testsSpy.getCall(0).returnValue
+        configTests = testsSpy.firstCall.returnValue
         expect(configTests.title).toBe "33% Tests Passing"
         expect(configTests.subtitle).toBe "(3 of 9)"
         expect(configTests.status).toBe "error"


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/flickerable.coffee
+++ test/flickerable.coffee
@@ -37,7 +37,7 @@
     equals player.I.alpha, 0.2

   2.times ->
-    player.
+    player.update()

 module()


Modal is now triggered on group join request to ensure the user knows about the information they are giving away.

--- picoCTF-web/web/coffee/team.coffee
+++ picoCTF-web/web/coffee/team.coffee
@@ -19,7 +19,8 @@
       when 1
         $("#group-info").html renderGroupInformation({data: data.data})

-        $("#group-request-form").on "submit", group_request
+        $("#join-group").on "click", group_request
+        $("#group-request-form").on "submit", join_group_request
         $(".leave-group-span").on "click", (e) ->
           leave_group $(e.target).data("group-name")

@@ -27,18 +28,27 @@
   apiCall "POST", "/api/group/join", {"group-name": group_name}
   .done (data) ->
     apiNotify(data)
-    if data['status'] is 1
+    if data["status"] is 1
       load_group_info()

 leave_group = (group_name) ->
   apiCall "POST", "/api/group/leave", {"group-name": group_name}
   .done (data) ->
     apiNotify(data)
-    if data['status'] is 1
+    if data["status"] is 1
       load_group_info()

-#Could be simplified without this function
 group_request = (e) ->
+  e.preventDefault()
+  form = $(this).closest "form"
+  $("#confirm-group-join").modal {backdrop: "static", keyboard: false}
+  .one "click", "#join-group", (e) ->
+    form.trigger "submit"
+    return
+  return
+
+
+join_group_request = (e) ->
   e.preventDefault()

   group_name = $("#group-name-input").val()


Remove debug

Remove debug

--- assets/javascripts/views/new_post_form.js.coffee
+++ assets/javascripts/views/new_post_form.js.coffee
@@ -1,7 +1,6 @@
 class StatusPro.Views.NewPostForm extends Backbone.View
   initialize: (options = {}) ->
     @parentView = options.parentView
-    window.form = @

     @action = "#{StatusPro.api_root}/posts"