Fix-up constraints test

Fix-up constraints test

--- bokehjs/test/models/plots/plot_canvas.coffee
+++ bokehjs/test/models/plots/plot_canvas.coffee
@@ -118,47 +118,21 @@

   beforeEach ->
     @test_doc = new Document()
-    test_plot = new Plot({x_range: new DataRange1d(), y_range: new DataRange1d(), toolbar: new Toolbar()})
-    test_plot.attach_document(@test_doc)
-    @test_plot_canvas = test_plot.plot_canvas
+    @plot = new Plot({
+      x_range: new Range1d({start: 0, end: 1})
+      y_range: new Range1d({start: 0, end: 1})
+      toolbar: new Toolbar()
+      title: null
+    })
+    @plot.attach_document(@test_doc)
+    @test_plot_canvas = new PlotCanvas({ 'plot': @plot })
+    @test_plot_canvas.attach_document(@test_doc)

   it "should return 20 constraints from _get_constant_constraints", ->
     expect(@test_plot_canvas._get_constant_constraints().length).to.be.equal 20

   it "should return 0 constraints from _get_side_constraints if there are no side renderers", ->
     expect(@test_plot_canvas._get_side_constraints().length).to.be.equal 0
-
-  it "should return 2 constraints from _get_side_constraints if there is one side renderer on above", ->
-    expect(@test_plot_canvas._get_side_constraints().length).to.be.equal 0
-    @test_plot_canvas.add_layout(new LinearAxis(), 'above')
-    expect(@test_plot_canvas._get_side_constraints().length).to.be.equal 2
-
-  it "should return 2 constraints from _get_side_constraints if there is one side renderer on below", ->
-    expect(@test_plot_canvas._get_side_constraints().length).to.be.equal 0
-    @test_plot_canvas.add_layout(new LinearAxis(), 'below')
-    expect(@test_plot_canvas._get_side_constraints().length).to.be.equal 2
-
-  it "should return 2 constraints from _get_side_constraints if there is one side renderer on left", ->
-    expect(@test_plot_canvas._get_side_constraints().length).to.be.equal 0
-    @test_plot_canvas.add_layout(new LinearAxis(), 'left')
-    expect(@test_plot_canvas._get_side_constraints().length).to.be.equal 2
-
-  it "should return 2 constraints from _get_side_constraints if there is one side renderer on right", ->
-    expect(@test_plot_canvas._get_side_constraints().length).to.be.equal 0
-    @test_plot_canvas.add_layout(new LinearAxis(), 'right')
-    expect(@test_plot_canvas._get_side_constraints().length).to.be.equal 2
-
-  it "should return 4 constraints from _get_side_constraints if there are two side renderers", ->
-    expect(@test_plot_canvas._get_side_constraints().length).to.be.equal 0
-    @test_plot_canvas.add_layout(new LinearAxis(), 'left')
-    @test_plot_canvas.add_layout(new LinearAxis(), 'right')
-    expect(@test_plot_canvas._get_side_constraints().length).to.be.equal 4
-
-  it "should return 3 constraints from _get_side_constraints if there are two side renderers on one side", ->
-    expect(@test_plot_canvas._get_side_constraints().length).to.be.equal 0
-    @test_plot_canvas.add_layout(new LinearAxis(), 'left')
-    @test_plot_canvas.add_layout(new LinearAxis(), 'left')
-    expect(@test_plot_canvas._get_side_constraints().length).to.be.equal 3

   it "should call _get_side_constraints, _get_constant_constraints", ->
     @test_plot_canvas._get_side_constraints = sinon.spy()
@@ -178,6 +152,56 @@
     @test_plot_canvas.get_constraints()
     for child in children
       expect(child.get_constraints.callCount).to.be.equal 1
+
+describe "PlotCanvas.Model constraints with different layouts", ->
+
+  beforeEach ->
+    @doc = new Document()
+    @plot = new Plot({
+      x_range: new Range1d({start: 0, end: 1})
+      y_range: new Range1d({start: 0, end: 1})
+      toolbar: new Toolbar()
+      title: null
+    })
+
+  it "should return 2 constraints from _get_side_constraints if there is one side renderer on above", ->
+    @plot.add_layout(new LinearAxis(), 'above')
+    @plot.attach_document(@doc)
+    plot_canvas = new PlotCanvas({ 'plot': @plot })
+    expect(plot_canvas._get_side_constraints().length).to.be.equal 2
+
+  it "should return 3 constraints from _get_side_constraints if there are two side renderers on one side", ->
+    @plot.add_layout(new LinearAxis(), 'left')
+    @plot.add_layout(new LinearAxis(), 'left')
+    @plot.attach_document(@doc)
+    plot_canvas = new PlotCanvas({ 'plot': @plot })
+    expect(plot_canvas._get_side_constraints().length).to.be.equal 3
+
+  it "should return 2 constraints from _get_side_constraints if there is one side renderer on below", ->
+    @plot.add_layout(new LinearAxis(), 'below')
+    @plot.attach_document(@doc)
+    plot_canvas = new PlotCanvas({ 'plot': @plot })
+    expect(plot_canvas._get_side_constraints().length).to.be.equal 2
+
+  it "should return 2 constraints from _get_side_constraints if there is one side renderer on left", ->
+    @plot.add_layout(new LinearAxis(), 'left')
+    @plot.attach_document(@doc)
+    plot_canvas = new PlotCanvas({ 'plot': @plot })
+    expect(plot_canvas._get_side_constraints().length).to.be.equal 2
+
+  it "should return 2 constraints from _get_side_constraints if there is one side renderer on right", ->
+    @plot.add_layout(new LinearAxis(), 'right')
+    @plot.attach_document(@doc)
+    plot_canvas = new PlotCanvas({ 'plot': @plot })
+    expect(plot_canvas._get_side_constraints().length).to.be.equal 2
+
+  it "should return 4 constraints from _get_side_constraints if there are two side renderers", ->
+    @plot.add_layout(new LinearAxis(), 'left')
+    @plot.add_layout(new LinearAxis(), 'right')
+    @plot.attach_document(@doc)
+    plot_canvas = new PlotCanvas({ 'plot': @plot })
+    expect(plot_canvas._get_side_constraints().length).to.be.equal 4
+

 describe "PlotCanvas.View render", ->


ake sure legend less than or greater than arrows also point in the right direction of domain_min is actually larger than domain_max

--- src/coffee/choropleth.coffee
+++ src/coffee/choropleth.coffee
@@ -85,10 +85,16 @@
         legend_h = 210
         offset_t = 4
         offset_y = geomap.properties.height - box_h
-        # reverse a copy to not alter colors array
+
+        # Reverse a copy to not alter colors array.
         colorlist = geomap.properties.colors.slice().reverse()
         rect_h = legend_h / colorlist.length

+        # Determine minimum and maximum values of data domain.
+        domain_min = geomap.private.domain[0]
+        domain_max = geomap.private.domain[geomap.private.domain.length - 1]
+
+        # Remove possibly existing legend, before drawing.
         geomap.properties.svg.select('g#legend').remove()

         lg = geomap.properties.svg.append('g')
@@ -133,10 +139,12 @@
             .attr('y', (d, i)-> i * rect_h + rect_h + offset_t)

         # Add text element for maximum value.
-        domain_max = geomap.private.domain[geomap.private.domain.length - 1]
         max_text = geomap.properties.format(domain_max)
         if domain_max < max_val
-            max_text = '> ' + max_text
+            if domain_max > domain_min
+                max_text = '> ' + max_text
+            else
+                max_text = '< ' + max_text

         sg.append('text')
             .text(max_text)
@@ -144,7 +152,6 @@
             .attr('y', offset_t)

         # Determine text to display for min val by default use domain_min.
-        domain_min = geomap.private.domain[0]
         min_text = geomap.properties.format(domain_min)
         if min_val < domain_min
             # When a threshold scale is used domain_min is the upper bound of
@@ -152,7 +159,10 @@
             if geomap.private.domain.length > 2
                 min_text = geomap.properties.format(min_val)
             else
-                min_text = '< ' + min_text
+                if domain_max > domain_min
+                    min_text = '< ' + min_text
+                else
+                    min_text = '> ' + min_text

         # Hacky way to update already existing legend text element with min val.
         min_val_idx = colorlist.length - 1


refactor hat-trick's stepShownCallback() now that step_shown is triggered even on the first step

--- app/assets/javascripts/hat-trick.js.coffee
+++ app/assets/javascripts/hat-trick.js.coffee
@@ -3,7 +3,7 @@
 class HatTrickWizard
   constructor: (formElem, @wizard) ->
     @form = $(formElem)
-    this.stepShownCallback() # because we just showed the first step (or the one in the URL)
+    this.enableFormwizard()

   formwizardEnabled: false

@@ -14,13 +14,6 @@
   stepsNeedUpdate: false

   stepShownCallback: ->
-    if not @formwizardEnabled
-      this.saveStepMetadata()
-      this.addStepClass()
-      this.setAction(hatTrick.metadata.url, hatTrick.metadata.method)
-      # prevent submitting the step that happens to be the last fieldset
-      # TODO: Figure out a better way to do this
-      this.addFakeLastStep()
     currentStepId = this.currentStepId()
     if hatTrick.stepMetadata[currentStepId]?
       hatTrick.metadata.currentStep = hatTrick.stepMetadata[currentStepId]
@@ -28,23 +21,17 @@
       this.requestMetadataFromServer()
       return
     this.updateStepFromMetadata()
-    if not @formwizardEnabled
-      currentStepId = this.currentStepId()
-      # can't go back from the first step
-      if hatTrick.metadata.currentStep.first
-        this.buttons[currentStepId] = this.buttons[currentStepId].filter (button) ->
-          not button.back?
-
-      this.setupButtonsForStep(currentStepId)
-      this.enableFormwizard()
-      this.bindEvents()
+    currentStepId = this.currentStepId()
+    # can't go back from the first step
+    if hatTrick.metadata.currentStep.first
+      this.buttons[currentStepId] = this.buttons[currentStepId].filter (button) ->
+        not button.back?
+    this.setupButtonsForCurrentStep()
+    if @stepsNeedUpdate
+      this.updateSteps()
+      @stepsNeedUpdate = false
     else
-      this.setupButtonsForCurrentStep()
-      if @stepsNeedUpdate
-        this.updateSteps()
-        @stepsNeedUpdate = false
-      else
-        this.updateButtons()
+      this.updateButtons()
     this.setCurrentStepField()
     this.removeLinkField()
     this.setFormFields(hatTrick.model)
@@ -170,11 +157,17 @@
     @form.append """<fieldset id="_ht_fake_last_step" style="display: none;" class="step"></fieldset>"""

   enableFormwizard: ->
+    this.addStepClass()
+    this.saveStepMetadata()
+    this.setAction(hatTrick.metadata.url, hatTrick.metadata.method)
+    # prevent submitting the step that happens to be the last fieldset
+    # TODO: Figure out a better way to do this
+    this.addFakeLastStep()
+    this.bindEvents()
     @form.formwizard
       formPluginEnabled: true,
       validationEnabled: false,
       focusFirstInput: true,
-      historyEnabled: true,
       disableUIStyles: true,
       inDuration: 0,
       next: "button:submit",


make external redirects open in new window (if we're in an iframe) to avoid x-frame-Options restrictions

--- app/assets/javascripts/hat-trick.js.coffee
+++ app/assets/javascripts/hat-trick.js.coffee
@@ -346,7 +346,10 @@
     if data.metadata?.externalRedirectURL?
       externalRedirectURL = data.metadata.externalRedirectURL
       if externalRedirectURL isnt ""
-        location.href = data.metadata.externalRedirectURL
+        if (top.location == self.location)
+          location.href = data.metadata.externalRedirectURL
+        else
+          window.open(data.metadata.externalRedirectURL)

     if data.metadata?.url? and data.metadata?.method?
       this.setAction(data.metadata.url, data.metadata.method)


Fixed Toast messages on request failures

--- app/assets/javascripts/libs/request.coffee
+++ app/assets/javascripts/libs/request.coffee
@@ -165,7 +165,7 @@
         (text) ->
           try
             json = JSON.parse(text)
-            Toast.message(json.message)
+            Toast.message(json.message ? json.messages)
             Promise.reject(json)
           catch error
             Toast.error(text)


removed obsolete file

removed obsolete file

--- app/assets/javascripts/templates.js.coffee
+++ app/assets/javascripts/templates.js.coffee
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/


fix userpilot identify condition (#1934)

--- app/coffee/modules/common/userpilot.coffee
+++ app/coffee/modules/common/userpilot.coffee
@@ -36,7 +36,7 @@

     identify: (force = false) ->
         userdata = @win.localStorage.getItem("userInfo")
-        if ((@win.userpilot and userdata and not @.identified) or force)
+        if (@win.userpilot and ((userdata and not @.identified) or force))
             data = JSON.parse(userdata)
             if (data["id"])
                 id = parseInt(data["id"], 10)


Fix quench subject conversion

Fix quench subject conversion

--- app/collections/zooniverse_subjects.coffee
+++ app/collections/zooniverse_subjects.coffee
@@ -81,7 +81,14 @@
     params.join('&')

   galaxy_zoo_starburst: (subject) =>
-    @galaxy_zoo(subject)
+    model =
+      uid: subject.zooniverse_id
+      image: subject.location.standard
+      thumb: subject.location.thumbnail
+      ra: subject.coords[0]
+      dec: subject.coords[1]
+    model[key] = value for key, value of subject.metadata when key isnt 'control' or key isnt 'counters'
+    model

   galaxy_zoo: (subject) =>
     model =


remove fetching from db

remove fetching from db

--- src/controllers/index.coffee
+++ src/controllers/index.coffee
@@ -62,30 +62,30 @@
       return

     result = []
-    get_from_db = false
+    get_from_db = true
     get_from_flickr = false
-    pg.connect DATABASE_URL, (err, client, done) ->
-      if err
-        console.log err
-        return done()
-
-      query = client.query "SELECT * FROM photos ORDER BY random() LIMIT 1;", (err, reslt) ->
-        if err
-          console.log err
-          get_from_db = true
-          return done()
-        console.log "Get from db: ", result
-        for r in reslt.rows
-          c_ph =
-            url: r.url_z,
-            country: r.country,
-            res_url: r.res_url
-
-          result.push (c_ph)
-        get_from_db = true
-        console.log "Got photos from db; flickr status: " + get_from_flickr
-        if get_from_flickr == true
-          res.send result
+    # pg.connect DATABASE_URL, (err, client, done) ->
+    #   if err
+    #     console.log err
+    #     return done()
+    #
+#      query  = client.query "SELECT * FROM photos ORDER BY random() LIMIT 1;", (err, reslt) ->
+#         if err
+#           console.log err
+#           get_from_db = true
+#           return done()
+#         console.log "Get from db: ", result
+#         for r in reslt.rows
+#           c_ph =
+#             url: r.url_z,
+#             country: r.country,
+#             res_url: r.res_url
+#
+#           result.push (c_ph)
+#         get_from_db = true
+#         console.log "Got photos from db; flickr status: " + get_from_flickr
+#         if get_from_flickr == true
+#           res.send result

     place_ids = []


Fix bug in displaying opening hours

Fix bug in displaying opening hours

--- src/models.coffee
+++ src/models.coffee
@@ -92,9 +92,9 @@
             data = super()

             opening_hours = _.filter @get('connections'), (c) ->
-                c.section == 'opening_hours' and c.type == 0
+                c.section == 'opening_hours' and c.type == 0 and p13n.get_language() of c.name
             if opening_hours.length > 0
-                response.opening_hours = opening_hours[0].name[p13n.get_language()]
+                data.opening_hours = opening_hours[0].name[p13n.get_language()]

             highlights = _.filter @get('connections'), (c) ->
                 c.section == 'miscellaneous' and p13n.get_language() of c.name


Another incorrect variable

Another incorrect variable

Signed-off-by: Steven Hoffman <f5bcacb8ce1651b7d1e56f2693431f20e085fdeb@valenciamgmt.com>

--- vendor/assets/javascripts/fustrate/components/alert_box.coffee
+++ vendor/assets/javascripts/fustrate/components/alert_box.coffee
@@ -3,10 +3,10 @@

   @initialize: ->
     $('.alert-box').on 'click', '.close', (e) ->
-      event.preventDefault()
+      e.preventDefault()

       alert_box = $(e.currentTarget).closest('.alert-box')

-      alert_box.fadeOut @constructor.fadeSpeed, -> alert_box.remove()
+      alert_box.fadeOut @constructor.fadeSpeed, alert_box.remove

       false


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

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

   self.bind "update", ->
     I.x = I.x.clamp(I.width / 2, App.width - I.width / 2)
-    I.y = I.y.clamp(I.height / ,)
+    I.y = I.y.clamp(I.height / 2, App.h)


msgflo: Allow to specify --forward

msgflo: Allow to specify --forward

--- src/msgflo.coffee
+++ src/msgflo.coffee
@@ -17,6 +17,7 @@
     .option('--library <FILE.json>', 'Library configuration file', String, 'package.json')
     .option('--graph <file.json>', 'Initial graph to load', String, '')
     .option('--ignore [process]', "Don't set up these processes", collectArray, [])
+    .option('--forward stderr,stdout', "Forward these streams from child", String, 'stderr,stdout')
     .parse(process.argv)

   r = new runtime.Runtime program


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/animated.coffee
+++ src/animated.coffee
@@ -104,9 +104,7 @@
     if I.currentFrameIndex == frames.indexOf(frames.last())
       self.trigger("Complete")

-      nextState = I.activeAnimation.complete
-
-      if nextState
+      if nextState = I.activeAnimation.complete
         I.activeAnimation = find(nextState) || I.activeAnimation
         I.currentFrameIndex = 0
     else


Fix obscure edge case with JS parser hackery (this. at end of lines in comments)

--- app/lib/aether/languages/javascript.coffee
+++ app/lib/aether/languages/javascript.coffee
@@ -131,8 +131,8 @@
   # Hacky McHack step for things we can't easily change via AST transforms (which preserve statement ranges).
   # TODO: Should probably refactor and get rid of this soon.
   hackCommonMistakes: (code, aether) ->
-    # Stop this.\n from failing on the next weird line
-    code = code.replace /this\.\s*?\n/g, "this.IncompleteThisReference;"
+    # Stop this.\n from failing on the next weird line, unless it's in a comment
+    code = code.replace /(?<!\/\/.*?)this\.\s*?\n/g, "this.IncompleteThisReference;"
     # If we wanted to do it just when it would hit the ending } but allow multiline this refs:
     #code = code.replace /this.(\s+})$/, "this.IncompleteThisReference;$1"
     code


Add stack trace

Add stack trace

--- list.coffee
+++ list.coffee
@@ -340,6 +340,8 @@
                     ready = false
                     e
                 else
+                    console.log e.stack
+                    console.trace()
                     throw e
         if not ready then throw J.makeValueNotReadyObject()
         ret


Forgot to pass offset and limit to the request

--- src/coffee/utils.coffee
+++ src/coffee/utils.coffee
@@ -3,7 +3,7 @@
 # TODO: move it to `sphere-node-client` or `sphere-node-utils`
 module.exports =

-  pagedFetch: (rest, endpoint)->
+  pagedFetch: (rest, endpoint) ->
     deferred = Q.defer()
     _page = (offset = 0, limit = 100, total, acc = []) ->
       if total? and (offset + limit) >= total + limit
@@ -12,7 +12,7 @@
           message: ' done'
         deferred.resolve acc
       else
-        rest.GET endpoint, (error, response, body) ->
+        rest.GET "#{endpoint}?offset=#{offset}&limit=#{limit}", (error, response, body) ->
           unless total
             deferred.notify
               inProgress: true
@@ -29,4 +29,4 @@
               humanReadable = JSON.stringify body, null, 2
               deferred.reject humanReadable
     _page()
-    deferred.promise+    deferred.promise


Delete unnecessary spaces

Delete unnecessary spaces

--- src/autometa.coffee
+++ src/autometa.coffee
@@ -75,7 +75,7 @@
   for template in templates
     template = path.resolve(template)
     filename = path.basename(template)
-
+
     if fs.existsSync(template)
       ext = path.extname(template)
       if (ext is '.csv') or (ext is '.ejs') or (ext is '.ect')


add simulateShipping

add simulateShipping

--- src/checkout.coffee
+++ src/checkout.coffee
@@ -254,9 +254,23 @@
 		.done(@_cacheOrderForm)
 		.done(broadcastOrderForm)

-	# Sends a request to calculates shipping for the current OrderForm, given an address object.
+	# Sends a request to calculates shipping for the current OrderForm, given a COMPLETE address object.
 	calculateShipping: (address) =>
 		@sendAttachment('shippingData', {address: address})
+
+	# Simulates shipping using a list of items, a postal code and a country.
+	simulateShipping: (items, postalCode, country) =>
+		data =
+			items: items
+			postalCode: postalCode
+			country: country
+
+		@ajax
+			url: @_getSimulationURL()
+			type: 'POST'
+			contentType: 'application/json; charset=utf-8'
+			dataType: 'json'
+			data: JSON.stringify(data)

 	# Given an address with postal code and a country, retrieves a complete address, when available.
 	getAddressInformation: (address) =>
@@ -380,6 +394,9 @@
 	_getOrdersURL: (orderGroupId) =>
 		HOST_URL + '/api/checkout/pub/orders/order-group/' + orderGroupId

+	_getSimulationURL: =>
+		HOST_URL + '/api/checkout/pub/orderForms/simulation'
+
 	_getPostalCodeURL: (postalCode = '', countryCode = 'BRA') =>
 		HOST_URL + '/api/checkout/pub/postal-code/' + countryCode + '/' + postalCode


Handle error spawn ENOENT

Handle error spawn ENOENT

--- src/rcedit.coffee
+++ src/rcedit.coffee
@@ -27,6 +27,8 @@
   child = spawn rcedit, args

   stderr = ''
+  child.on 'error', (err) ->
+    callback err
   child.stderr.on 'data', (data) -> stderr += data
   child.on 'close', (code) ->
     if code is 0


Implement sync/publish functions on Rivets.View.

--- src/rivets.coffee
+++ src/rivets.coffee
@@ -188,6 +188,12 @@
   # Unbinds all of the current bindings for this view.
   unbind: =>
     binding.unbind() for binding in @bindings
+
+  sync: =>
+    binding.sync() for binding in @bindings
+
+  publish: =>
+    binding.publish() for binding in @bidirectionals()

 # Cross-browser event binding
 bindEvent = (el, event, fn) ->


router: fix method binding

router: fix method binding

--- src/router.coffee
+++ src/router.coffee
@@ -37,7 +37,7 @@
         for backend in @backends
             backend.notify notification

-    authorizeFor: (sender, actor, cb) ->
+    authorizeFor: (sender, actor, cb) =>
         backends = new Array(@backends...)
         tryBackend = =>
             backend = backends.shift()
@@ -50,7 +50,7 @@
                     cb err, valid
         tryBackend()

-    detectAnonymousUser: (user, cb) ->
+    detectAnonymousUser: (user, cb) =>
         backends = new Array(@backends...)
         tryBackend = =>
             backend = backends.shift()


Change position of res.writeHead in order to avoid error

--- src/server.coffee
+++ src/server.coffee
@@ -131,15 +131,13 @@

   renderNotFound: (req, res) =>
     res.contentType('text/plain')
-    res.writeHead 404
     res.write '404 Not Found\n'
     res.end()
+    res.writeHead 404

   renderStaticFile: (req, res, fileName) =>
     ext  = path.extname fileName
     res.contentType(mimeTypes[ext])
-    res.writeHead 200
-
     fs.readFile fileName, 'binary', (error, file) =>
       uri = req.protocol + '://' + req.get('host') + req.url
       referer = req.headers.referer
@@ -163,6 +161,7 @@
             page.sources.push source

           file = Instrumentor.instrumentFunctionTrace source, @tracer
+      res.writeHead 200
       res.write(file, 'binary')
       res.end()


Remove console.log

Remove console.log

--- src/server.coffee
+++ src/server.coffee
@@ -127,8 +127,6 @@
     if err then return callback err
     if res.statusCode isnt 200 then return callback new Error "Returned non-200 response code: #{body}"

-    console.log res.statusCode, body.toString()
-
     callback null, body


Typos

Typos

--- src/server.coffee
+++ src/server.coffee
@@ -19,7 +19,7 @@
   server.use express.bodyParser()
   return

-# Search Intereface
+# Search Interface
 server.get '/', (req, res) ->
   res.render 'search'


Added app owner id type conversion

Added app owner id type conversion

--- src/data/db_apps.coffee
+++ src/data/db_apps.coffee
@@ -80,6 +80,9 @@
 						secret:replies[2],
 						owner: replies[3]
 					}
+					if typeof owner_id != 'string' && owner_id.toString?
+						owner_id = owner_id.toString()
+
 					if app.owner == owner_id
 						apps.push app
 					next()


Fix source mapping line numbers

Fix source mapping line numbers

--- src/instrumenter.coffee
+++ src/instrumenter.coffee
@@ -84,13 +84,13 @@
             leave: (node, parent) ->
                 mappedLocation = (location) ->
                   locArray = sourceMap.getSourcePosition([
-                    location.line - program.loc.start.line,
-                    location.column - program.loc.start.column])
+                    location.line - 1,
+                    location.column])
                   line = 0
                   column = 0
                   if locArray
-                    line = locArray[0] + program.loc.start.line
-                    column = locArray[1] + program.loc.start.column
+                    line = locArray[0] + 1
+                    column = locArray[1]
                   return { line: line, column: column }

                 if node.loc?.start


governor: Split out calculation of new state

Preparation for supporting hysteresis

--- src/governor.coffee
+++ src/governor.coffee
@@ -9,32 +9,41 @@
 rabbitmq = require './rabbitmq'
 scale = require './scale'

+newState = (cfg, queues) ->
+  state = {}
+  for name, role of cfg
+    continue if name == '*'
+    state[name] = s = {}
+    s.current_jobs = queues[role.queue]
+    s.metric = role.metric
+    s.app = role.app
+
+    if not s.current_jobs?
+      s.error = new Error "Could not get data for queue: #{role.queue}"
+    else
+      s.new_workers = scale.scale role, s.current_jobs
+
+  return state
+
+realizeState = (cfg, state, callback) ->
+  workers = []
+  for name, role of state
+    continue if role.error
+    workers.push
+      app: role.app
+      role: cfg[name].worker
+      quantity: role.new_workers
+
+  heroku.setWorkers cfg['*'], workers, (err) ->
+    return callback err, state if err
+    return callback null, state
+
 checkAndScale = (cfg, callback) ->
-  state = {}
   rabbitmq.getStats cfg['*'], (err, queues) ->
     return callback err if err

-    workers = []
-    for name, role of cfg
-      continue if name == '*'
-      state[name] = s = {}
-      s.current_jobs = queues[role.queue]
-      s.metric = role.metric
-      s.app = role.app
-
-      if not s.current_jobs?
-        s.error = new Error "Could not get data for queue: #{role.queue}"
-      else
-        s.new_workers = scale.scale role, s.current_jobs
-        workers.push
-          app: role.app
-          role: role.worker
-          quantity: s.new_workers
-
-    heroku.setWorkers cfg['*'], workers, (err) ->
-      return callback err, state if err
-      return callback null, state
-
+    state = newState cfg, queues
+    realizeState cfg, state, callback

 class Governor extends EventEmitter
   constructor: (c) ->


Add support for triggering assignment notifications at moment of ticket creation

--- src/jira/webhook.coffee
+++ src/jira/webhook.coffee
@@ -51,6 +51,12 @@
     @onDescriptionChange event,
       toString: event.issue.fields.description or ""
       fromString: ""
+
+    if event.issue.fields.assignee
+      @onAssigneeChange event,
+        field: "assignee"
+        fieldtype: "jira"
+        to: event.issue.fields.assignee.name

   onJiraMention: (event, username, context) ->
     chatUser = null


Fix unset keystroke handling, :art:

Fix unset keystroke handling, :art:

--- src/menu-manager.coffee
+++ src/menu-manager.coffee
@@ -143,16 +143,20 @@
   # Public: Refreshes the currently visible menu.
   update: ->
     clearImmediate(@pendingUpdateOperation) if @pendingUpdateOperation?
+
     @pendingUpdateOperation = setImmediate =>
-      includedBindings = @keymapManager.getKeyBindings().filter (binding) =>
-        return false unless @includeSelector(binding.selector)
-        return false if binding.command is 'unset!'
-        return false if process.platform is 'darwin' and /^alt-(shift-)?.$/.test(binding.keystrokes)
-        return false if process.platform is 'win32' and /^ctrl-alt-(shift-)?.$/.test(binding.keystrokes)
-        true
+      unsetKeystrokes = new Set
+      for binding in @keymapManager.getKeyBindings()
+        if binding.command is 'unset!'
+          unsetKeystrokes.add(binding.keystrokes)

       keystrokesByCommand = {}
-      for binding in includedBindings
+      for binding in @keymapManager.getKeyBindings()
+        continue unless @includeSelector(binding.selector)
+        continue if unsetKeystrokes.has(binding.keystrokes)
+        continue if binding.keystrokes.includes(' ')
+        continue if process.platform is 'darwin' and /^alt-(shift-)?.$/.test(binding.keystrokes)
+        continue if process.platform is 'win32' and /^ctrl-alt-(shift-)?.$/.test(binding.keystrokes)
         keystrokesByCommand[binding.command] ?= []
         keystrokesByCommand[binding.command].unshift binding.keystrokes

@@ -175,21 +179,7 @@
   unmerge: (menu, item) ->
     MenuHelpers.unmerge(menu, item)

-  # macOS can't handle displaying accelerators for multiple keystrokes.
-  # If they are sent across, it will stop processing accelerators for the rest
-  # of the menu items.
-  filterMultipleKeystroke: (keystrokesByCommand) ->
-    filtered = {}
-    for key, bindings of keystrokesByCommand
-      for binding in bindings
-        continue if binding.indexOf(' ') isnt -1
-
-        filtered[key] ?= []
-        filtered[key].push(binding)
-    filtered
-
   sendToBrowserProcess: (template, keystrokesByCommand) ->
-    keystrokesByCommand = @filterMultipleKeystroke(keystrokesByCommand)
     ipcRenderer.send 'update-application-menu', template, keystrokesByCommand

   # Get an {Array} of {String} classes for the given element.


Automagically append http://www. in website field when empty

--- app/assets/javascripts/app/controllers/people.js.coffee
+++ app/assets/javascripts/app/controllers/people.js.coffee
@@ -73,6 +73,8 @@
     'click a[name=person_second_phone_button]': 'call_to'
     'click a[name=person_mobile_button]': 'call_to'
     'click a[name=person_website_button]': 'link_to'
+    'focusin input[name=website]': 'append_http'
+    'focusout input[name=website]': 'remove_http'

   constructor: (params) ->
     super
@@ -122,6 +124,18 @@
     url = $(e.target).closest(".input-group").find("input").val()
     window.open(url, 'person_website')

+  append_http: (e) ->
+    e.preventDefault()
+    input = $(e.target)
+    if input.val() == ""
+      input.val("http://www.")
+
+  remove_http: (e) ->
+    e.preventDefault()
+    input = $(e.target)
+    if input.val() == "http://www."
+      input.val("")
+
 class App.People extends Spine.Controller
   className: 'person'


removing grid view

removing grid view

--- app/assets/javascripts/luca/components/grid_view.coffee
+++ app/assets/javascripts/luca/components/grid_view.coffee
@@ -1,269 +0,0 @@
-_.def('Luca.components.GridView').extend('Luca.Panel').with
-
-  bodyTemplate: "components/grid_view"
-
-  autoBindEventHandlers: true
-
-  events:
-    "dblclick table tbody tr" : "double_click_handler"
-    "click table tbody tr": "click_handler"
-
-  className: 'luca-ui-g-view'
-
-  rowClass: "luca-ui-g-row"
-
-  wrapperClass: "luca-ui-g-view-wrapper"
-
-  # add whatever additional container classes you want
-  # to be applied to the wrapper here
-  additionalWrapperClasses: []
-
-  # add additional style declarations to the wrapper if you like
-  # these will be added by jquery.css and accept the same syntax
-  wrapperStyles: {}
-
-  scrollable: true
-
-  emptyText: 'No Results To display.'
-
-  # available options are striped, condensed, bordered
-  # or any combination of these, split up by space
-  tableStyle: 'striped'
-
-  # we have to specify height to make the scrollable table portion work
-  defaultHeight: 285
-
-  # unless we specify the width ourselves
-  # the width of the grid will automatically be set to the width of the container
-  # and if it can't be determined, then it will be set to the default
-  defaultWidth: 756
-
-  # the grid should never outgrow its container
-  maxWidth: undefined
-
-  # hooks is configuration sugar
-  # the before:grid:render trigger
-  # will automatically fire the
-  # beforeGridRender function
-  hooks:[
-    "before:grid:render"
-    "before:render:header"
-    "before:render:row"
-    "after:grid:render"
-    "row:double:click"
-    "row:click"
-    "after:collection:load"
-  ]
-
-  initialize: (@options={})->
-    _.extend @, @options
-    _.extend @, Luca.concerns.Deferrable
-
-    @loadMask = Luca.config.enableBoostrap unless @loadMask?
-    @loadMaskEl ||= ".luca-ui-g-view-body" if @loadMask is true
-
-    Luca.Panel::initialize.apply(@, arguments)
-
-    @configure_collection(true)
-
-    @collection.bind "before:fetch", ()=>
-      @trigger "enable:loadmask" if @loadMask is true
-
-    @collection.bind "reset", (collection) =>
-      @refresh()
-      @trigger "disable:loadmask" if @loadMask is true
-      @trigger "after:collection:load", collection
-
-    # if a model changes, then we will update the row's contents
-    # by rerendering that row's cells
-    @collection.bind "change", (model)=>
-      return unless @rendered is true
-
-      try
-        rowEl = @getRowEl( model.id || model.get('id') || model.cid )
-        cells = @render_row(model, @collection.indexOf(model), cellsOnly: true )
-        $( rowEl ).html( cells.join(" ") )
-      catch error
-        console.log "Error in change handler for GridView.collection", error, @, model
-
-  beforeRender: ()->
-    Luca.Panel::beforeRender?.apply(@, arguments)
-
-    @trigger "before:grid:render", @
-
-    @table      = @$ 'table.luca-ui-g-view'
-    @header     = @$ "thead"
-    @body       = @$ "tbody"
-    @footer     = @$ "tfoot"
-    @wrapper    = @$ ".#{ @wrapperClass }"
-
-    @applyCssClasses()
-
-    @setDimensions() if @scrollable
-
-    @renderHeader()
-
-    @emptyMessage()
-
-    $(@container).append @$el
-
-  afterRender: ()->
-    Luca.Panel::afterRender?.apply(@, arguments)
-
-    @rendered = true
-    @refresh()
-    @trigger "after:grid:render", @
-
-  applyCssClasses: ()->
-    @$el.addClass 'scrollable-g-view' if @scrollable
-
-    _( @additionalWrapperClasses ).each (containerClass)=>
-      @wrapper?.addClass( containerClass )
-
-    if Luca.config.enableBoostrap
-      @table.addClass('table')
-
-    _( @tableStyle?.split(" ") ).each (style)=>
-      @table.addClass("table-#{ style }")
-
-  setDimensions: (offset)->
-    @height ||= @defaultHeight
-
-    @$('.luca-ui-g-view-body').height( @height )
-    @$('tbody.scrollable').height( @height - 23 )
-
-    @container_width = do => $(@container).width()
-
-    @width ||= if @container_width > 0 then @container_width else @defaultWidth
-
-    # don't let the grid outgrow its maxWidth
-    @width = _([@width, (@maxWidth || @width)]).max()
-
-    @$('.luca-ui-g-view-body').width @width
-    @$('.luca-ui-g-view-body table').width @width
-
-    @setDefaultColumnWidths()
-
-  resize: (newWidth)->
-    difference = newWidth - @width
-    @width = newWidth
-
-    @$('.luca-ui-g-view-body').width( @width )
-    @$('.luca-ui-g-view-body table').width( @width )
-
-    if @columns.length > 0
-      distribution = difference / @columns.length
-
-      _(@columns).each (col,index)=>
-        column = $(".column-#{ index }", @el )
-        column.width( col.width = col.width + distribution )
-
-  padLastColumn: ()->
-    configured_column_widths = _(@columns).inject (sum, column)->
-      sum = (column.width) + sum
-    , 0
-
-    unused_width = @width - configured_column_widths
-
-    if unused_width > 0
-      @lastColumn().width += unused_width
-
-  setDefaultColumnWidths: ()->
-    default_column_width = if @columns.length > 0 then @width / @columns.length else 200
-
-    _( @columns ).each (column)->
-      parseInt(column.width ||= default_column_width)
-
-    @padLastColumn()
-
-  lastColumn: ()->
-    @columns[ @columns.length - 1 ]
-
-
-
-  emptyMessage: (text="")->
-    text ||= @emptyText
-    @body.html('')
-    @body.append Luca.templates["components/grid_view_empty_text"](colspan:@columns.length,text:text)
-
-  refresh: ()->
-    @body.html('')
-    @collection.each (model,index)=>
-      @render_row.apply(@, [model,index])
-
-    if @collection.models.length == 0
-      @emptyMessage()
-
-  ifLoaded: (fn, scope)->
-    scope ||= @
-    fn ||= ()-> true
-
-    @collection.ifLoaded(fn,scope)
-
-  applyFilter: (values, options={auto:true,refresh:true})->
-    @collection.applyFilter(values, options)
-
-  renderHeader: ()->
-    @trigger "before:render:header"
-
-    headers = _(@columns).map (column,column_index) =>
-      # temporary hack for scrollable grid dimensions.
-      style = if column.width then "width:#{ column.width }px;" else ""
-
-      "#{ column.header}	"
-
-    @header.append("
#{ headers }
")
-
-  getRowEl: (id)->
-    @$ "[data-record-id=#{ id }]", 'table'
-
-  render_row: (row,row_index, options={})->
-    rowClass = @rowClass
-
-    model_id = if row?.get and row?.attributes then row.get('id') else ''
-
-    @trigger "before:render:row", row, row_index
-
-    cells = _( @columns ).map (column,col_index) =>
-      value = @cell_renderer(row, column, col_index)
-      style = if column.width then "width:#{ column.width }px;" else ""
-
-      display = if _.isUndefined(value) then "" else value
-
-      "#{ display }	"
-
-    return cells if options.cellsOnly
-
-    altClass = ''
-    if @alternateRowClasses
-      altClass = if row_index % 2 is 0 then "even" else "odd"
-
-    content = "
#{ cells }
"
-
-    return content if options.contentOnly is true
-
-    @body?.append(content)
-
-  cell_renderer: (row, column, columnIndex )->
-    if _.isFunction column.renderer
-      return column.renderer.apply @, [row,column,columnIndex]
-    else if column.data.match(/\w+\.\w+/)
-      source = row.attributes || row
-      return Luca.util.nestedValue( column.data, source )
-    else
-      return row.get?( column.data ) || row[ column.data ]
-
-  double_click_handler: (e)->
-    me = my = $( e.currentTarget )
-    rowIndex = my.data('row-index')
-    record = @collection.at( rowIndex )
-    @trigger "row:double:click", @, record, rowIndex
-
-  click_handler: (e)->
-    me = my = $( e.currentTarget )
-    rowIndex = my.data('row-index')
-    record = @collection.at( rowIndex )
-    @trigger "row:click", @, record, rowIndex
-
-    $(".#{ @rowClass }", @body ).removeClass('selected-row')
-    me.addClass('selected-row')


The main app tour is only shown if the screen is bigger than a smartphone (sm bootstrap responsive category or bigger).

A different tour will be shown in smartphones.

--- app/assets/javascripts/ng-services/ng-TourSvc.js.coffee
+++ app/assets/javascripts/ng-services/ng-TourSvc.js.coffee
@@ -4,6 +4,11 @@

 angular.module('feedbunch').service 'tourSvc',
 ['$http', 'timerFlagSvc', ($http, timerFlagSvc)->
+
+  #--------------------------------------------
+  # Media query to show the main app tour only in screens bigger than a smartphone
+  #--------------------------------------------
+  sm_min_media_query = 'screen and (min-width: 768px)'

   #--------------------------------------------
   # PRIVATE FUNCTION: Update show_main_tour flag for the current user with the passed value.
@@ -28,21 +33,23 @@
     # Show the main application tour.
     #---------------------------------------------
     show_main_tour: ->
-      now = new Date()
-      $http.get("/api/tour_i18n.json?time=#{now.getTime()}")
-      .success (data)->
-        tour =
-          id: 'main-tour',
-          showCloseButton: true,
-          showPrevButton: true,
-          showNextButton: true,
-          onEnd: dont_show_main_tour,
-          onClose: dont_show_main_tour,
-          i18n: data['i18n'],
-          steps: data['steps']
-        hopscotch.startTour tour
-      .error (data, status)->
-        timerFlagSvc.start 'error_loading_tour' if status!=0
+      # The main tour is only shown in screens bigger than a smartphone
+      enquire.register sm_min_media_query, ->
+        now = new Date()
+        $http.get("/api/tour_i18n.json?time=#{now.getTime()}")
+        .success (data)->
+          tour =
+            id: 'main-tour',
+            showCloseButton: true,
+            showPrevButton: true,
+            showNextButton: true,
+            onEnd: dont_show_main_tour,
+            onClose: dont_show_main_tour,
+            i18n: data['i18n'],
+            steps: data['steps']
+          hopscotch.startTour tour
+        .error (data, status)->
+          timerFlagSvc.start 'error_loading_tour' if status!=0

   return service


work on FileGroup class

work on FileGroup class

--- app/assets/javascripts/uploadcare/files/group.js.coffee
+++ app/assets/javascripts/uploadcare/files/group.js.coffee
@@ -11,6 +11,11 @@
     constructor: (settings) ->
       @settings = utils.buildSettings settings
       @__files = []
+
+      @finalized = false
+
+      @onFileAdded = $.Callbacks()
+      @onFileRemoved = $.Callbacks()

       @__uploadDf = $.Deferred()
       @__infoDf = $.Deferred()
@@ -37,15 +42,27 @@
       file for file in @__files # returns copy of @__files

     add: (file) ->
-      @__files.push file
-      file.progress (progressInfo) =>
-        @__fileProgresses[file] = progressInfo.progress
-        @__singleFileDf.notify @__progressInfo()
+      if file
+        @__files.push file
+        file.progress (progressInfo) =>
+          @__fileProgresses[file] = progressInfo.progress
+          @__singleFileDf.notify @__progressInfo()
+        @onFileAdded.fire file
+
+    removeAll: ->
+      @remove(file) for file in @__files
+
+    # creates copy of group, but not finalized
+    newGroup: ->
+      gr = new ns.FileGroup
+      gr.add(file) for file in @__files
+      gr

     remove: (file) ->
-      if (index = files.indexOf(file)) isnt -1
-        file.splice(index, 1)
+      if (index = @__files.indexOf(file)) isnt -1
+        @__files.splice(index, 1)
         # TODO unsubsribe progress
+        @onFileRemoved.fire file

     save: ->
       @__finalize()
@@ -61,10 +78,14 @@
           .fail =>
             @__infoDf.reject('info')

+    cancel: =>
+      @__finalize()
+      file.cancel() for file in @__files
+
     # returns object that act like single file
     asSingle: ->
       pr = @__singleFileDf.promise()
-      pr.cancel = @__cancel
+      pr.cancel = @cancel

     __progressInfo: ->
       progress = 0
@@ -75,9 +96,9 @@
       progress: if @__progressState == 'ready' then 1 else progress * 0.9

     __fileInfos: (cb) ->
-      $.when(@__files...).then(null, (errorsAndInfos...) ->
-        errorAndInfo[1] for errorAndInfo in errorsAndInfos
-      ).always cb
+      files = for file in @__files
+        file.when null, (err, info) -> $.when(info)
+      $.when(files...).done cb

     __buildInfo: (cb) ->
       info =
@@ -94,32 +115,27 @@
         cb(info)

     __finalize: ->
-      unless @__finalized
-        @__finalized = true
+      unless @finalized
+        @finalized = true
         @add = @remove = ->
           throw new Error("group can't be changed after save")
         $.when(@__files...)
           .then(@__uploadDf.resolve, @__uploadDf.reject)
         # if one file fails all fails
-        @__uploadDf.reject @__cancel
-
-    __cancel: =>
-      @__finalize()
-      file.cancel() for file in @__files
-
+        @__uploadDf.fail @cancel

     __createGroup: ->
       # tmp
       return $.when({group_id: '123~4'})

-      df = $.Deferred()
-      @__fileInfos (infos...) ->
-        data =
-          pub_key: @settings.publicKey
-        for info, i in infos
-          data["file_id[#{i}]"] = info.fileId
-        $.ajax("#{@settings.urlBase}/group/create/", {data, dataType: 'jsonp'})
-          .then(df.resolve, df.reject)
-      return df.promise()
+      # df = $.Deferred()
+      # @__fileInfos (infos...) ->
+      #   data =
+      #     pub_key: @settings.publicKey
+      #   for info, i in infos
+      #     data["file_id[#{i}]"] = info.fileId
+      #   $.ajax("#{@settings.urlBase}/group/create/", {data, dataType: 'jsonp'})
+      #     .then(df.resolve, df.reject)
+      # return df.promise()


Enable clamping of diagonals

Enable clamping of diagonals

--- app/scripts/components/controls/KeyboardControls.coffee
+++ app/scripts/components/controls/KeyboardControls.coffee
@@ -47,7 +47,7 @@
           movementMap[key] = value

     ship.addComponent('Multiway, Keyboard')
-      .multiway({ y: 400, x: 400 }, movementMap)
+      .multiway({ y: 400, x: 400 }, movementMap, clamp: yes)
       .bind('GamePause', (paused) ->
         if paused
           @disabledBeforePause = @disableControls


Added event logging to console.

Added event logging to console.

--- config/bookish-config.coffee
+++ config/bookish-config.coffee
@@ -71,7 +71,13 @@
       # so we never always include `marionette` and never assume Marionette is already loaded as a dependency.
       #
       #      init: -> ret = @Backbone.Marionette; delete @Backbone.Marionette; delete @Backbone; delete @_; ret
-      init: -> ret = @Backbone.Marionette; delete @Backbone.Marionette; delete @Backbone; ret
+      init: (_, Backbone) ->
+        trigger = Marionette.Controller.prototype.trigger
+        Marionette.Controller.prototype.trigger = ->
+          console.log arguments
+          trigger.apply(@,arguments)
+
+        ret = @Backbone.Marionette; delete @Backbone.Marionette; delete @Backbone; ret

     # ## UI Libraries


improve user message for env list

improve user message for env list

--- src/tf.coffee
+++ src/tf.coffee
@@ -209,4 +209,5 @@

     ekvs = [ "`#{projname}` env:" ]
     ekvs.push "  `#{k}` = `#{v}`" for k,v of localstorage
+    ekvs = [ "No environment variables." ] unless ekvs.length > 1
     return msg.send {room: msg.message.user.name}, ekvs.join "\n"


client/redux: make minor changes to payment service

Signed-off-by: Umut Sirin <4055abbc0e40a1254e715b952ccd414607e0b365@gmail.com>

--- client/app/lib/redux/services/payment.coffee
+++ client/app/lib/redux/services/payment.coffee
@@ -1,6 +1,8 @@
 _ = require 'lodash'
 makeHttpClient = require 'app/util/makeHttpClient'
 { pickData } = makeHttpClient.helpers
+
+{ Status } = require 'app/redux/modules/payment/constants'

 exports.client = client = makeHttpClient { baseURL: '/api/social/payment' }

@@ -54,12 +56,14 @@
 exports.fetchInfo = fetchInfo = ->
   client.get(Endpoints.Info).then ({ data: info }) ->
     # if status is trialing, use `trialInfo`
-    if info.subscription.status is 'trialing'
+    if info.subscription.status is Status.TRIALING
       info = _.assign(_.omit(info, 'trialInfo'), info.trialInfo)
     return info

 getTimestamp = (date) ->

-  Math.round (date.getTime() + (30 * 24 * 60 * 60 * 1000)) / 1000
+  thirtyDaysInMs = (30 * 24 * 60 * 60 * 1000)

+  Math.round (date.getTime() + thirtyDaysInMs) / 1000
+


Collaboration: watching logic improvements

--- client/ide/views/statusbar/avatarview.coffee
+++ client/ide/views/statusbar/avatarview.coffee
@@ -9,8 +9,16 @@

     super options, data

-    @intentTimer = null
-    @nickname    = @getOptions().origin
+    @intentTimer   = null
+    @nickname      = @getOptions().origin
+    { appManager } = KD.singletons
+
+    appManager.tell 'IDE', 'getCollaborationData', (collaborationData) =>
+
+      { watchMap } = collaborationData
+      isWatching  = watchMap.indexOf(@nickname) > -1
+
+      @setClass 'watching'  if isWatching

   click: (event) ->
@@ -115,20 +123,12 @@
       MENU.once 'KDObjectWillBeDestroyed', => MENU = null

-  setWatchState: (isWatching, nickname, item) ->
+  setWatchState: (shouldWatch, nickname) ->

-    isWatching = @latestWatchState or isWatching
-    methodName = 'watchParticipant'
-    menuLabel  = 'Unwatch'
-
-    if isWatching
-      methodName = 'unwatchParticipant'
-      menuLabel  = 'Watch'
+    @toggleClass 'watching'
+    methodName = if shouldWatch then 'watchParticipant' else 'unwatchParticipant'

     KD.singletons.appManager.tell 'IDE', methodName, nickname
-    item.updatePartial menuLabel
-
-    @latestWatchState = not isWatching

   destroy: ->


clarified license (just in case it wasn't obvious)

--- lib/esl.coffee
+++ lib/esl.coffee
@@ -1,3 +1,7 @@
+###
+(c) 2010 Stephane Alnet
+Released under the AGPL3 license
+###

 net         = require 'net'
 querystring = require 'querystring'


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -577,8 +577,8 @@
       #console.log 'ts: a', a
       #d.cx = Math.sin(a) * (radius - 75)
       #d.cy = -Math.cos(a) * (radius - 75)
-      d.cx = Math.sin(a) * ((radiuso - radiusi) / 2)
-      d.cy = -Math.cos(a) * ((radiuso - radiusi) / 2)
+      d.cx = Math.sin(a) * (radiuso - (radiuso - radiusi) / 2)
+      d.cy = -Math.cos(a) * (radiuso - (radiuso - radiusi) / 2)
       ### calculate the default position for the label,
          so that the middle of the label is centered in the arc
       ###


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -192,7 +192,7 @@
         if !data
           return

-        piedata = [data[0].label]
+        piedata = data[0].label
         console.log("update pie", piedata)

         $(@node).children(".title").text($(@node).attr("data-title"))


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -20,7 +20,7 @@
     width = 400 #width
     height = 400 #height
     radiuso = 200 #outer radius
-    radiusi = 100 #inner radius
+    radiusi = 120 #inner radius

     color = d3.scale.ordinal()
       #.domain([1,10])


Agent pie: start/end angle pie transition work

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -3,12 +3,12 @@
     @accessor 'data'

     constructor: ->
-        @instanceDataId = $(@node).attr('data-id')
+        #@instanceDataId = $(@node).attr('data-id')

     ready: ->
         #@testData = 123
         #@oldPieData = ''
-        #@instanceDataId = $(@node).attr('data-id')
+        @instanceDataId = $(@node).attr('data-id')
         #console.log('@instanceDataId',@instanceDataId)
         #@oldPieData[@instanceDataId] = ''
         window.oldPieData = window.oldPieData or {}


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -333,7 +333,8 @@
     labels.text((d) ->
       # Set the text *first*, so we can query the size
       # of the label with .getBBox()
-      d.value
+      #d.value
+      d.label
     ).each((d, i) ->
       # Move all calculations into the each function.
       # Position values are stored in the data object


--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -178,7 +178,7 @@
             #    b = i(t)
             #    return arc b
         #)
-        path.transition().duration(750).attrTween('d', (d) ->
+        path.transition().duration(750).attrTween('d', (d, i, a) ->
             `var i`
             i = d3.interpolate(this._current, d)
             this._current = i(0)


--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -169,7 +169,7 @@
         path.transition().duration(1000).attrTween('d', (d,i) ->
             theOldDataInPie = window.oldPieData[myInstanceDataId]
             console.log('theOldDataInPie in the tween',theOldDataInPie)
-            #console.log('@oldPieData in the tween',@oldPieData[@instanceDataId])
+            console.log('myInstanceDataId in the tween',myInstanceDataId)
             console.log('window.oldPieData[myInstanceDataId] in the tween',window.oldPieData[myInstanceDataId])
             console.log('window.oldPieData in the tween',window.oldPieData)
             #@testData = @testData + 1000


RemoteApi: check all types of methods signatures not only statics

--- workers/social/lib/social/remoteapi.coffee
+++ workers/social/lib/social/remoteapi.coffee
@@ -139,10 +139,9 @@

     type = if id then 'instance' else 'static'

-    if type is 'static'
-      unless Models[constructorName]?[method]
-        sendApiError res, { ok: false, error: 'No such method' }
-        return
+    unless Models[constructorName].getSignature type, method
+      sendApiError res, { ok: false, error: 'No such method' }
+      return

     [validCall, signatures] = Models[constructorName].testSignature type, method, args


Valid echonest library usage. Documents now have correct content from echonest..

--- start.coffee
+++ start.coffee
@@ -68,19 +68,18 @@
 					# Boolean to handle if we should query for that song ident..
 					next_query = true
 					if err
-						log "Couldn't perform search: #{err}"
 						next_query = false

 					if res.songs.length < 1
-						log "Couldn't find any matching songs."
 						next_query = false
+
+					log "#{_doc.artist}/#{_doc.title} .."

 					# If we weren't able to find the correct song on echonest, then simply save the doc we have..
 					if not next_query
 						runtime['db'].save _doc, ( err, res ) ->
 							if err
 								return cb err
-							log "#{_doc.title} by #{_doc.artist}"
 							return cb null

 						return
@@ -91,11 +90,9 @@
 							# Again, simple boolean flag regarding if we found the audio summary..
 							found_summary = true
 							if err
-								log "Couldn't get audio profile: #{err}"
 								found_summary = false

 							if res.songs.length < 1
-								log "Couldn't find song profile.."
 								found_summary = false

 							# Shove the results we got from the audio summary into the doc to save..
@@ -107,7 +104,6 @@
 							runtime['db'].save _doc, ( err, res ) ->
 								if err
 									return cb err
-								log "#{_doc.title by #{_doc.artist}"
 								return cb null

 		# This is the cb for async.each
@@ -186,7 +182,8 @@
 		# Get rate_limit by doing a quick http query to echonest and parsing the header..
 		rate_limit = 120

-		runtime['echonest'] = echonest.Echonest { "api_key": config['echonest_api_key'], "rate_limit": rate_limit }
+		runtime['echonest'] = new echonest.Echonest { "api_key": config['echonest_api_key'], "rate_limit": rate_limit }
+
 		return cb null

 	, ( cb ) ->


Make ajax calls zepto compatible

Make ajax calls zepto compatible

--- lib/assets/javascripts/firehose/long_poll.js.coffee
+++ lib/assets/javascripts/firehose/long_poll.js.coffee
@@ -43,7 +43,8 @@
     data.last_message_sequence = @_lastMessageSequence
     # TODO: Some of these options will be deprecated in jQuery 1.8
     #       See: http://api.jquery.com/jQuery.ajax/#jqXHR
-    $.ajax @config.longPoll.url,
+    $.ajax
+      url: @config.longPoll.url
       crossDomain:  true
       data:         data
       timeout:      @_timeout
@@ -70,7 +71,8 @@
     # Ping long poll server to verify internet connectivity
     # jQuery CORS doesn't support timeouts and there is no way to access xhr2 object
     # directly so we can't manually set a timeout.
-    $.ajax @config.longPoll.url,
+    $.ajax
+      url: @config.longPoll.url
       method: 'HEAD'
       crossDomain: true
       data: @config.params


Don't stop scanning on error

Don't stop scanning on error

--- lib/ymdp/javascripts/jquery/authorization.js.coffee
+++ lib/ymdp/javascripts/jquery/authorization.js.coffee
@@ -55,7 +55,7 @@
   confirm: User.confirm

   scan: ->
-    Debug.log("Authorize.scan")
+    Debug.log("BEGINNING Authorize.scan")
     if Authorize.stop_scanning
       Debug.log("Authorize.stop_scanning is true", Authorize.stop_scanning)
       window.clearInterval(Authorize.scanner)
@@ -66,10 +66,10 @@

     User.getState Authorize.scanResponse, (response) ->
       # error function
-      Debug.error("Error in Authorize.scan's getUserState", response)
+      Debug.error("Found Error in Authorize.scan's getUserState", response)

-      if Authorize.scanner
-        window.clearInterval(Authorize.scanner)
+      # if Authorize.scanner
+      #   window.clearInterval(Authorize.scanner)

   scanResponse: (response) ->
     Debug.log("inside Authorize.scan's getUserState callback", response)


Removed unused split and join #160

Removed unused split and join #160

--- dl/src/ecc/aes.coffee
+++ dl/src/ecc/aes.coffee
@@ -49,7 +49,7 @@

         new_checksum = hash.sha256 plaintext
         new_checksum = new_checksum.slice 0, 4
-        new_checksum = new_checksum.toString('binary').split("").join("")
+        new_checksum = new_checksum.toString('binary')

         unless checksum.toString('binary') is new_checksum
             throw new Error "Invalid key, could not decrypt message"
@@ -67,7 +67,7 @@
         ]
         # DEBUG console.log('... S',S.toString('hex'))
         checksum = hash.sha256(message).slice 0,4
-        checksum = checksum.toString('binary').split("").join("")
+        checksum = checksum.toString('binary')
         checksum = new Buffer(checksum, 'binary')
         payload = Buffer.concat [checksum, message]
         # DEBUG console.log('... payload',payload.toString())


Add helper method to cancel forms via js

--- app/assets/javascripts/boot.js.coffee
+++ app/assets/javascripts/boot.js.coffee
@@ -1,5 +1,8 @@

 window.OUT = {} unless window.OUT?
+
+OUT.cancelFormFor = (ele) ->
+  $(ele).parents("form").find("a.cancel").click()

 OUT.registerKeyboardShortcut = (key, cb) ->
   $('body').live "keypress", (event) ->
@@ -18,7 +21,7 @@
 $(window).load ->
   $('form input[type="text"]').live "keydown", (event) ->
     if event.keyCode == 27
-      $(this).parents("form").find("a.cancel").click()
+      OUT.cancelFormFor(this)
       event.stopImmediatePropagation()
       event.preventDefault()
       false


Cleaned out some old code

Cleaned out some old code

--- app/assets/javascripts/init.js.coffee
+++ app/assets/javascripts/init.js.coffee
@@ -48,16 +48,6 @@
       url: '/song_tags/-1'
       data: {"tag_id": tagElement.attr("data-tag-id"),"song_id": $(".song_tags").attr("data-song-id")},
       dataType: 'JSON'
-
-# filterBySongTag = (el) ->
-  # $(el.target).toggleClass "active"
-  # if $(".song_tag.active").length > 0
-  #   $("tr").hide()
-  #   $($(".song_tag.active").map( ->
-  #     "." + $(this).attr "data-tag-name"
-  #   ).get().join(",")).show()
-  # else
-  #   $("tr").show()

 ceAfterUpdate = (el) ->
   $(el).closest('table').removeClass 'table-hover'


Fix off by one error in the toolbar.

Fix off by one error in the toolbar.

@current and @alt_current must be between 1 and @nb(_alt)?_items but are
initialized to 0. Adjusting there value with arithmetic on boundary checking
leads to a OBOE (hit prev first). It's safer to reset the value to the lower
or upper bound.

--- app/assets/javascripts/toolbar.coffee
+++ app/assets/javascripts/toolbar.coffee
@@ -33,12 +33,12 @@

   next_item: =>
     @current += 1
-    @current -= @nb_items  if @current > @nb_items
+    @current = 1 if @current > @nb_items
     @go_to_current()

   prev_item: =>
     @current -= 1
-    @current += @nb_items  if @current <= 0
+    @current = @nb_items  if @current <= 0
     @go_to_current()

   go_to_current: ->
@@ -70,12 +70,12 @@

   alt_next_item: =>
     @alt_current += 1
-    @alt_current -= @nb_alt_items  if @alt_current > @nb_alt_items
+    @alt_current = 1  if @alt_current > @nb_alt_items
     @go_to_alt_current()

   alt_prev_item: =>
     @alt_current -= 1
-    @alt_current += @nb_alt_items  if @alt_current <= 0
+    @alt_current = @nb_alt_items  if @alt_current <= 0
     @go_to_alt_current()

   go_to_alt_current: ->


fix(kanban): no load kanban

fix(kanban): no load kanban

--- app/coffee/modules/kanban/main.coffee
+++ app/coffee/modules/kanban/main.coffee
@@ -462,7 +462,7 @@
         @.loadKanban().then () =>
             @timeout () =>
                 @.initialLoad = true
-            , 0, false
+            , 0, true

         @.generateFilters()


Wait until user is logged-in to add message listener

* wait until user is logged-in to add message listener

* use Tracker rather than the onLogin event

--- packages/rocketchat-ui/lib/RoomManager.coffee
+++ packages/rocketchat-ui/lib/RoomManager.coffee
@@ -38,12 +38,14 @@
 	ChatMessage.remove _id: msg._id

-RocketChat.Notifications.onUser 'message', (msg) ->
-	msg.u =
-		username: 'rocketbot'
-	msg.private = true
-
-	ChatMessage.upsert { _id: msg._id }, msg
+Tracker.autorun ->
+	if Meteor.userId()
+		RocketChat.Notifications.onUser 'message', (msg) ->
+			msg.u =
+				username: 'rocketbot'
+			msg.private = true
+
+			ChatMessage.upsert { _id: msg._id }, msg

 @RoomManager = new class


sending all events to particles

sending all events to particles

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -28,7 +28,7 @@
   @methodOf TimedEvents#
   @param {Number} n Number of frames to wait before executing the callback
   @param {Function} fn Code to execute after n frames has passed
-  ###
+  ###
   every: (n, fn) ->
     while I.everyEventLastFired
       fn()


Reformat

Reformat

--- app/js/controllers/preferences.coffee
+++ app/js/controllers/preferences.coffee
@@ -1,8 +1,8 @@
 angular.module("app").controller "PreferencesController", ($scope, $location, Wallet, Shared, Growl) ->
-	$scope.timeout = Wallet.timeout
+    $scope.timeout = Wallet.timeout

-	$scope.updatePreferences = ->
-		Wallet.set_setting('timeout', $scope.timeout).then (r) ->
-			console.log('t sumbitted')
-			Shared.timeout=$scope.timeout
-			Growl.notice "", "Preferences Updated"+    $scope.updatePreferences = ->
+        Wallet.set_setting('timeout', $scope.timeout).then (r) ->
+            console.log('t sumbitted')
+            Shared.timeout=$scope.timeout
+            Growl.notice "", "Preferences Updated"


tableverse/shape: Fix bug updating index during remove.

--- Oghma/tableverse/shape.coffee
+++ Oghma/tableverse/shape.coffee
@@ -67,7 +67,7 @@
       @__k.setAttrs( attrs )

     remove: ( thingy ) ->
-      thingyverse.dice.remove( thingy )
+      thingyverse.shapes.remove( thingy )
       super thingy

   thingyverse.shapes = new Heron.Index.MapIndex( 'owner' )


fixing the itallics in the new Acknowledgements page

added in the missing * at the end of the acknowledgements statement. Only one * on the left. Added in the right one.

--- app/pages/about/acknowledgements.cjsx
+++ app/pages/about/acknowledgements.cjsx
@@ -8,7 +8,7 @@
     ## Acknowledging the Zooniverse
     Per the [Zooniverse Project Builder Policies](/lab-policies), all research publications using any data derived from Zooniverse approved projects (those listed on the [Zooniverse Projects page](/projects)) are required to acknowledge the Zooniverse and the Project Builder platform. To do so, please use the following text:

-    *This publication uses data generated via the [Zooniverse.org](https://www.zooniverse.org/) platform, development of is which funded by generous support, including a Global Impact Award from Google, and by a grant from the Alfred P. Sloan Foundation.
+    *This publication uses data generated via the [Zooniverse.org](https://www.zooniverse.org/) platform, development of is which funded by generous support, including a Global Impact Award from Google, and by a grant from the Alfred P. Sloan Foundation.*

     We ask that all researchers making use of the Zooniverse Project Builder platform in any way also consider including the above acknowledgement in their publications.


Fix vote buttons when results not shown

Fix vote buttons when results not shown

--- vue/src/shared/models/poll_model.coffee
+++ vue/src/shared/models/poll_model.coffee
@@ -68,8 +68,7 @@
     @hasMany   'versions'

   pollOptions: ->
-    ids = @results.map((o) -> o.id).filter( (id) -> id != 0)
-    options = (@recordStore.pollOptions.collection.chain().find(pollId: @id, id: {$in:ids}).data())
+    options = (@recordStore.pollOptions.collection.chain().find(pollId: @id, id: {$in: @pollOptionIds}).data())
     orderBy(options, 'priority')

   pollOptionsForVoting: ->


Fix whitespace

Fix whitespace

--- client/account/lib/views/accounteditshortcutsrow.coffee
+++ client/account/lib/views/accounteditshortcutsrow.coffee
@@ -3,13 +3,13 @@
 facade = require('./accounteditshortcutsfacade')
 EventType = require './accounteditshortcutseventtype'
 recorder = require 'record-shortcuts'
-{ presentBinding } = require 'app/shortcutscontroller'
+{ presentBinding } = require 'app/shortcutscontroller'

 module.exports =

 class AccountEditShortcutsRow extends kd.View

-  # Class name for columns.
+  # Class name for columns.
   COL_CLASS_NAME = 'col'

   # Class name to set for currently recording item.
@@ -21,13 +21,13 @@
   # Class name to set for duplicate/colliding items.
   DUP_CLASS_NAME = 'collides'

-  # Class name that we use to catch cancel click.
+  # Class name that we use to catch cancel click.
   CANCEL_CLASS_NAME = 'cancel'

   # The maximum description string length.
   DESCRIPTION_TRUNC_LEN = 30

-  # The separator pattern to truncate to.
+  # The separator pattern to truncate to.
   DESCRIPTION_TRUNC_SEP = ' '

   CLICK = 'click'
@@ -87,7 +87,7 @@
       unless silent
         @emit EventType.Item.TOGGLED, @_enabled

-    # Handles dom click events.
+    # Handles dom click events.
     #
     clickHandler = (e) =>
       if @_active
@@ -130,7 +130,7 @@
         binding.updatePartial presentBinding @_binding

     # Handles Facade.DUP, which is fired on every change made.
-    #
+    #
     # Passed value determines if this row's binding is colliding with some other binding or not.
     #
     dupHandler = (dup) =>


Client: Activity: Tests: updated TestUtils source  'react-addons-test-utils'

--- client/activity/lib/components/appcomponent/test.coffee
+++ client/activity/lib/components/appcomponent/test.coffee
@@ -1,7 +1,7 @@
 React                = require 'react/addons'
 expect               = require 'expect'
 ActivityAppComponent = require '../appcomponent'
-{ TestUtils }        = React.addons
+TestUtils            = require 'react-addons-test-utils'

 describe 'ActivityAppComponent', ->


NFinderItem: Use string interpolation of CoffeeScript

--- client/finder/lib/filetree/itemviews/nfinderitem.coffee
+++ client/finder/lib/filetree/itemviews/nfinderitem.coffee
@@ -109,7 +109,7 @@
       @callback? newValue
       @resetView()

-    ext = '.' + FSHelper.getFileExtension data.name
+    ext = ".#{FSHelper.getFileExtension data.name}"

     if (index = data.name.indexOf ext) > 0
       @renameView.input.getElement().setSelectionRange 0, index


removing test strata mapping

removing test strata mapping

--- src/hem.coffee
+++ src/hem.coffee
@@ -70,8 +70,6 @@
     if fs.existsSync(@options.testPublic)
       strata.map @options.testPath, (app) =>
         app.get(@options.specsPath, @specsPackage().createServer())
-        app.get("", (env, callback) ->
-          callback(200, 'Content-Type':'text', 'hmmm'))
         app.use(strata.file, @options.testPublic, ['index.html', 'index.htm'])

     # start server


Adding changes for entering and leaving room from @pboos

--- src/irc.coffee
+++ src/irc.coffee
@@ -47,6 +47,19 @@
       console.log('left %s', channel)

       self.receive new LeaveMessage(null)
+
+  createUser: (channel, from) ->
+      user = @userForName from
+      unless user?
+        id = (new Date().getTime() / 1000).toString().replace('.','')
+        user = @userForId id
+        user.name = from
+
+      if channel.match(/^[&#]/)
+        user.room = channel
+      else
+        user.room = null
+      user

   kick: (channel, client, message) ->
     @bot.emit 'raw',
@@ -103,17 +116,10 @@
     bot.addListener 'message', (from, to, message) ->
       console.log "From #{from} to #{to}: #{message}"

-      user = self.userForName from
-      unless user?
-        id = (new Date().getTime() / 1000).toString().replace('.','')
-        user = self.userForId id
-        user.name = from
-
-      if to.match(/^[&#]/)
-        user.room = to
+      user = self.createUser to, from
+      if user.room
         console.log "#{to} <#{from}> #{message}"
       else
-        user.room = null
         console.log "msg <#{from}> #{message}"

       self.receive new TextMessage(user, message)
@@ -127,14 +133,14 @@
     bot.addListener 'join', (channel, who) ->
         console.log('%s has joined %s', who, channel)

-        user = self.userForName who
-        self.receive new EnterMessage(user)
+        user = self.createUser channel, who
+        self.receive new Robot.EnterMessage(user)

     bot.addListener 'part', (channel, who, reason) ->
         console.log('%s has left %s: %s', who, channel, reason)

-        user = self.userForName who
-        self.receive new LeaveMessage(user)
+        user = self.createUser channel, who
+        self.receive new Robot.LeaveMessage(user)

     bot.addListener 'kick', (channel, who, _by, reason) ->
         console.log('%s was kicked from %s by %s: %s', who, channel, _by, reason)
@@ -153,4 +159,3 @@

 exports.use = (robot) ->
   new IrcBot robot
-


Moved to local modals.

Moved to local modals.

--- app/assets/javascripts/app/controllers/_channel/email.js.coffee
+++ app/assets/javascripts/app/controllers/_channel/email.js.coffee
@@ -64,11 +64,16 @@

   new: (e) =>
     e.preventDefault()
-    new App.ChannelEmailFilterEdit( {} )
+    new App.ChannelEmailFilterEdit(
+      container: @el.closest('.content')
+    )

   edit: (id, e) =>
     e.preventDefault()
-    new App.ChannelEmailFilterEdit( object: App.PostmasterFilter.find(id) )
+    new App.ChannelEmailFilterEdit(
+      object:    App.PostmasterFilter.find(id)
+      container: @el.closest('.content')
+    )

 class App.ChannelEmailFilterEdit extends App.ControllerModal
   constructor: ->
@@ -152,12 +157,17 @@

   new: (e) =>
     e.preventDefault()
-    new App.ChannelEmailAddressEdit( {} )
+    new App.ChannelEmailAddressEdit(
+      container: @el.closest('.content')
+    )

   edit: (id, e) =>
     e.preventDefault()
     item = App.EmailAddress.find(id)
-    new App.ChannelEmailAddressEdit( object: item )
+    new App.ChannelEmailAddressEdit(
+      object:    item
+      container: @el.closest('.content')
+    )

 class App.ChannelEmailAddressEdit extends App.ControllerModal
   constructor: ->
@@ -238,12 +248,17 @@

   new: (e) =>
     e.preventDefault()
-    new App.ChannelEmailSignatureEdit( {} )
+    new App.ChannelEmailSignatureEdit(
+      container: @el.closest('.content')
+    )

   edit: (id, e) =>
     e.preventDefault()
     item = App.Signature.find(id)
-    new App.ChannelEmailSignatureEdit( object: item )
+    new App.ChannelEmailSignatureEdit(
+      object:    item
+      container: @el.closest('.content')
+    )

 class App.ChannelEmailSignatureEdit extends App.ControllerModal
   constructor: ->
@@ -324,12 +339,17 @@

   new: (e) =>
     e.preventDefault()
-    new App.ChannelEmailInboundEdit( {} )
+    new App.ChannelEmailInboundEdit(
+      container: @el.closest('.content')
+    )

   edit: (id, e) =>
     e.preventDefault()
     item = App.Channel.find(id)
-    new App.ChannelEmailInboundEdit( object: item )
+    new App.ChannelEmailInboundEdit(
+      object:    item
+      container: @el.closest('.content')
+    )

 class App.ChannelEmailInboundEdit extends App.ControllerModal


Limit to 10 autocomplete results.

Limit to 10 autocomplete results.

Use the typeahead's builtin matching engine for better results too.

--- app/assets/javascripts/components/typeahead_component.js.coffee
+++ app/assets/javascripts/components/typeahead_component.js.coffee
@@ -5,15 +5,22 @@
   sourceList: []

   didInsertElement: ->
+    engine = new Bloodhound
+      name: 'schools'
+      local: @get('sourceList').map (str) ->
+        {value: str}
+      datumTokenizer: (d) ->
+        Bloodhound.tokenizers.whitespace(d.value)
+      queryTokenizer: Bloodhound.tokenizers.whitespace
+      limit: 10
+
+    engine.initialize()
+
     @.$().typeahead({
       hint: true,
       highlight: true,
-      minLength: 1
-    }, {
-      name: 'schools',
-      displayKey: 'value',
-      source: @substringMatcher(@get('sourceList'))
-    })
+      minLength: 1,
+    }, {source: engine.ttAdapter(), displayKey: 'value'})

   substringMatcher: (strs)->
     (q, cb) ->


Fixes: #2118

Fixes: #2118

--- app/assets/javascripts/d3/merit_order_hourly_flexibility.coffee
+++ app/assets/javascripts/d3/merit_order_hourly_flexibility.coffee
@@ -23,7 +23,7 @@
       @drawChart()
       @dateSelect.setVal(1)

-      @drawLegend(@series)
+      @drawLegend(@series.concat(@model.target_series()))

       defs = @svg.append('defs')
       defs.append('clipPath')


Set initial cursor position to first intended code insertion point instead of end of sample code. Don't add newline to end of sample code if last line was all whitespace (like in an indented while loop).

--- app/views/play/level/tome/SpellView.coffee
+++ app/views/play/level/tome/SpellView.coffee
@@ -234,7 +234,7 @@
         if @aceSession.selection.isEmpty()
           cursor = @ace.getCursorPosition()
           line = @aceDoc.getLine(cursor.row)
-          if delimMatch = line.substring(cursor.column).match /^(["|']?\)+;?)/  # Yay for editors misreading regexes: "
+          if delimMatch = line.substring(cursor.column).match /^(["|']?\)+;?)/
             newRange = @ace.getSelectionRange()
             newRange.setStart newRange.start.row, newRange.start.column + delimMatch[1].length
             newRange.setEnd newRange.end.row, newRange.end.column + delimMatch[1].length
@@ -621,7 +621,7 @@
     return if @destroyed
     lineCount = @aceDoc.getLength()
     lastLine = @aceDoc.$lines[lineCount - 1]
-    if lastLine isnt ''
+    if /\S/.test lastLine
       cursorPosition = @ace.getCursorPosition()
       wasAtEnd = cursorPosition.row is lineCount - 1 and cursorPosition.column is lastLine.length
       @aceDoc.insertNewLine row: lineCount, column: 0  #lastLine.length
@@ -958,7 +958,7 @@
     currentLine = _.string.rtrim(@aceDoc.$lines[cursorPosition.row].replace(@singleLineCommentRegex(), ''))  # trim // unless inside "
     endOfLine = cursorPosition.column >= currentLine.length  # just typed a semicolon or brace, for example
     beginningOfLine = not currentLine.substr(0, cursorPosition.column).trim().length  # uncommenting code, for example
-    incompleteThis = /^(s|se|sel|self|t|th|thi|this)$/.test currentLine.trim()
+    incompleteThis = /^(s|se|sel|self|t|th|thi|this|g|ga|gam|game|h|he|her|hero)$/.test currentLine.trim()
     #console.log "finished=#{valid and (endOfLine or beginningOfLine) and not incompleteThis}", valid, endOfLine, beginningOfLine, incompleteThis, cursorPosition, currentLine.length, aether, new Date() - 0, currentLine
     if not incompleteThis and @options.level.isType('game-dev')
       # TODO: Improve gamedev autocast speed
@@ -1234,6 +1234,9 @@
         unless seenAnEntryPoint
           session.addGutterDecoration index, 'next-entry-point'
           seenAnEntryPoint = true
+          unless @hasSetInitialCursor
+            @hasSetInitialCursor = true
+            @ace.navigateTo index, line.match(/\S/)?.index ? line.length

         # Shift pointer right based on current indentation
         # TODO: tabs probably need different horizontal offsets than spaces


#13 Refactor public API abstractions.

#13 Refactor public API abstractions.

We need to expose completely different abstractions than what we've done so far. But it would be nice not to break currently existing code.

Introducing sockjs.ServerInstance, but sockjs.Server should still work as previously defined.

--- src/sockjs.coffee
+++ src/sockjs.coffee
@@ -51,7 +51,7 @@
 utils.objectExtend(App.prototype, trans_htmlfile.app)

-class Server extends events.EventEmitter
+class ServerInstance extends events.EventEmitter
     constructor: (user_options) ->
         @options =
             prefix: ''
@@ -59,20 +59,16 @@
             origins: ['*:*']
             disabled_transports: []
             jsessionid: true
-        if @options.sockjs_url
-            throw new Error("options.sockjs_url is required!")
         if user_options
             utils.objectExtend(@options, user_options)

-    installHandlers: (http_server, user_options) ->
-        options = {}
-        utils.objectExtend(options, @options)
-        if user_options
-            utils.objectExtend(options, user_options)
+    installHandlers: (http_server) ->
+        if not @options.sockjs_url
+            throw new Error('Option "sockjs_url" is required!')
         console.log('SockJS v' + sockjs_version() + ' ' +
-                    'started on ' + JSON.stringify(options.prefix))
+                    'bound to ' + JSON.stringify(@options.prefix))

-        p = (s) => new RegExp('^' + options.prefix + s + '[/]?$')
+        p = (s) => new RegExp('^' + @options.prefix + s + '[/]?$')
         t = (s) => [p('/([^/.]+)/([^/.]+)' + s), 'server', 'session']
         opts_filters = ['h_sid', 'xhr_cors', 'cache_for', 'xhr_options', 'expose']
         dispatcher = [
@@ -91,8 +87,8 @@
             ['GET',     t('/eventsource'), ['h_sid', 'h_no_cache', 'eventsource']],
             ['GET',     t('/htmlfile'),    ['h_sid', 'h_no_cache', 'htmlfile']],
         ]
-        maybe_add_transport = (name, urls) ->
-            if options.disabled_transports.indexOf(name) isnt -1
+        maybe_add_transport = (name, urls) =>
+            if @options.disabled_transports.indexOf(name) isnt -1
                 # modify urls to return 404
                 urls = for url in urls
                     [method, url, filters] = url
@@ -113,7 +109,7 @@
                 return false
             ee.addListener(event, new_handler)

-        path_regexp = new RegExp('^' + options.prefix  + '([/].+|[/]?)$')
+        path_regexp = new RegExp('^' + @options.prefix  + '([/].+|[/]?)$')
         handler = (req, res, extra) =>
             if not req.url.match(path_regexp)
                 return false
@@ -125,10 +121,42 @@
         return true

+class ServerDeprecatedWrapper
+    constructor: (server_options) ->
+        @listeners = {}
+        @options = {}
+        if server_options
+            utils.objectExtend(@options, server_options)
+
+    addListener: (event, listener) ->
+        if @installed
+            throw Error('Don\'t add listeners after "installHandler" was run.')
+        if not (event of @listeners)
+            @listeners[event] = []
+        @listeners[event].push(listener)
+
+    installHandlers: (http_server, user_options) ->
+        @installed = true
+        options = {}
+        utils.objectExtend(options, @options)
+        if user_options
+            utils.objectExtend(options, user_options)
+        srv = new ServerInstance(options)
+        for event of @listeners
+            for listener in @listeners[event]
+                srv.addListener(event, listener)
+        srv.installHandlers(http_server)
+        return srv
+
+ServerDeprecatedWrapper.prototype.on = \
+    ServerDeprecatedWrapper.prototype.addListener
+
+
 sockjs_version = ->
     try
         package = fs.readFileSync(__dirname + '/../package.json', 'utf-8')
     catch x
     return if package then JSON.parse(package).version else null

-exports.Server = Server
+exports.Server = ServerDeprecatedWrapper
+exports.ServerInstance = ServerInstance


Adding comments.

Adding comments.

--- src/timber.coffee
+++ src/timber.coffee
@@ -165,8 +165,8 @@
         @logger = new timber.Logger("timber.Environment")
         @logger.debug("Initializing")

-        @density = 10  # The density of the environment's medium.
-        @gravitationalConstant = 0.5
+        @density = 10              # The density of the environment's medium.
+        @gravitationalConstant = 3 # The strength of the environment's gravity.

     # Update the elements with the effects of the given number of milliseconds
@@ -219,7 +219,8 @@
     #
     # @param element {Object}
     gravity : (element) ->
-        force = new timber.Vector(0, @gravitationalConstant)
+        # FIXME: technically, we should add drag as well.
+        return new timber.Vector(0, @gravitationalConstant)

 #


webapp/editor html-md: fixing localize_image_links to respect the base url and also to deal with empty file paths

--- src/smc-webapp/editor-html-md/editor-html-md.coffee
+++ src/smc-webapp/editor-html-md/editor-html-md.coffee
@@ -526,22 +526,16 @@
                 @update_preview()

     localize_image_links: (e) =>
-        # make relative links to images use the raw server
-        for x in e.find("img")
-            y = $(x)
-            src = y.attr('src')
-            if not src? or src[0] == '/' or src.indexOf('://') != -1
-                continue
-            new_src = "/#{@project_id}/raw/#{@file_path()}/#{src}"
-            y.attr('src', new_src)
-        # make relative links to objects use the raw server
-        for x in e.find("object")
-            y = $(x)
-            src = y.attr('data')
-            if not src? or src[0] == '/' or src.indexOf('://') != -1
-                continue
-            new_src = "/#{@project_id}/raw/#{@file_path()}/#{src}"
-            y.attr('data', new_src)
+        {join} = require('path')
+        # make relative links to images and objects use the raw server
+        for [tag, attr] in [['img', 'src'], ['object', 'data']]
+            for x in e.find(tag)
+                y = $(x)
+                src = y.attr(attr)
+                if not src? or src[0] == '/' or src.indexOf('://') != -1
+                    continue
+                new_src = join('/', window.smc_base_url, @project_id, 'raw', @file_path(), src)
+                y.attr(attr, new_src)

     init_preview_select: () =>
         @preview_content.click (evt) =>


Fix `submit:prepare` trigger as a result of mouse click

Fixes #31

--- prepare.coffee
+++ prepare.coffee
@@ -36,8 +36,9 @@
   # preDispatch is a new hook added in 1.7.2. Its not documented as
   # a real public API, but we'll abuse it anyway.
   preDispatch = (event) ->
+    timestamp = "#{event.type}:" + event.timeStamp
     # Check if this event has dispatched a prepare event already
-    if event.timeStamp isnt lastPreparedTimestamp
+    if timestamp isnt lastPreparedTimestamp
       # Reuse the existing event instead of creating a new copy. Any
       # calls to preventDefault or stopPropagation will take
       # immediate effect.
@@ -47,7 +48,7 @@
       # Restore the old event type
       event.type = origType
       # Mark event's timestamp id as prepared
-      lastPreparedTimestamp = event.timeStamp
+      lastPreparedTimestamp = timestamp
     return

   # Install stub prepare handler to ensure preDispatch is invoked


the checkpoint marker blinks (fadeout and in) when a student registers a rating

--- app/assets/javascripts/analytics.js.coffee
+++ app/assets/javascripts/analytics.js.coffee
@@ -19,8 +19,8 @@

     #update student view
     marker = $("#checkpoint#{checkpoint}").find('.marker')
-    marker.removeClass('checkpoint_0 checkpoint_1 checkpoint_2')
-    marker.addClass("checkpoint_#{current_score}")
+    marker.removeClass('checkpoint_0 checkpoint_1 checkpoint_2').fadeOut ->
+      marker.addClass("checkpoint_#{current_score}").fadeIn()

 getScores = (ratings) ->
   zeroCount = 0


OX-609 fixed on click handler which was removed after the ajax call

--- app/assets/javascripts/main/routing.coffee
+++ app/assets/javascripts/main/routing.coffee
@@ -149,7 +149,7 @@

     "admin.user.userAdministration" : ->

-      $("td").on "click", ".label-experience", (event) ->
+      $("form").on "click", ".label-experience", (event) ->
         values = $(this).html().split(" ")
         if values
           $("input[name=experience-domain]").val(values[0])


fix bulk issues

fix bulk issues

--- app/coffee/modules/resources/issues.coffee
+++ app/coffee/modules/resources/issues.coffee
@@ -36,7 +36,7 @@

     service.bulkCreate = (projectId, data) ->
         url = $urls.resolve("bulk-create-issues")
-        params = {projectId: projectId, bulkIssues: data}
+        params = {project_id: projectId, bulk_issues: data}
         return $http.post(url, params)

     service.stats = (projectId) ->


standardize song creation

standardize song creation

--- app/frontend/scripts/application.js.coffee
+++ app/frontend/scripts/application.js.coffee
@@ -7,6 +7,14 @@
   url: '/now_playing',
   dataType: 'json',
   success: (response) ->
-    song   = new Song(response.name, response.artist, response.album)
+    song   = songFromJson(response)
     stache = Mustache.to_html(templates.now_playing,song,templates)
-    $('#now-playing').html(stache)+    $('#now-playing').html(stache)
+
+# Takes a JSON response and parses it for our common Song attributes.
+#
+# json - The common JSON endpoint we return.
+#
+# Returns a Song.
+songFromJson = (json) ->
+  new Song(json.name, json.artist, json.album)


Aborting flow execution when factored model/view is null.

--- www/src/theoricus/mvc/controller.coffee
+++ www/src/theoricus/mvc/controller.coffee
@@ -22,6 +22,7 @@

       model_name = controller_name.singularize()
       @the.factory.model model_name, null, (model)=>
+        return unless model?

         view_folder = controller_name
         view_name   = action_name
@@ -44,6 +45,7 @@
       fn view
     else
       @the.factory.view path, @process, ( view )=>
+        return unless view?
         @_render_view path, data, el, view
         fn view


add door info to room defs

add door info to room defs

--- src/javascript/game/map/room_defs.coffee
+++ src/javascript/game/map/room_defs.coffee
@@ -24,6 +24,9 @@
   ]
   items: [
   ]
+  doors: [
+    ['leftExit', 0x0, 0x5]
+  ]

 # hall, door on right
 RoomDefs[0x13] =
@@ -39,6 +42,9 @@
     # [0xF,0x5, 0xF0] # XXX stand-in for the door
   ]
   items: [
+  ]
+  doors: [
+    ['rightExit', 0xF, 0x5]
   ]

 # Skree hall


fix browserify support for async parsing

--- src/xml2js.coffee
+++ src/xml2js.coffee
@@ -5,6 +5,7 @@
 builder = require 'xmlbuilder'
 bom = require './bom'
 processors = require './processors'
+global.setImmediate = require('timers').setImmediate

 # Underscore has a nice function for this, but we try to go without dependencies
 isEmpty = (thing) ->


Pad documentation

Pad documentation

--- src/window.coffee
+++ src/window.coffee
@@ -16,7 +16,7 @@

     @param 1 name of the property to retrieve
     @return the object with the given name or any object with
-        a vendor-prefixed variation of the given name
+            a vendor-prefixed variation of the given name
 ###

 # Possible javascript vendor prefixes


[grunt] add url of grunt-gray-matter to docs

--- tasks/data.coffee
+++ tasks/data.coffee
@@ -7,7 +7,7 @@

   ###
   Gray Matter
-  /modules/grunt-gray-matter
+  https://www.npmjs.com/package/grunt-gray-matter
   Extract data from specified files with Gray Matter
   ###


test: Update 'contains an AuthnContext if requested'

This provides more context for failing the case where Comparison=exact is not
found as an attribute on the target node.

--- test/saml2.coffee
+++ test/saml2.coffee
@@ -51,7 +51,7 @@
         authn_request = dom.getElementsByTagName('AuthnRequest')[0]

         requested_authn_context = authn_request.getElementsByTagNameNS('urn:oasis:names:tc:SAML:2.0:protocol', 'RequestedAuthnContext')[0]
-        assert _(requested_authn_context.attributes).some (attr) -> attr.name is 'Comparison' and attr.value is 'exact'
+        assert _(requested_authn_context.attributes).some((attr) -> attr.name is 'Comparison' and attr.value is 'exact'), "Could not determine if specified attribute had proper value (Comparison=exact)"
         assert.equal requested_authn_context.getElementsByTagNameNS('urn:oasis:names:tc:SAML:2.0:assertion', 'AuthnContextClassRef')[0].firstChild.data, 'context:class'


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/state.coffee
+++ test/state.coffee
@@ -8,3 +8,5 @@
   animation.transition('run')

   equals animation.currentState(), "run"
+
+


Working errors from ace worker

Working errors from ace worker

--- src/js/app/editor.coffee
+++ src/js/app/editor.coffee
@@ -1,7 +1,6 @@
 $ = require 'ejquery'
 ace = require 'ace/ace'
 Prelude = require 'vendor/prelude/prelude-browser-min'
-CodeMirror = require 'vendor/codemirror/codemirror'
 TimeLine = require 'app/UniqueTimeLine'
 Commands = require 'app/Commands'
 History = require 'app/History'
@@ -191,7 +190,7 @@
         setCurrentMessage modesList(), "modesList"
       else
         log "#{name} compiler loaded"
-      compileCode()
+      # compileCode()
       callback?()
     , (error) ->
       log "#{name} loading failed"
@@ -249,7 +248,7 @@
   sourceCompiled = false
   sourceChanged = true
   history.add e
-  return unless autoCompile
+  return #unless autoCompile
   DELAY = 700
   lastHit = +new Date
   setTimeout ->
@@ -406,22 +405,10 @@
   else
     log output

-CodeMirror.keyMap.commandLine =
-  Up: "doNothing"
-  Down: "doNothing"
-  PageUp: "doNothing"
-  PageDown: "doNothing"
-  Enter: "doNothing"
-  fallthrough: "default"
-
-CodeMirror.commands.doNothing = (cm) ->
-  true
-
 outputScrollTop = ->
   $("#rightColumn").animate
     scrollTop: 0
   , $("#rightColumn").scrollTop() / 10
-

 defaultEditor = ->
   winSize =
@@ -485,12 +472,23 @@

 sourceArea = ace.edit 'sourceArea'
 sourceArea.setTheme "ace/theme/cobalt"
-sourceArea.getSession().setMode "compilers/coffeescript/mode"
+sourceArea.session.setMode "compilers/coffeescript/mode"
+sourceArea.session.on 'changeMode', ->
+  sourceArea.session.$worker.on 'ok', ({data: {result}}) ->
+    saveCurrent()
+    compiledJS = result
+    hideError "compiler", "runtime"
+    sourceCompiled = true
+    # $("#repl_permalink").attr "href", "##{sourceFragment}#{encodeURIComponent(source)}"
+
+  sourceArea.session.$worker.on 'error', ({data: {text}}) ->
+    showErrorMessage "compiler", "Compiler: #{text}"
+
 sourceArea.setHighlightActiveLine true
-sourceArea.getSession().setTabSize 2
+sourceArea.session.setTabSize 2
 sourceArea.setShowPrintMargin false

-sourceArea.getSession().on 'change', sourceChange
+sourceArea.session.on 'change', sourceChange

 sourceArea.commands.addCommand
   name: 'leave'
@@ -500,7 +498,7 @@

 commandArea = ace.edit 'commandArea'
 commandArea.setTheme "ace/theme/cobalt"
-commandArea.getSession().setMode "compilers/coffeescript/mode"
+commandArea.session.setMode "compilers/coffeescript/mode"
 commandArea.setHighlightActiveLine false
 commandArea.setShowPrintMargin false
 commandArea.renderer.setShowGutter false


Keep track of outport bracket context

Keep track of outport bracket context

--- src/lib/Component.coffee
+++ src/lib/Component.coffee
@@ -228,13 +228,14 @@
     return

   getBracketContext: (type, port, scope, idx) ->
-    portname = port
-    if @inPorts[port].isAddressable()
-      portname = "#{port}[#{idx}]"
+    {name, index} = ports.normalizePortName port
+    portsList = if type is 'in' then @inPorts else @outPorts
+    if portsList[name].isAddressable() and idx
+      port = "#{port}[#{idx}]"
     # Ensure we have a bracket context for the current scope
-    @bracketContext[type][portname] = {} unless @bracketContext[type][portname]
-    @bracketContext[type][portname][scope] = [] unless @bracketContext[type][portname][scope]
-    return @bracketContext[type][portname][scope]
+    @bracketContext[type][port] = {} unless @bracketContext[type][port]
+    @bracketContext[type][port][scope] = [] unless @bracketContext[type][port][scope]
+    return @bracketContext[type][port][scope]

   addToResult: (result, port, ip, before = false) ->
     {name, index} = ports.normalizePortName port
@@ -257,7 +258,12 @@
       return unless @isForwardingOutport inport, name
       # We have already forwarded this context to this outport
       return unless ctx.ports.indexOf(outport) is -1
-      forwardable.unshift ctx
+      # See if we have already forwarded the same bracket from another
+      # inport
+      outContext = @getBracketContext('out', name, ctx.ip.scope, index)[idx]
+      if outContext
+        return if outContext.ip.data is ctx.ip.data and outContext.ports.indexOf(outport) isnt -1
+      forwardable.push ctx
     return forwardable

   addBracketForwards: (result) ->
@@ -268,6 +274,7 @@
         for port in context.ports
           ipClone = context.closeIp.clone()
           @addToResult result, port, ipClone, true
+          @getBracketContext('out', port, ipClone.scope, ipClone.index).pop()

     if result.__bracketContext
       # First see if there are any brackets to forward. We need to reverse
@@ -285,22 +292,30 @@
               portIdentifier = "#{outport}[#{idx}]"
               unforwarded = @getForwardableContexts inport, portIdentifier, context
               continue unless unforwarded.length
+              forwardedOpens = []
               for ctx in unforwarded
+                debugBrackets "#{@nodeId} openBracket from '#{inport}' to '#{portIdentifier}': '#{ctx.ip.data}'"
                 ipClone = ctx.ip.clone()
                 ipClone.index = parseInt idx
-                idxIps.unshift ipClone
-                debugBrackets "#{@nodeId} openBracket from '#{inport}' to '#{portIdentifier}': '#{ctx.ip.data}'"
+                forwardedOpens.push ipClone
                 ctx.ports.push portIdentifier
+                @getBracketContext('out', outport, ctx.ip.scope, idx).push ctx
+              forwardedOpens.reverse()
+              idxIps.unshift ip for ip in forwardedOpens
             continue
           # Don't register ports we're only sending brackets to
           datas = ips.filter (ip) -> ip.type is 'data'
           continue unless datas.length
           unforwarded = @getForwardableContexts inport, outport, context
           continue unless unforwarded.length
+          forwardedOpens = []
           for ctx in unforwarded
-            ips.unshift ctx.ip.clone()
             debugBrackets "#{@nodeId} openBracket from '#{inport}' to '#{outport}': '#{ctx.ip.data}'"
+            forwardedOpens.push ctx.ip.clone()
             ctx.ports.push outport
+            @getBracketContext('out', outport, ctx.ip.scope).push ctx
+          forwardedOpens.reverse()
+          ips.unshift ip for ip in forwardedOpens

     if result.__bracketClosingAfter?.length
       for context in result.__bracketClosingAfter
@@ -309,6 +324,7 @@
         for port in context.ports
           ipClone = context.closeIp.clone()
           @addToResult result, port, ipClone, false
+          @getBracketContext('out', port, ipClone.scope, ipClone.index).pop()

     delete result.__bracketClosingBefore
     delete result.__bracketContext


Keep one bracket context object that can track both in and out

--- src/lib/Component.coffee
+++ src/lib/Component.coffee
@@ -39,7 +39,8 @@
     @ordered = options.ordered ? false
     @autoOrdering = options.autoOrdering ? null
     @outputQ = []
-    @bracketContextIn = {}
+    @bracketContext =
+      in: {}
     @activateOnInput = options.activateOnInput ? true
     @forwardBrackets = in: ['out', 'error']

@@ -72,7 +73,8 @@
     return unless @started
     inPorts = @inPorts.ports or @inPorts
     inPort.clear() for inPort in inPorts
-    @bracketContextIn = {}
+    @bracketContext =
+      in: {}
     callback = =>
       @started = false
       @emit 'end'
@@ -228,9 +230,9 @@
     if @inPorts[port].isAddressable()
       portname = "#{port}[#{idx}]"
     # Ensure we have a bracket context for the current scope
-    @bracketContextIn[portname] = {} unless @bracketContextIn[portname]
-    @bracketContextIn[portname][scope] = [] unless @bracketContextIn[portname][scope]
-    return @bracketContextIn[portname][scope]
+    @bracketContext.in[portname] = {} unless @bracketContext.in[portname]
+    @bracketContext.in[portname][scope] = [] unless @bracketContext.in[portname][scope]
+    return @bracketContext.in[portname][scope]

   addToResult: (result, port, ip, before = false) ->
     if port.indexOf('[') is -1
@@ -699,7 +701,7 @@
       # We're doing bracket forwarding. See if there are
       # dangling closeBrackets in buffer since we're the
       # last running process function.
-      for port, contexts of @nodeInstance.bracketContextIn
+      for port, contexts of @nodeInstance.bracketContext.in
         continue unless contexts[@scope]
         nodeContext = contexts[@scope]
         continue unless nodeContext.length