proper callbacks

proper callbacks

--- lib/esl.coffee
+++ lib/esl.coffee
@@ -488,11 +488,11 @@
 exports.createCallServer = ->
   server = new eslServer (call) ->
     Unique_ID = 'Unique-ID'
-    call.connect ->
+    call.connect (call) ->
       unique_id = call.body[Unique_ID]
       call.auto_cleanup()
-      call.filter Unique_ID, unique_id, ->
-        call.event_json 'ALL', ->
+      call.filter Unique_ID, unique_id, (call) ->
+        call.event_json 'ALL', (call) ->
           server.emit 'CONNECT', call
   return server


Random stuff, trying to get it to work.

Random stuff, trying to get it to work.

--- lib/checker.coffee
+++ lib/checker.coffee
@@ -1,6 +1,14 @@
+spellchecker = require 'spellchecker'
+
 class Checker
+  spellchecker: null
+
   constructor: (@editor) ->
     console.log("initializing spell check en-us", @editor)
+    console.log("spell", spellchecker)
+    @spellchecker = new spellchecker.Spellchecker
+    @spellchecker.setDictionary("en_US", spellchecker.getAvailableDictionaries())
+    console.log("init'd", @spellchecker)

   deactivate: ->
     console.log("deactivating en-us")


Clean files in project sub directories as well

--- lib/cleaner.coffee
+++ lib/cleaner.coffee
@@ -12,14 +12,15 @@
     if !@latex.manager.findMain()
       return false
     rootDir = path.dirname(@latex.mainFile)
-    removeGlobs = atom.config.get('atom-latex.file_ext_to_clean')\
-      .replace(/\s/,'').split(',')
-    for removeGlob in removeGlobs
-      glob(removeGlob, cwd: rootDir, (err, files) ->
-        if err
-          return
-        for file in files
-          fullPath = path.resolve(rootDir, file)
-          fs.unlink(fullPath)
-      )
+    FileExts = atom.config.get('atom-latex.file_ext_to_clean')\
+      .replace(/\*\./g,'').replace(/\,\s/g,'|')
+    glob("**/*.*(#{FileExts})", cwd: rootDir, (err, files) ->
+      if err
+        console.log err
+        return
+      for file in files
+        fullPath = path.resolve(rootDir, file)
+        fs.unlink(fullPath,(e) ->
+          console.log e if e?)
+    )
     return true


Fix touch events around details view

Fix touch events around details view

--- assets/javascripts/views/post.js.coffee
+++ assets/javascripts/views/post.js.coffee
@@ -72,9 +72,7 @@
       [touch_details.scrollX, touch_details.scrollY] = [window.scrollX, window.scrollY]

     @$el.off('touchend.toggle_details').on 'touchend.toggle_details', (e) =>
-      return true unless (_.find tag_blacklist, (t)=> t == e.target.tagName.toLowerCase()) &&
-                    !(_.find $(e.target).parents(), (el) => _.find(tag_blacklist, (t) => t == el.tagName.toLowerCase())) &&
-                    touch_details.scrollX == window.scrollX && touch_details.scrollY == window.scrollY
+      return true unless (!(_.find tag_blacklist, (t)=> t == e.target.tagName.toLowerCase()) && !(_.find $(e.target).parents(), (el) => _.find(tag_blacklist, (t) => t == el.tagName.toLowerCase())) && touch_details.scrollX == window.scrollX && touch_details.scrollY == window.scrollY)
       e.preventDefault()
       @toggleDetails()
       false


Update zh-HANS.coffee (#5938)

Update zh-HANS.coffee (#5938)

chinese translation update

--- app/locale/zh-HANS.coco.coffee
+++ app/locale/zh-HANS.coco.coffee
@@ -1221,8 +1221,8 @@
     email_exists: "使用该账号的电子邮箱"
     phone_number: "手机号码"
     phone_number_help: "工作日我们如何找到您？"
-    primary_role_label: "您的主要职业"
-    role_default: "选择职业"
+    primary_role_label: "您的主要角色"
+    role_default: "选择角色"
     primary_role_default: "（请选择）"
     purchaser_role_default: "（请选择）"
     tech_coordinator: "其它"


fix option.defaults supplied in an array to buildValueStore

--- lib/get.coffee
+++ lib/get.coffee
@@ -24,7 +24,7 @@
   #if options.stack is true # options.default may be undefined, that's okay
   # let's use this for file reading, so, always create it.
   # keep deleting what we read in unless options.stack is true
-  store = buildValueStore options.default
+  store = buildValueStore array: [options.defaults]

   # we do this by default, so, only *don't* when explicitly set to false
   unless options.collapse is false


Quick and dirty fix for #194

Quick and dirty fix for #194

Since git-plus works on temporary repository objects, TreeView does not seem pick up on events from them. So in order to update TreeView, one *has* to update project's repositories, I think.

More involved fix would be to get project repositories  right away, if possible, and work on those, but I'm not sure if it would have any undesirable side effects.

--- lib/git.coffee
+++ lib/git.coffee
@@ -91,6 +91,11 @@
     repo.destroy?()
   else
     repo.refreshStatus()
+    atom.project.getRepositories()
+      .filter (r) ->
+        r.path is repo.path
+      .forEach (r) ->
+        r.refreshStatus()
   gitCmd
     args: ['add', '--refresh', '--', '.']
     stderr: (data) -> # don't really need to flash an error


rely even less on cwd

rely even less on cwd

--- plugins/project/project.coffee
+++ plugins/project/project.coffee
@@ -16,10 +16,10 @@
     'Command-Ctrl-N': 'toggle'

   initialize: ->
-    @dir = File.workingDirectory()
+    @dir ?= File.workingDirectory()

     activeWindow.document.ace.on 'open', ({filename}) =>
-      @reload() if File.isDirectory filename
+      @reload filename if File.isDirectory filename

     $('#project li').live 'click', (event) =>
       $('#project .active').removeClass 'active'
@@ -48,8 +48,8 @@

     @showing = not @showing

-  reload: ->
-    @dir = dir = File.workingDirectory()
+  reload: (dir=@dir) ->
+    @dir = dir
     $('#project .cwd').text _.last dir.split '/'
     $('#project li').remove()
     $('#project .files').append @createList dir


Remove JS comments

Remove JS comments

--- plugins/webpack/webpack.coffee
+++ plugins/webpack/webpack.coffee
@@ -25,7 +25,7 @@
       resolve:
         extensions: brk " .js .coffee .litcoffee .coffee.md"
       plugins: values
-        minimize: new webpack.optimize.UglifyJsPlugin
+        minimize: new webpack.optimize.UglifyJsPlugin comments: false
         reorder: new webpack.optimize.OccurenceOrderPlugin
       environments:
         development:


I don’t know what I am doing

I don’t know what I am doing

--- lib/kss.coffee
+++ lib/kss.coffee
@@ -15,9 +15,9 @@
       for stylesheet in document.styleSheets
         idxs = []
         for rule, idx in stylesheet.cssRules
-          if (rule.type == CSSRule.STYLE_RULE) && pseudos.test(rule.selectorText)
+          while (rule.type == CSSRule.STYLE_RULE) && pseudos.test(rule.selectorText)
             replaceRule = (matched, stuff) ->
-              return ".pseudo-class-" + matched.replace(':', '')
+              return matched.replace(/\:/g, '.pseudo-class-')
             @insertRule(rule.cssText.replace(pseudos, replaceRule))

   # Takes a given style and attaches it to the current page.


Fixed size check for non-1x displays

Fixed size check for non-1x displays


healthcheck: increase timeout to 1s

healthcheck: increase timeout to 1s

--- server.coffee
+++ server.coffee
@@ -16,7 +16,7 @@
 CookieService = require './src/services/cookie'

 MIN_TIME_REQUIRED_FOR_HSTS_GOOGLE_PRELOAD_MS = 10886400000 # 18 weeks
-HEALTHCHECK_TIMEOUT = 400
+HEALTHCHECK_TIMEOUT = 1000

 Rx.config.Promise = Promise


Use proxy_pass'd api

Use proxy_pass'd api

--- app/main.coffee
+++ app/main.coffee
@@ -17,7 +17,10 @@

 # api
 Api = require 'zooniverse/lib/api'
-api = new Api project: 'planet_hunter'
+api = if window.location.hostname is 'www.planethunters.org'
+  new Api project: 'planet_hunter', host: 'http://www.planethunters.org', path: '/_ouroboros_api/proxy'
+else
+  new Api project: 'planet_hunter'

 # site navigation
 SiteNavigation = require './controllers/site-navigation'


change page hash on load

change page hash on load

--- app/assets/javascripts/man.coffee
+++ app/assets/javascripts/man.coffee
@@ -40,6 +40,8 @@
         $('@viewport').attr('src', "/?url=#{url}")
         $('@form').addClass('transient')

+        window.location.hash = "##{url}";
+
         setResultClass = ->
           $('@form').removeClass('transient')
           $('@content').addClass('result')


debug

debug

--- app/assets/javascripts/zzz.coffee
+++ app/assets/javascripts/zzz.coffee
@@ -2,5 +2,5 @@
 # All this logic will automatically be available in application.js.
 # You can use CoffeeScript in this file: http://coffeescript.org/

-$->
+$ ->
   alert "bah"


Remove lab-how-to route.

Remove lab-how-to route.

--- app/router.cjsx
+++ app/router.cjsx
@@ -248,7 +248,6 @@
       <Route path="mini-course" component={require './pages/lab/mini-course'} />
     </Route>
     <Route path="lab-policies" component={require './pages/lab/help/lab-policies'} />
-    <Route path="lab-how-to" component={HowToBuildProject} />
     <Route path="glossary" component={require './pages/lab/help/glossary'} />

     <Route path="lab-best-practices" component={require './pages/lab/best-practices'}>


move pipe after error handler setup

move pipe after error handler setup

--- app/coffee/LocalFileWriter.coffee
+++ app/coffee/LocalFileWriter.coffee
@@ -14,7 +14,6 @@
 		fsPath = @_getPath(key)
 		logger.log fsPath:fsPath, "writing file locally"
 		writeStream = fs.createWriteStream(fsPath)
-		stream.pipe writeStream
 		writeStream.on "finish", ->
 			timer.done()
 			logger.log fsPath:fsPath, "finished writing file locally"
@@ -25,6 +24,7 @@
 		stream.on "error", (err)->
 			logger.log err:err, fsPath:fsPath, "problem writing file locally, with read stream"
 			callback err
+		stream.pipe writeStream

 	deleteFile: (fsPath, callback)->
 		logger.log fsPath:fsPath, "removing local temp file"


Split nodes if their child count exceeds the branching factor

--- src/marker-index.coffee
+++ src/marker-index.coffee
@@ -1,4 +1,6 @@
 Point = require "./point"
+
+BRANCHING_FACTOR = 3

 class Node
   constructor: (@children) ->
@@ -30,7 +32,10 @@
         i++

       childStart = childEnd
-    return
+
+    if @children.length > BRANCHING_FACTOR
+      splitIndex = Math.ceil(@children.length / BRANCHING_FACTOR)
+      [new Node(@children.slice(0, splitIndex)), new Node(@children.slice(splitIndex))]

   findContaining: (start, end) ->
     # We break this query into subqueries on our children. For any child that


Fix error on drawing graph

Fix error on drawing graph

--- app/static/coffee/views.coffee
+++ app/static/coffee/views.coffee
@@ -600,7 +600,7 @@
         _renderTrendChartView: (name, datasets, colorNames) ->
             ### Render single trend chart ###
             view = new app.views.TrendChartView
-                labels: _.map _.range(30), -> ''
+                labels: _.map(_.range(30), (-> ''))
                 datasets: datasets
                 name: name
                 colorNames: colorNames


code style: use `=` instead of `:` for "static" class assignment

--- node_modules_koding/koding-payment/lib/main.coffee
+++ node_modules_koding/koding-payment/lib/main.coffee
@@ -35,14 +35,14 @@
   # See https://docs.recurly.com/api/accounts for XML format
   #

-  @fetchAccountDetailsByPaymentMethodId: (paymentMethodId, callback) ->
+  @fetchAccountDetailsByPaymentMethodId = (paymentMethodId, callback) ->
     GET "accounts/#{paymentMethodId}", (err, res) =>
       return callback err  if err
       @fetchPaymentMethodById paymentMethodId, (err, billing) ->
         return callback err  if err
         callback null, new models.Account res[0]?.account, billing

-  @setAccountDetailsByPaymentMethodId: (paymentMethodId, data, callback) ->
+  @setAccountDetailsByPaymentMethodId = (paymentMethodId, data, callback) ->

     xml =
       """
@@ -62,7 +62,7 @@
       else
         PUT "accounts/#{paymentMethodId}", xml, callback

-  @deleteAccount: (paymentMethodId, callback)->
+  @deleteAccount = (paymentMethodId, callback)->
     DEL "accounts/#{paymentMethodId}", callback

   #
@@ -70,7 +70,7 @@
   # See https://docs.recurly.com/api/invoices for XML format
   #

-  @fetchAdjustments: (paymentMethodId, type, state, callback) ->
+  @fetchAdjustments = (paymentMethodId, type, state, callback) ->
     [callback, state] = [state, callback]  unless callback
     [callback, type]  = [type, callback]   unless callback
     type  or= 'credits and charges'
@@ -87,19 +87,19 @@

       callback null, adjs

-  @fetchCharged: (paymentMethodId, callback) ->
+  @fetchCharged = (paymentMethodId, callback) ->
     @fetchAdjustments paymentMethodId, 'charge', 'invoiced', callback

-  @fetchPendingCharges: (paymentMethodId, callback) ->
+  @fetchPendingCharges = (paymentMethodId, callback) ->
     @fetchAdjustments paymentMethodId, 'charge', 'pending', callback

-  @fetchCredited: (paymentMethodId, callback) ->
+  @fetchCredited = (paymentMethodId, callback) ->
     @fetchAdjustments paymentMethodId, 'credit', 'invoiced', callback

-  @fetchPendingCredits: (paymentMethodId, callback) ->
+  @fetchPendingCredits = (paymentMethodId, callback) ->
     @fetchAdjustments paymentMethodId, 'credit', 'pending', callback

-  @createAdjustment: (paymentMethodId, data, callback) ->
+  @createAdjustment = (paymentMethodId, data, callback) ->
     xml =
       """
       <adjustment>
@@ -114,9 +114,9 @@
     POST "accounts/#{paymentMethodId}/adjustments", xml, (err, res) ->
       callback err, unless err then new models.Adjustment res.adjustment

-  @createCharge: @createAdjustment
-
-  @createRefund: (paymentMethodId, data, callback) ->
+  @createCharge = @createAdjustment
+
+  @createRefund = (paymentMethodId, data, callback) ->
     data.unit_amount_in_cents = "-#{data.unit_amount_in_cents}"
     @createAdjustment paymentMethodId, data, callback

@@ -125,7 +125,7 @@
   # See https://docs.recurly.com/api/invoices for XML format
   #

-  @fetchInvoices: (paymentMethodId, callback) ->
+  @fetchInvoices = (paymentMethodId, callback) ->
     GET "accounts/#{paymentMethodId}/invoices", (err, res) ->
       return callback err  if err

@@ -138,7 +138,7 @@
   # charge amount from pending one-time adjustments (carge/credit) to subscription
   # if not manually charged with this method, those will be automatically charged
   # on subscription's renewal (typically monthly)
-  @chargePending: (paymentMethodId, callback)->
+  @chargePending = (paymentMethodId, callback)->
     POST "accounts/#{paymentMethodId}/invoices", '', (err, res)->
       callback err, unless err then new models.Transaction res.transaction

@@ -147,7 +147,7 @@
   # See https://docs.recurly.com/api/accounts for XML format
   #

-  @fetchPaymentMethodById: (paymentMethodId, callback)->
+  @fetchPaymentMethodById = (paymentMethodId, callback)->
     GET "accounts/#{paymentMethodId}/billing_info", (err, res)->
       return callback err  if err?
       paymentMethod = res[0]?.billing_info
@@ -197,7 +197,7 @@
   # See https://docs.recurly.com/api/plans for documentation
   #

-  @fetchPlans: (callback) ->
+  @fetchPlans = (callback) ->
     GET 'plans', (err, res) ->
       return callback err  if err

@@ -207,7 +207,7 @@

       callback null, plans

-  @fetchPlan: (data, callback) ->
+  @fetchPlan = (data, callback) ->
     GET "plans/#{data.code}", (err, res) ->
       return callback err  if err

@@ -216,7 +216,7 @@
       else
         callback new models.Error 'plan', 'Requested plan not found'

-  @createPlan: (data, callback) ->
+  @createPlan = (data, callback) ->
     data.feeInitial  ?= 0
     data.feeInterval ?= 1

@@ -239,7 +239,7 @@
     POST 'plans', xml, (err, res) ->
       callback err, unless err then new models.Plan res.plan

-  @updatePlan: (data, callback)->
+  @updatePlan = (data, callback)->
     data.feeInitial  ?= 0
     data.feeInterval ?= 1

@@ -261,7 +261,7 @@
     PUT "plans/#{data.code}", xml, (err, res)->
       callback err, unless err then new models.Plan res.plan

-  @deletePlan: (data, callback)->
+  @deletePlan = (data, callback)->
     DEL "plans/#{data.code}", callback

   #
@@ -269,7 +269,7 @@
   # See https://docs.recurly.com/api/subscriptions for documentation
   #

-  @fetchSubscriptions: (paymentMethodId, callback) ->
+  @fetchSubscriptions = (paymentMethodId, callback) ->
     GET "accounts/#{paymentMethodId}/subscriptions", (err, res) ->
       return callback err  if err

@@ -279,7 +279,7 @@

       callback null, subs

-  @fetchSubscription: (paymentMethodId, data, callback) ->
+  @fetchSubscription = (paymentMethodId, data, callback) ->
     GET "subscriptions/#{data.uuid}", (err, res) ->
       return callback err  if err

@@ -288,7 +288,7 @@
       else
         callback new models.Error 'subscription', 'Requested subscription not found'

-  @createSubscription: (paymentMethodId, data, callback)->
+  @createSubscription = (paymentMethodId, data, callback)->
     data.quantity ?= 1

     xml =
@@ -307,7 +307,7 @@
     POST 'subscriptions', xml, (err, res)->
       callback err, unless err then new models.Subscription res.subscription

-  @updateSubscription: (paymentMethodId, data, callback)->
+  @updateSubscription = (paymentMethodId, data, callback)->
     data.quantity ?= 1
     timeframe      = 'now'

@@ -324,17 +324,17 @@
     PUT "subscriptions/#{data.uuid}", xml, (err, res)->
       callback err, unless err then new models.Subscription res.subscription

-  @terminateSubscription: (paymentMethodId, data, callback)->
+  @terminateSubscription = (paymentMethodId, data, callback)->
     data.refund ?= 'none'

     PUT "subscriptions/#{data.uuid}/terminate?refund=#{data.refund}", '', (err, res)->
       callback err, unless err then new models.Subscription res.subscription

-  @cancelSubscription: (paymentMethodId, data, callback)->
+  @cancelSubscription = (paymentMethodId, data, callback)->
     PUT "subscriptions/#{data.uuid}/cancel", '', (err, res)->
       callback err, unless err then new models.Subscription res.subscription

-  @reactivateUserSubscription: (paymentMethodId, data, callback)->
+  @reactivateUserSubscription = (paymentMethodId, data, callback)->
     PUT "subscriptions/#{data.uuid}/reactivate", '', (err, res)->
       callback err, unless err then new models.Subscription res.subscription

@@ -343,7 +343,7 @@
   # See https://docs.recurly.com/api/transactions for documentation
   #

-  @fetchTransactions: (paymentMethodId, callback) ->
+  @fetchTransactions = (paymentMethodId, callback) ->
     GET "accounts/#{paymentMethodId}/transactions", (err, res) ->
       return callback err  if err

@@ -353,7 +353,7 @@

       callback null, trans

-  @createTransaction: (paymentMethodId, data, callback)->
+  @createTransaction = (paymentMethodId, data, callback)->
     xml =
       """
       <transaction>
@@ -369,5 +369,5 @@
     POST 'transactions', xml, (err, res)->
       callback err, unless err then new models.Transaction res.transaction

-  @deleteTransaction: (paymentMethodId, data, callback)->
+  @deleteTransaction = (paymentMethodId, data, callback)->
     DEL "transactions/#{data.uuid}?amount_in_cents=##{data.amount}", callback


fix divergence bug, root cause is failure to keep track of leaf text

--- src/editor.coffee
+++ src/editor.coffee
@@ -247,7 +247,7 @@
         leaf.setText(text)
         parent.appendChild(leaf.node)
       else
-        leaf.setText(leaf.text.substr(0, position.offset) + text + leaf.text.substr(position.offset))
+        leaf.setText(leaf.node.textContent.substr(0, position.offset) + text + leaf.node.textContent.substr(position.offset))
     @doc.updateLine(leaf.line)

   normalize: ->


focus editor upon init by default

focus editor upon init by default

--- src/editor.coffee
+++ src/editor.coffee
@@ -112,6 +112,10 @@

   enable: ->
     @doc.root.setAttribute('contenteditable', true)
+    @doc.root.focus()
+    position = Tandem.Position.makePosition(this, 0)
+    start = new Tandem.Range(this, position, position)
+    Tandem.Range.setSelection(this, start)

   initContentListeners: ->
     onEdit = _.debounce( =>


Clean up visibilities where I made an error

--- src/editor.coffee
+++ src/editor.coffee
@@ -654,7 +654,7 @@
   # {Delegates to: TextBuffer.getEndPosition}
   getEofBufferPosition: -> @buffer.getEndPosition()

-  # Public: Get the {Range} of the paragraph surrounding the most recently added
+  # Extended: Get the {Range} of the paragraph surrounding the most recently added
   # cursor.
   #
   # Returns a {Range}.
@@ -1064,7 +1064,7 @@
   #   * `replace` Call this {Function} with a {String} to replace the match.
   scan: (regex, iterator) -> @buffer.scan(regex, iterator)

-  # Essential: Scan regular expression matches in a given range, calling the given
+  # Extended: Scan regular expression matches in a given range, calling the given
   # iterator function on each match.
   #
   # * `regex` A {RegExp} to search for.
@@ -1078,7 +1078,7 @@
   #   * `replace` Call this {Function} with a {String} to replace the match.
   scanInBufferRange: (regex, range, iterator) -> @buffer.scanInRange(regex, range, iterator)

-  # Essential: Scan regular expression matches in a given range in reverse order,
+  # Extended: Scan regular expression matches in a given range in reverse order,
   # calling the given iterator function on each match.
   #
   # * `regex` A {RegExp} to search for.
@@ -1332,7 +1332,7 @@
   # Returns a {Point}.
   clipBufferPosition: (bufferPosition) -> @buffer.clipPosition(bufferPosition)

-  # Essential: Clip the start and end of the given range to valid positions in the
+  # Extended: Clip the start and end of the given range to valid positions in the
   # buffer. See {::clipBufferPosition} for more information.
   #
   # * `range` The {Range} to clip.
@@ -1340,7 +1340,7 @@
   # Returns a {Range}.
   clipBufferRange: (range) -> @buffer.clipRange(range)

-  # Essential: Clip the given {Point} to a valid position on screen.
+  # Extended: Clip the given {Point} to a valid position on screen.
   #
   # If the given {Point} describes a position that is actually reachable by the
   # cursor based on the current contents of the screen, it is returned


boot: Note about async user-code

boot: Note about async user-code

--- lib/assets/javascripts/unpoly/framework.coffee
+++ lib/assets/javascripts/unpoly/framework.coffee
@@ -53,6 +53,7 @@
         # In case the DOM was already ready when up.event.boot() was called, we still
         # haven't executed user-provided code. So we wait one more frame until
         # user-provided compilers, event handlers, etc. have been registered.
+        # This also gives async user-code a chance to run in the next microtask.
         u.task ->
           # At this point all user-code has been called.
           # The following event will cause Unpoly to compile the <body>.


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine.coffee
+++ src/engine.coffee
@@ -2,8 +2,6 @@
   defaults =
     FPS: 30
     age: 0
-    excludedModules: []
-    includedModules: []
     paused: false
     showFPS: false
     zSort: false


use prop correctly

use prop correctly

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -61,13 +61,13 @@
       @tool.deselect()

     'click .asteroid-done-screen': ->
-      @notify translate 'classifier.rightPanel.asteroidDoneScreen' if @state is 'asteroidTool' and @doneButton.prop('disabled')?
+      @notify translate 'classifier.rightPanel.asteroidDoneScreen' if @state is 'asteroidTool' and @doneButton.prop('disabled')

     'click .artifact-done-screen': ->
-      @notify translate 'classifier.rightPanel.artifactDoneScreen' if @state is 'artifactTool' and @doneButton.prop('disabled')?
+      @notify translate 'classifier.rightPanel.artifactDoneScreen' if @state is 'artifactTool' and @doneButton.prop('disabled')

     'click .finished-screen': ->
-      if @state is 'whatKind' and @finishButton.prop("disabled")? and !@nextSubjectButton.is(":visible")
+      if @state is 'whatKind' and @finishButton.prop("disabled") and !@nextSubjectButton.is(":visible")
         @notify translate 'classifier.finished.finishedButtonScreen'

     'click .right-panel': ->


Simplify if statement

Simplify if statement

--- framer/Animation.coffee
+++ framer/Animation.coffee
@@ -73,7 +73,7 @@
 		get: -> @options.looping
 		set: (value) ->
 			@options.looping = value
-			if (@options?.looping ? false) and @options?.layer? and !@isAnimating
+			if @options?.looping and @options?.layer? and !@isAnimating
 				@restart()

 	start: =>


Add File Component To Example

Add File Component To Example

--- examples/coffeescript/example.coffee
+++ examples/coffeescript/example.coffee
@@ -78,6 +78,12 @@
             xs: "6"
             label: "Time of Day"

+          f.input("uploadAvatar",
+            type: "file",
+            xs: "6"
+            label: "Uploading Avatar"
+          ),
+
         div className: "row",
           div className: "sm-col-12",
             h3 {}, "Additional Sketchy Info"


CloudFoundry's process.env.VMC_APP_PORT listen

--- web/astrolin.coffee
+++ web/astrolin.coffee
@@ -115,6 +115,6 @@
   util.puts "Uncaught Exception: #{err.toString()}"

 # Start the server.
-port = parseInt(process.env.C9_PORT || process.env.PORT || 8001)
+port = parseInt(process.env.PORT || process.env.VMC_APP_PORT || process.env.C9_PORT || 8001)
 app.listen port, null # app.address().port # null host will accept connections from other instances
 console.log "Express been started on :%s", port


house keeping

house keeping

--- app/js/controllers/packets.coffee
+++ app/js/controllers/packets.coffee
@@ -25,16 +25,13 @@

   # get recent packets
   refresh_recent_packets = ->
-    Blockchain.refresh_recent_packets().then (result) ->
-      console.log 'refresh packets', result
-      $scope.packets = result
+    Blockchain.refresh_recent_packets().then (result) -> $scope.packets = result

   # monitor every block update
   recent_packets_observer =
     name: "recent_packets_observer"
     frequency: "each_block"
     update: (data, deferred) =>
-      console.log 'onBlock'
       refresh_recent_packets()
       deferred.resolve(true)


fixed string matching rules

fixed string matching rules


Youtube previews

Youtube previews

--- app/scripts/lib/formatters.coffee
+++ app/scripts/lib/formatters.coffee
@@ -87,6 +87,12 @@
       ""
     ]

+  YT_PREVIEW_FORMATTER:
+    [/([^<]+)<\/a>/g
+    , ->
+      ""
+    ]
+
   markdown: (raw) ->
     ###Markdown with some additional BnW-specific rules.###

@@ -140,6 +146,9 @@

     # Image's previews
     html.replace @IMG_PREVIEW_FORMATTER[0], @IMG_PREVIEW_FORMATTER[1]
+
+    # Youtube previews
+    html.replace @YT_PREVIEW_FORMATTER[0], @YT_PREVIEW_FORMATTER[1]

   moinmoin: (raw) ->
     ###
@@ -189,6 +198,7 @@
       @USER_LINK_FORMATTER
       @POST_LINK_FORMATTER
       @IMG_PREVIEW_FORMATTER
+      @YT_PREVIEW_FORMATTER
       # Fix newlines
       [/\n/g, -> "
"]
     ]


Revert "Regard .tikz files like TeX files as well"

This reverts commit 07012597f3b0aff1ccd84817ed4077673b3a1e64.

--- lib/manager.coffee
+++ lib/manager.coffee
@@ -44,7 +44,7 @@

   isTexFile: (name) ->
     @latex.manager.loadLocalCfg()
-    if path.extname(name) == '.tex' or path.extname(name) == '.tikz' or \
+    if path.extname(name) == '.tex' or \
         @latex.manager.config?.latex_ext?.indexOf(path.extname(name)) > -1
       return true
     return false


remove temp code

remove temp code

--- source/assets/javascripts/application.js.coffee
+++ source/assets/javascripts/application.js.coffee
@@ -1,6 +1 @@
 //= require_tree .
-var foo = bar
-
-if foo == bar {
-  foo = undefined
-}


:lipstick: Use Date.now

:lipstick: Use Date.now

--- lib/metrics.coffee
+++ lib/metrics.coffee
@@ -2,9 +2,9 @@

 module.exports =
   activate: ({sessionLength}) ->
-    @sessionStart = new Date().getTime()
+    @sessionStart = Date.now()
     Reporter.sendDeactivateEvent(sessionLength) if sessionLength
     Reporter.sendActivateEvent()

   serialize: ->
-    sessionLength: new Date().getTime() - @sessionStart
+    sessionLength: Date.now() - @sessionStart


migrate script fixes

migrate script fixes

--- util/migrateCobaltBoxToCustard.coffee
+++ util/migrateCobaltBoxToCustard.coffee
@@ -8,8 +8,8 @@

 argv = require('optimist')
   .usage('Only for Linode->EC2 currently!\nUsage: $0 [--verbose] --source-box <box> --target-box <box> --source-host <host> --target-host <host>')
-  .demand(['source-box', 'target-box', 'new-host'])
-  .string(['source-box', 'target-box', 'new-host'])
+  .demand(['source-box', 'target-box', 'source-host', 'target-host'])
+  .string(['source-box', 'target-box', 'source-host', 'target-host'])
   .alias('bs', 'source-box')
   .alias('v', 'verbose')
   .alias('bt', 'target-box')
@@ -64,16 +64,19 @@
   cmd = "rsync --archive --verbose -e 'ssh' --rsync-path 'sudo rsync' /home/#{SOURCE_BOX}/ ubuntu@#{box.server}:/ebs/home/#{box.name}"
   exec cmd, (err, stdout, stderr) ->
     checkVerboseAndPrint cmd, err, stdout, stderr
+    callback()

 chownBox = (box, callback) ->
   cmd = "ssh ubuntu@#{box.server} 'sudo chown -R #{box.name}: /ebs/home/#{box.name}'"
   exec cmd, (err, stdout, stderr) ->
     checkVerboseAndPrint cmd, err, stdout, stderr
+    callback()

 copyCrontab = (box, callback) ->
-  cmd = """cat /var/spool/cron/crontabs/#{SOURCE_BOX} | ssh ubuntu@#{box.server} 'sudo sh -c "cat > /ebs/crontabs/#{TARGET_BOX}; chown #{TARGET_BOX}:crontab /etc/crontabs/#{TARGET_BOX}"'"""
+  cmd = """cat /var/spool/cron/crontabs/#{SOURCE_BOX} | ssh ubuntu@#{box.server} 'sudo sh -c "cat > /ebs/crontabs/#{TARGET_BOX}; chown #{TARGET_BOX}:crontab /ebs/crontabs/#{TARGET_BOX}"'"""
   exec cmd, (err, stdout, stderr) ->
     checkVerboseAndPrint cmd, err, stdout, stderr
+    callback()

 Box.findOneByName TARGET_BOX, (err, box) ->
   unless box?.name?


allow passing through of question children from exercise preview component as question footer

--- src/components/exercise/preview.cjsx
+++ src/components/exercise/preview.cjsx
@@ -91,7 +91,9 @@
         choicesEnabled={false}
         show_all_feedback={@props.displayFeedback}
         type='teacher-review'
-        details={details}/>
+        details={details}>
+        {@props.questionFooter}
+      </Question>
     )

     <BS.Panel


fixed output parsing and coloring

fixed output parsing and coloring

--- lib/atom-python-test-view.coffee
+++ lib/atom-python-test-view.coffee
@@ -13,14 +13,14 @@
             @span class: 'icon icon-x'
           @button outlet: 'clearBtn', class: 'btn inline-block-tight right', click: 'clear', style: 'float: right', =>
             @span class: 'icon icon-trashcan'
-          @button outlet: 'clearBtn', class: 'btn inline-block-tight right', click: 'clear', style: 'float: right', =>
+          @button outlet: 'clearBtn', class: 'btn inline-block-tight right', click: 'showHistory', style: 'float: right', =>
             @span class: 'icon icon-history'
         @pre class: 'output', outlet: 'output'
-        # TODO: create history button

     initialize: ->
       @panel ?= atom.workspace.addBottomPanel(item: this)
       @message = ""
+      @history = ""
       @panel.hide()
     # TODO: create history field to store previous results

@@ -44,30 +44,39 @@
         new_line = "" + line + ""
       return new_line

-    # TODO: move html taggin to a separate function
+    colorStatus: (line) ->
+      parts = line.split(" ")
+      new_line = parts[0] + " "
+      if parts[1] == "FAILED"
+        new_line += @addSpanTag(parts[1], "failure-line")
+      else if parts[1] == "PASSED"
+        new_line += @addSpanTag(parts[1], "success-line")
+      else
+        new_line += parts[1]
+      return new_line
+
     # TODO: refactor the error coloring
-    addLine: (line) ->
-      if line.indexOf("====") > -1 and true == /.*\d+.failed.*(passed)?.in.*seconds.*/i.test(line)
-        array_o_lines = line.split("\n")
-        for l in array_o_lines
-          if l.indexOf("====") > -1 or l.indexOf("E") == 0
-            @message = @addSpanTag(l, "failure-line")
-          else
-            @message = @addSpanTag(l, "error-text")
-          @find(".output").append(@message + "\n")
-      else if true == /.*\d+.passed.in.*seconds.*/i.test(line)
-        @message = @addSpanTag(line, "success-line")
-        @find(".output").append(@message)
-      else
-        @find(".output").append(line)
-
+    # TODO: add empty line after collected... and before FAILURES/x passed in
+    addLine: (lines) ->
+      for line in lines.split("\n")
+        if line == ""
+          continue
+        if line.indexOf("====") > -1
+          if line.indexOf("failed") > -1
+            @message = @addSpanTag(line, "failure-line")
+          else if line.indexOf("passed") > -1
+            @message = @addSpanTag(line, "success-line")
+        else if line.indexOf("FAILED") > -1 or line.indexOf("PASSED") > -1
+          @message = @colorStatus(line)
+        else
+          @message = line
+        @find(".output").append(@message + "\n")

     clear: ->
       @message = ''
       virtual_console = @find(".output")[0]
       while virtual_console.firstChild
         virtual_console.removeChild(virtual_console.firstChild)
-

     finish: ->
       console.log('finish')


Fix * completion

Fix * completion

--- lib/autocomplete-provider.coffee
+++ lib/autocomplete-provider.coffee
@@ -54,11 +54,15 @@
                     if unQuoteFunctionNames
                         value.displayText = value.text = PgHoffAutocompleteProvider.UnQuote(value.text)

+                    replacementPrefix = switch before[-1..-1]
+                        when '*' then '*'
+
                     suggestion =
                         text: value.text
                         displayText: value.text
                         iconHTML: iconHTML
                         rightLabel: value.type
+                        replacementPrefix: replacementPrefix
                         #description: 'this would be nice'
                         type: type
                     return suggestion


expand and collapse all buttons work

expand and collapse all buttons work

--- lib/project/project-find-and-replace-view.coffee
+++ lib/project/project-find-and-replace-view.coffee
@@ -53,6 +53,9 @@
     @regexOptionButton.on 'click', @toggleRegexOption
     @caseSensitiveOptionButton.on 'click', @toggleCaseSensitiveOption
     @inSelectionOptionButton.on 'click', @toggleInSelectionOption
+
+    @expandAll.on 'click', @onExpandAll
+    @collapseAll.on 'click', @onCollapseAll

     @findEditor.on 'core:confirm', @confirmFind
     @findEditor.on 'find-and-replace:focus-next', @focusReplace
@@ -151,6 +154,14 @@

     deferred

+  onExpandAll: (event) =>
+    @previewList.expandAllPaths()
+    @previewList.focus()
+
+  onCollapseAll: (event) =>
+    @previewList.collapseAllPaths()
+    @previewList.focus()
+
   toggleRegexOption: => @toggleOption('regex')

   toggleCaseSensitiveOption: => @toggleOption('caseSensitive')


remove trash

remove trash

--- lib/carte/client/views/list.cjsx
+++ lib/carte/client/views/list.cjsx
@@ -29,7 +29,7 @@
     @queryParam {order: 'random'}, ['sort', 'page']

   tagParam: (tag)->
-    @queryParam {tag: tag}, ['seed']
+    @queryParam {tag: tag}, []

   queryParam: (param, deleteKeys)->
     query = $.extend {}, @props.cards.query, param


Avoid extra space in colors markers in search results

--- lib/color-results-element.coffee
+++ lib/color-results-element.coffee
@@ -148,9 +148,7 @@
       #{lineNumber}

         #{prefix}
-
-          #{match.matchText}
-
+        #{match.matchText}
         #{suffix}


find other final lines, in terse mode, for tf operations

--- src/tf.coffee
+++ src/tf.coffee
@@ -168,13 +168,13 @@
     cmdline = "#{cmdline} -force" if action == 'destroy'
     msg.send {room: msg.message.user.name}, "```\n#{cmdline}\n```"
     exec cmdline, (error, stdout, stderr) ->
-      if stdout
-        if stdout.length < 1024
+      if stdout and !stderr
+        if stdout.length < 2048
           return msg.send {room: msg.message.user.name}, "```\n#{stdout}\n```"
         else unless verbose
           out = 'Error'
           for line in stdout.split "\n"
-            if line.match /^Plan: /
+            if line.match /^(?:Plan: |Apply complete)/
               out = line
           return msg.send {room: msg.message.user.name}, "```\n#{out}\n```"
         out = []


don't use array for markdown children

don't use array for markdown children

--- app/markdown.coffee
+++ app/markdown.coffee
@@ -86,7 +86,7 @@
       components.push UserHtmlComponent html: Marked.Parser.parse current_tokens, opts
     {components}
   render: ->
-    React.DOM.div className: 'lead-markdown', @state.components
+    React.DOM.div className: 'lead-markdown', @state.components...
   componentDidMount: ->
     _.each @getDOMNode().querySelectorAll('a'), (a) =>
       a.addEventListener 'click', (e) =>


Use args variable in vparam scripts

Use args variable in vparam scripts

--- lib/session.coffee
+++ lib/session.coffee
@@ -387,7 +387,7 @@
   allVirtualParameters = virtualParametersCache.get(sessionContext)
   for provision, j in provisions
     counter += 2
-    globals = {TIMESTAMPS: provision[1], VALUES: provision[2]}
+    globals = {args: provision.slice(1)}
     do (j) -> sandbox.run(allVirtualParameters[provision[0]].script, globals,
       sessionContext, startRevision, endRevision,
       (err, _fault, _clear, _declarations, _done, _returnValue) ->


problem.coffee change: show answer -> also show solution_* & do mathjax typeset

--- lms/static/coffee/src/modules/problem.coffee
+++ lms/static/coffee/src/modules/problem.coffee
@@ -48,11 +48,15 @@
               @$("label[for='input_#{key}_#{choice}']").attr
                 correct_answer: 'true'
           else
-            @$("#answer_#{key}").html(value)	// needs to be html, not text, for complex solutions (eg coding)
+            @$("#answer_#{key}").html(value)	# needs to be html, not text, for complex solutions (eg coding)
+            @$("#solution_#{key}").html(value)	# needs to be html, not text, for complex solutions (eg coding)
+        MathJax.Hub.Queue ["Typeset", MathJax.Hub]
+        MathJax.Hub.Queue ["Typeset", MathJax.Hub]
         @$('.show').val 'Hide Answer'
         @element.addClass 'showed'
     else
       @$('[id^=answer_]').text ''
+      @$('[id^=solution_]').text ''
       @$('[correct_answer]').attr correct_answer: null
       @element.removeClass 'showed'
       @$('.show').val 'Show Answer'


BREAKING COMMIT; Feature: autofill form

BREAKING COMMIT; Feature: autofill form

If the user has already successfully submitted the form, then data stored in the
cookie will be autofilled in the form and the form inputs will be disabled.

--- assets/javascripts/contact.coffee
+++ assets/javascripts/contact.coffee
@@ -39,10 +39,21 @@
       del: =>
         document.cookie = "#{@name}=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path="

-    if not Cookie.find 'state'
-      object =
-    	  'didContact':true
-      cookie = new Cookie 'state', object, 7
+    if Cookie.find 'state'
+      value = new Cookie 'state'
+      .unserializedValue()
+
+      autofill = (input, values) ->
+        value = values[input.name]
+        input.disabled = true
+        if input.value?(value)
+          true
+        else if input.text?(value)
+          true
+        false
+
+      autofill input, value.values for input in $ 'form input, textarea'
+      return true

     $ @form
       .find 'button[type="submit"]'
@@ -58,10 +69,20 @@
             $ @submitButton
             .prop 'disabled', true
             url = $ @form
-           				.attr 'action'
-            data = $ @form
-            				.serialize()
-            @send url, data, @submitButton, @flashDiv
+            .attr 'action'
+            serializedString = $ @form
+            .serialize()
+            serializedArray = $ @form
+            .serializeArray()
+
+            normalize = (serializedObj) ->
+              normalizedObj = {}
+              normalizedObj[serializedObj.name] = serializedObj.value
+              normalizedObj
+
+            normalizedValues = (normalize object for object in serializedArray)
+
+            @send url, serializedString, normalizedValues, @submitButton, @flashDiv

     @markup = (field, success)->
       parentDiv = field.parentElement
@@ -100,44 +121,52 @@
             retVal = false
       retVal

-    @send = (url, data, submitButton, flashDiv) ->
-       $.ajax
-          url: url
-          data: data
-          method: 'POST'
-          error: (jqXHR, textStatus, errorThrown) ->
-            message = switch
-              when textStatus is 'abort' then 'The operation has been cancelled.'
-              when textStatus is 'error' then 'Unknown error.'
-              when textStatus is 'parsererror' then 'Failed parsing the response.'
-              when textStatus is 'timeout' then 'The operation timed-out.'
+    @send = (url, serializedString, normalizedArray, submitButton, flashDiv) ->
+      $.ajax
+        url: url
+        data: serializedString
+        method: 'POST'
+        error: (jqXHR, textStatus, errorThrown) ->
+          message = switch
+            when textStatus is 'abort' then 'The operation has been cancelled.'
+            when textStatus is 'error' then 'Unknown error.'
+            when textStatus is 'parsererror' then 'Failed parsing the response.'
+            when textStatus is 'timeout' then 'The operation timed-out.'

-            $ submitButton
-            .prop 'disabled', false
-            $ flashDiv
-            .removeClass 'alert-danger'
-            .addClass 'alert-danger'
-            $ flashDiv
-            .find '.title'
-            .text 'Error'
-            $ flashDiv
-            .find '.message'
-            .text message
-          success: (data, textStatus, jqXHR) ->
-            $ flashDiv
-            .removeClass 'alert-success'
-            .addClass 'alert-success'
-            $ flashDiv
-            .find '.title'
-            .text 'Success!'
-            $ flashDiv
-            .find '.message'
-            .text 'Message successfully sent.'
-          complete: (jqXHR, textStatus) ->
-            # Show the flash `<div>` and then hide it after 7 seconds
-            $ flashDiv
-            .show 'slow'
-            .delay 7000
-            .hide 'slow'
+          $ submitButton
+          .prop 'disabled', false
+          $ flashDiv
+          .removeClass 'alert-danger'
+          .addClass 'alert-danger'
+          $ flashDiv
+          .find '.title'
+          .text 'Error'
+          $ flashDiv
+          .find '.message'
+          .text message
+        success: (data, textStatus, jqXHR) ->
+          state =
+            didContact:true
+            dateContacted: new Date()
+            values: normalizedArray
+
+          cookie = new Cookie 'state', state, 7
+          cookie.save()
+
+          $ flashDiv
+          .removeClass 'alert-success'
+          .addClass 'alert-success'
+          $ flashDiv
+          .find '.title'
+          .text 'Success!'
+          $ flashDiv
+          .find '.message'
+          .text 'Message successfully sent.'
+        complete: (jqXHR, textStatus) ->
+          # Show the flash `<div>` and then hide it after 7 seconds
+          $ flashDiv
+          .show 'slow'
+          .delay 7000
+          .hide 'slow'

 contactForm = new ContactFormValidation $('form'), $('#flash')


removed muddled unsub thinking

removed muddled unsub thinking

--- src/xq.coffee
+++ src/xq.coffee
@@ -395,7 +395,7 @@
         stop = false
         arr.every (k, idx) ->
             a = val(k)
-            unsub = unwrap a, false, (ua, isError) ->
+            unwrap a, false, (ua, isError) ->
                 return if stop
                 if isError
                     stop = true
@@ -405,7 +405,6 @@
                 done++ if r k, idx, ua
                 if arr.length == done
                     stop = true
-                    unsub?()
                     return thenResolver.call _this, fx, fe, result, false, cb
                 null
             return true
@@ -431,19 +430,16 @@

 # Recursively unwrap the given value. Callback when we got to the
 # bottom of it.
-unwrap = (v, isError, cb, ended = true, prevUnsub) ->
-    unsub = null
+unwrap = (v, isError, cb, ended = true) ->
     if v instanceof X
         al = v._always immediate:true, (v, isError) ->
-            unwrap v, isError, cb, false, unsub
+            unwrap v, isError, cb, false
             return null # important or we get endless loops
-        unsub = -> prevUnsub?(); al._doEnd()
         v.onEnd -> unwrap NVA, false, cb, ended
     else if isThenable v
         v.then ((x) -> unwrap x, false, cb, ended), ((e) -> unwrap e, true, cb, ended)
     else
         cb v, isError, ended
-    unsub || prevUnsub

 # retry the promise producing function f at most max times.
 X.retry = (max, delay, f) ->


Trimming user's own competitions by by-membership by default unless includeOwnCompetitions is passed

--- resources/competitions.coffee
+++ resources/competitions.coffee
@@ -66,11 +66,12 @@
         console.log "[HTTP] found no competition memberships (userId=#{userId})"
         return []

-      ownerOrMatchesMembership = memberships.map((membership) ->
+      conditions = memberships.map((membership) ->
         _id: membership.competition_id
       )
-      ownerOrMatchesMembership.push({ owner_id: userId })
-      condition = { $or: ownerOrMatchesMembership }
+      if @params.includeOwnCompetitions == 'true' or @params.includeOwnCompetitions == true
+        conditions.push({ owner_id: userId })
+      condition = { $or: conditions }
       dbQuery = @model.find(condition)
       unless showClosed
         dbQuery.where('open').equals(true)


point to other server

point to other server

--- public/js/coffee/server.coffee
+++ public/js/coffee/server.coffee
@@ -10,7 +10,7 @@
         alert "Your browser does not support websockets."

     connect: (name)->
-      @server = io.connect "http://localhost:5000/snake"
+      @server = io.connect "http://91.121.166.147:5001/snake"
       @server.emit('name', {name : name})
       @server.on "id", (message) ->
         PubSub('SettingID').publish(message.id)


Ace: Add `quiet` parameter to `removePane` method

--- client/Ace/aceapplicationtabview.coffee
+++ client/Ace/aceapplicationtabview.coffee
@@ -2,10 +2,10 @@

   removePane_: KDTabView::removePane

-  removePane: (pane, shouldDetach) ->
+  removePane: (pane, shouldDetach, quiet = no) ->
     {aceView} = pane.getOptions()

-    return  @removePane_ pane, shouldDetach  unless aceView
+    return  @removePane_ pane, shouldDetach  if quiet or not aceView

     {ace} = aceView
     file  = ace.getData()


Fix logs write

Fix logs write

--- lib/utils/process_manager.coffee
+++ lib/utils/process_manager.coffee
@@ -81,11 +81,11 @@
           log.info data

       if node.stderr
-        node.stderr.on 'data', (data) ->
+        node.stderr.on 'data', (data) =>
           fs.appendFile "#{@dir}/logs/node_err.log", data, (err) ->
             throw err if err

-      node.on 'close', (data) ->
+      node.on 'close', (data) =>
         fs.appendFile "#{@dir}/logs/node.log", data, (err) ->
           throw err if err

@@ -112,7 +112,8 @@
     mongod = child.spawn 'mongod',
       [
         "--dbpath", "#{@dir}/data/db",
-        "--logpath", "#{@dir}/data/db/mongo.log"
+        "--logpath", "#{@dir}/data/db/mongo.log",
+        #"--port", @pkg.
       ],
       { detached: true }


fix common coffeelint errors

fix common coffeelint errors

--- src/ramda-extras.coffee
+++ src/ramda-extras.coffee
@@ -37,18 +37,18 @@
 doit = (xs..., x) -> x

 # flytta till ramda-extras, typ 'composeP2'
-_composeP2 = (f, g) -> ->
-	context = @
-	value = g.apply @, arguments
+_composeP2 = (f, g) -> ->
+	context = this
+	value = g.apply this, arguments
 	if isThenable value
 		if f._fail then value.fail (x) -> func.call context, x
 		else res.then (x) -> func.call context, x
-	else f.call @, value
+	else f.call this, value

 # _composeP = (f, g) ->
 # 	->
-# 		context = @
-# 		value = f.apply @, arguments
+# 		context = this
+# 		value = f.apply this, arguments
 # 		if isThenable value
 # 			if f._fail then value.fail

@@ -117,7 +117,7 @@
 # STRING
 # ----------------------------------------------------------------------------------------------------------
 capitalize = lo.capitalize
-toStr = (a) -> a+''
+toStr = (a) -> a + ''

 # ----------------------------------------------------------------------------------------------------------
 # MATH


Jraphical: Module: Move targetSelector definition above the race

--- node_modules_koding/jraphical/lib/module.coffee
+++ node_modules_koding/jraphical/lib/module.coffee
@@ -225,6 +225,17 @@
         targetOptions or= {}
         _targetOptions  = cloneDeep targetOptions

+        if targetSelector = _targetOptions.selector or _targetOptions.query
+
+          delete _targetOptions.selector
+          delete _targetOptions.query
+
+        else
+          targetSelector = {}
+
+        if _targetOptions.options?
+          _targetOptions = _targetOptions.options
+
         collectOthers = race (i, type, group, next) ->

           ids         = (rel[idField] for rel in group)
@@ -235,17 +246,6 @@
             flag = group[index].data?.flags
             flags[id] = flag if flag
             timestamps[id] = group[index].timestamp
-
-          if targetSelector = _targetOptions.selector or _targetOptions.query
-
-            delete _targetOptions.selector
-            delete _targetOptions.query
-
-          else
-            targetSelector = {}
-
-          if _targetOptions.options?
-            _targetOptions = _targetOptions.options

           Base.constructors[type]
             .some extend(targetSelector,


Simplify logic

Simplify logic

--- client/lanes/react/mixins/Screen.coffee
+++ client/lanes/react/mixins/Screen.coffee
@@ -7,11 +7,13 @@
     loadOrCreateModel: (options) ->
         if options.prop and @props[options.props]
             @props[options.props]
-        else if options.attribute and @props.args?.length
-            options.klass.fetch(_.extend( {}, options.syncOptions, {
-                query: {"#{options.attribute}": @props.args[0]}
-            }))
         else
-            new options.klass
+            model = new options.klass
+            if options.attribute and @props.args?.length
+                model.fetch(_.extend( {}, options.syncOptions, {
+                    query: {"#{options.attribute}": @props.args[0]}
+                }))
+            model
+

 }


Bug fix.

Bug fix.

--- client/templates/members/members.coffee
+++ client/templates/members/members.coffee
@@ -1,4 +1,4 @@
-Template.members.onCreated
+Template.members.onCreated ->
   Session.setDefault 'selectedMembers', [Meteor.userId]

 Template.members.helpers


Removed an extraneous console.log

Removed an extraneous console.log

--- client/views/patients/addPatient.coffee
+++ client/views/patients/addPatient.coffee
@@ -42,7 +42,6 @@
                 $("[name=firstName]").val(response?.firstname)
                 $("[name=middleName]").val(response?.middlename)
                 $("[name=lastName]").val(response?.lastname)
-                console.log(response)

 Template.addPatient.helpers
     surgicalPathologyNumbers: ->


Fixed the max issue in xkcd

Fixed the max issue in xkcd

--- src/scripts/xkcd.coffee
+++ src/scripts/xkcd.coffee
@@ -14,6 +14,7 @@
 #
 # Author:
 #   twe4ked
+#   Hemanth (fixed the max issue)

 module.exports = (robot) ->
   robot.respond /xkcd(\s+latest)?$/i, (msg) ->
@@ -37,12 +38,14 @@
           msg.send object.title, object.img, object.al

   robot.respond /xkcd\s+random/i, (msg) ->
-    max = 1100 #max as of 3/2013 TODO: add way to get current max
-    num = Math.floor((Math.random()*max)+1)
-    msg.http("http://xkcd.com/#{num}/info.0.json")
-      .get() (err, res, body) ->
-        if res.statusCode == 404
-          msg.send 'Comic not found.'
-        else
-          object = JSON.parse(body)
-          msg.send object.title, object.img, object.alt
+    msg.http("http://xkcd.com/info.0.json")
+          .get() (err,res,body) ->
+            if res.statusCode == 404
+               max = 0
+            else
+               max = JSON.parse(body).num
+               num = Math.floor((Math.random()*max)+1)
+               msg.http("http://xkcd.com/#{num}/info.0.json")
+               .get() (err, res, body) ->
+               object = JSON.parse(body)
+               msg.send object.title, object.img, object.alt, object.num


Flattening map array

Flattening map array

--- src/js/Map.coffee
+++ src/js/Map.coffee
@@ -7,17 +7,16 @@

     ### @constant ###
     # initialize grid
-    @grid = new Array(@size)
-    for x in [0...@size]
-      @grid[x] = new Array(@size)
-      for y in [0...@size]
-        @grid[x][y] = new Array(@size)
+    @grid = new Array Math.pow(@size, 3)

     @setNeedsRedraw yes

+  setBlock: (block, x, y, z) ->
+    @grid[x + y * @size + z * @size * @size] = block
+
   getBlock: (x, y, z) ->
     throw new Error unless x? and y? and z?
-    return @grid[x][y][z]
+    return @grid[x + y * @size + z * @size * @size]

   selectBlock: (@selectedBlock) ->
     @setNeedsRedraw yes


added per-formula comments

added per-formula comments

--- src/spark-scroll.coffee
+++ src/spark-scroll.coffee
@@ -16,8 +16,13 @@
   #
   # each property of the sparkFormulas object is a formula variable

+  # top of the element hits the top of the viewport
   top: (element, container, rect, containerRect, offset) ->  ~~(rect.top - containerRect.top + offset)
+
+  # top of the element hits the center of the viewport
   center: (element, container, rect, containerRect, offset) ->  ~~(rect.top - containerRect.top - container.clientHeight/2 + offset)
+
+  # top of the element hits the bottom of the viewport
   bottom: (element, container, rect, containerRect, offset) ->  ~~(rect.top - containerRect.top - container.clientHeight + offset)
 }


Removed some of those nasty curly braces...

--- src/klarna.coffee
+++ src/klarna.coffee
@@ -223,10 +223,10 @@
     f = () ->
       new Promise (resolve, reject) ->
         # New status
-        data = {status: 'created'}
+        data = status: 'created'
         # If merchant reference(s), add to data to send
         if orderid1?
-          data.merchant_reference = {orderid1: orderid1}
+          data.merchant_reference = orderid1: orderid1
         if orderid2?
           data.merchant_reference.orderid2 = orderid2
         # Update order


Fixed problem with an api call to ecConfirmChange

--- coffee/lightbox-plans.controller.coffee
+++ coffee/lightbox-plans.controller.coffee
@@ -105,7 +105,7 @@
         currency = @.validPlan.currency

         @analytics.ecAddToCart(@.planId, @.validPlan.name, amount)
-        @analytics.ecConfirmPlan(@.planId, @.validPlan.name, amount)
+        @analytics.ecConfirmChange(@.planId, @.validPlan.name, amount)

         if @.myPlan && @.myPlan.customer_id?
             plan = {


Added support for non-tag logging, stack printing on errors and printing with margin

--- src/logger.coffee
+++ src/logger.coffee
@@ -21,7 +21,7 @@
 # Private methods
 getNonOcuppyingLength = (str) -> str.length - stripColor(str).length

-tag = (txt, style) -> style(_.padEnd(txt, LEFT_MARGIN)) + TAG_INDICATOR
+tag = (txt, style, tagString) -> style(_.padEnd(txt, LEFT_MARGIN)) + tagString

 fold = (string, leftPad = LEFT_PADSTRING_LONG_LINES) ->
     cols = Math.max MINIMUM_COLS, MAX_COLS_PER_LINE - leftPad.length
@@ -49,15 +49,17 @@
     else
         last

-createWriter = (txt, styler, stream = stdout) => (msg, { endline = on, margin = off } = {}) =>
-    msg = inspect msg unless _.isString msg
+createWriter = (txt, styler, { stream = stdout, tagString = TAG_INDICATOR } = {}) =>
+    (msg, { endline = on, margin = off } = {}) =>
+        msg = inspect msg unless _.isString msg

-    msg += "\n" if endline is on
-    if margin
-        stream.write "\n " + tag(txt, styler) + fold(msg, LEFT_PADSTRING_LONG_LINES + " ") + "\n"
-    else
-        stream.write tag(txt, styler) + fold(msg)
-    @
+        msg += "\n" if endline is on
+        if margin
+            stream.write "\n " + tag(txt, styler, tagString) +
+            fold(msg, LEFT_PADSTRING_LONG_LINES + " ") + "\n"
+        else
+            stream.write tag(txt, styler, tagString) + fold(msg)
+        @

 # Exposed methods
 @write = (str, stream = stdout) => stream.write str; @
@@ -72,6 +74,8 @@
         verboseWriter args... if global.cli?.verbose?
         @

+@noTag = @n = createWriter "", _.identity, { tagString: _.repeat(" ", TAG_INDICATOR.length) }
+
 @info = @i = createWriter INFO, styler.info

 @updateInfo = (msg) => @eraseLine(); @info(msg, endline: off); @
@@ -79,8 +83,11 @@
 @warn = @w = createWriter WARN, styler.warn

 @error = @e = do ->
-    errorWriter = createWriter ERROR, styler.error, stderr
-    (msg, { margin = off, exit = no, exitCode = 1 } = {}) ->
+    errorWriter = createWriter ERROR, styler.error, { stream: stderr }
+    (msg, { margin = off, exit = no, exitCode = 1, printStack = exit } = {}) ->
+        if printStack
+            stack = (new Error).stack.split("\n")[2..].join("\n")
+            msg = msg + "\n#{_.trimEnd stack, '\n'}"
         ret = errorWriter msg, margin: margin, endline: on
         process.exit exitCode if exit is yes
         ret


Fixed a bug (#67) that led to error messages in Atom

--- lib/atom-html-preview-view.coffee
+++ lib/atom-html-preview-view.coffee
@@ -39,7 +39,8 @@

   destroy: ->
     # @unsubscribe()
-    @editorSub.dispose()
+    if editorSub?
+      @editorSub.dispose()

   subscribeToFilePath: (filePath) ->
     @trigger 'title-changed'


Use --install-js not install_js to silence warn

--- bokehjs/gulp/tasks/install.coffee
+++ bokehjs/gulp/tasks/install.coffee
@@ -17,7 +17,7 @@
 gulp.task "install", ->
   # installs js and css
   # note: sets cwd as parent dir so that LICENSE.txt is accessible to setup.py
-  setup = spawn "python", ["setup.py", "--install_js"], {cwd: "../"}
+  setup = spawn "python", ["setup.py", "--install-js"], {cwd: "../"}
   for output in ["stdout", "stderr"]
     setup[output].setEncoding "utf8"
     setup[output].on "data", handleOutput


fix opening a notification by clicking on .btn-toolbar

--- lib/notifications-log-item.coffee
+++ lib/notifications-log-item.coffee
@@ -30,7 +30,7 @@
     @element.appendChild(notificationElement)
     @element.appendChild(@timestamp)
     @element.addEventListener 'click', (e) =>
-      if not e.target.closest('.btn-toolbar')?
+      if not e.target.closest('.btn-toolbar a, .btn-toolbar button')?
         @emitter.emit 'click'

     @disposables.add new Disposable => @element.remove()


Remove unneeded require

Remove unneeded require

--- src/extensions/outline-view/outline-view.coffee
+++ src/extensions/outline-view/outline-view.coffee
@@ -1,6 +1,5 @@
 {View, $$} = require 'space-pen'
 SelectList = require 'select-list'
-_ = require 'underscore'
 Editor = require 'editor'
 TagGenerator = require 'outline-view/tag-generator'


stupid bugfix of some jquery mutation stuff when switching to find page (and scrolls funny)

--- salvus/page/project.coffee
+++ salvus/page/project.coffee
@@ -379,17 +379,20 @@
         @container.find(".project-pages").children().removeClass('active')
         @container.find(".file-pages").children().removeClass('active')
         @container.css(position: 'static')
-        for tab in @tabs
-            if tab.name == name
-                @current_tab = tab
-                tab.target.show()
-                tab.label.addClass('active')
-                tab.onshow?()
-                @focus()
-            else if tab.name == @_last_display_tab_name
-                tab.onblur?()
-                tab.target.hide()
-        @_last_display_tab_name = name
+        f = () =>
+            for tab in @tabs
+                if tab.name == @_last_display_tab_name
+                    tab.onblur?()
+                    tab.target.hide()
+            @_last_display_tab_name = name
+            for tab in @tabs
+                if tab.name == name
+                    @current_tab = tab
+                    tab.target.show()
+                    tab.label.addClass('active')
+                    tab.onshow?()
+                    @focus()
+        require('async').nextTick(f)   # horrible temporary hack until this all gets react.

         if name == 'project-new-file'
             @actions.set_next_default_filename(require('account').default_filename())


remove todo

remove todo

--- spec/acceptance.spec.coffee
+++ spec/acceptance.spec.coffee
@@ -65,7 +65,6 @@

     beforeEach fetchPage "/"

-    # TODO: how to test that css compiled correctly? Or the href attrs even point to something.
     it "We have css links", ->
       $ = @browser.window.jQuery
       expect($("link[rel='stylesheet']").size()).toBeGreaterThan 0


Using elapsed time in delayed events

Using elapsed time in delayed events

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -64,7 +64,7 @@
   @returns {Engine} self
   ###
   delay: (seconds, fn) ->
-    delayedEvents.push
+    delayEvents.push
       delay: seconds
       fn: fn


levels and default game states

levels and default game states

--- src/title_screen.coffee
+++ src/title_screen.coffee
@@ -5,6 +5,6 @@
     engine.nextLevel() if justPressed.any

   self.bind "overlay", (canvas) ->
-    drawTitleText canvas, window.title, "Press any key to start"
+    self. canvas, window.title, "Press any key to start"

   return self


activity: add glance channel action

activity: add glance channel action

--- client/activity/lib/flux/actions/channel.coffee
+++ client/activity/lib/flux/actions/channel.coffee
@@ -376,6 +376,23 @@

   { SET_CHANNEL_PARTICIPANTS_DROPDOWN_VISIBILITY } = actionTypes
   dispatch SET_CHANNEL_PARTICIPANTS_DROPDOWN_VISIBILITY, { visible }
+
+
+emptyPromise = new Promise (resolve) -> resolve()
+
+glance = do (glancingMap = {}) -> (channelId) ->
+
+  return emptyPromise  if glancingMap[channelId]
+
+  glancingMap[channelId] = yes
+
+  { GLANCE_CHANNEL_BEGIN, GLANCE_CHANNEL_SUCCESS } = actionTypes
+
+  dispatch GLANCE_CHANNEL_BEGIN, { channelId }
+
+  kd.singletons.socialapi.channel.updateLastSeenTime { channelId }, (args...) ->
+    glancingMap[channelId] = no
+    dispatch GLANCE_CHANNEL_SUCCESS, { channelId }

 module.exports = {
@@ -393,5 +410,6 @@
   loadChannelsByQuery
   setChannelParticipantsDropdownVisibility
   deletePrivateChannel
+  glance
 }


:bug: Fix broken test cases

:bug: Fix broken test cases

These test cases were not running due to indentation errors.
The tests for commands 'dj' and 'dk' now correctly fail.

--- spec/operators-spec.coffee
+++ spec/operators-spec.coffee
@@ -278,55 +278,61 @@

     describe "when followed by an j", ->
       beforeEach ->
-        originalText = "12345\nabcde\nABCDE"
-        editor.setText(originalText)
-
-        describe "on the beginning of the file", ->
+        @originalText = "12345\nabcde\nABCDE"
+        editor.setText(@originalText)
+
+      describe "on the beginning of the file", ->
+        beforeEach ->
           editor.setCursorScreenPosition([0, 0])
-          it "deletes the next two lines", ->
-            keydown('d')
-            keydown('j')
-            expect(editor.getText()).toBe("ABCDE")
-
-        describe "on the end of the file", ->
-          editor.setCursorScreenPosition([4,2])
-          it "deletes nothing", ->
-            keydown('d')
-            keydown('j')
-            expect(editor.getText()).toBe(originalText)
-
-        describe "on the middle of second line", ->
-          editor.setCursorScreenPosition([2,1])
-          it "deletes the last two lines", ->
-            keydown('d')
-            keydown('j')
-            expect(editor.getText()).toBe("12345")
+        it "deletes the next two lines", ->
+          keydown('d')
+          keydown('j')
+          expect(editor.getText()).toBe("ABCDE")
+
+      describe "on the end of the file", ->
+        beforeEach ->
+          editor.setCursorScreenPosition([2, 4])
+        it "deletes nothing", ->
+          keydown('d')
+          keydown('j')
+          expect(editor.getText()).toBe(@originalText)
+
+      describe "on the middle of second line", ->
+        beforeEach ->
+          editor.setCursorScreenPosition([1,2])
+        it "deletes the last two lines", ->
+          keydown('d')
+          keydown('j')
+          expect(editor.getText()).toBe("12345")

     describe "when followed by an k", ->
       beforeEach ->
-        originalText = "12345\nabcde\nABCDE"
-        editor.setText(originalText)
-
-        describe "on the end of the file", ->
-          editor.setCursorScreenPosition([4, 2])
-          it "deletes the bottom two lines", ->
-            keydown('d')
-            keydown('k')
-            expect(editor.getText()).toBe("ABCDE")
-
-        describe "on the beginning of the file", ->
+        @originalText = "12345\nabcde\nABCDE"
+        editor.setText(@originalText)
+
+      describe "on the end of the file", ->
+        beforeEach ->
+          editor.setCursorScreenPosition([2,4])
+        it "deletes the bottom two lines", ->
+          keydown('d')
+          keydown('k')
+          expect(editor.getText()).toBe("ABCDE")
+
+      describe "on the beginning of the file", ->
+        beforeEach ->
           editor.setCursorScreenPosition([0,0])
-          it "deletes nothing", ->
-            keydown('d')
-            keydown('k')
-            expect(editor.getText()).toBe(originalText)
-
-        describe "when on the middle of second line", ->
-          editor.setCursorScreenPosition([2,1])
-          it "deletes the first two lines", ->
-            keydown('d')
-            keydown('k')
-            expect(editor.getText()).toBe("12345")
+        it "deletes nothing", ->
+          keydown('d')
+          keydown('k')
+          expect(editor.getText()).toBe(@originalText)
+
+      describe "when on the middle of second line", ->
+        beforeEach ->
+          editor.setCursorScreenPosition([1,2])
+        it "deletes the first two lines", ->
+          keydown('d')
+          keydown('k')
+          expect(editor.getText()).toBe("12345")

   describe "the D keybinding", ->
@@ -479,11 +485,11 @@
         keydown('y')
         keydown('h')

-        it "saves the left letter to the default register", ->
-          expect(vimState.getRegister('"').text).toBe " "
-
-        it "moves the cursor position to the left", ->
-          expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+      it "saves the left letter to the default register", ->
+        expect(vimState.getRegister('"').text).toBe " "
+
+      it "moves the cursor position to the left", ->
+        expect(editor.getCursorScreenPosition()).toEqual [0, 3]

     describe "with a down motion", ->
       beforeEach ->


activity/flux: update like message action

--- client/activity/lib/flux/actions/message.coffee
+++ client/activity/lib/flux/actions/message.coffee
@@ -1,6 +1,7 @@
-kd = require 'kd'
+kd                     = require 'kd'
+whoami                 = require 'app/util/whoami'
+actionTypes            = require './actiontypes'
 generateFakeIdentifier = require 'app/util/generateFakeIdentifier'
-actionTypes = require './actiontypes'

 dispatch = (args...) -> kd.singletons.reactor.dispatch args...

@@ -120,16 +121,19 @@
     LIKE_MESSAGE_FAIL
     LIKE_MESSAGE_SUCCESS } = actionTypes

-  dispatch LIKE_MESSAGE_BEGIN, { messageId }
+  userId = whoami()._id
+
+  dispatch LIKE_MESSAGE_BEGIN, { messageId, userId }

   socialapi.message.like { id: messageId }, (err) ->
     if err
-      dispatch LIKE_MESSAGE_FAIL, { err, messageId }
-      return
-
-    kd.utils.wait 573, ->
-      socialapi.message.byId { id: messageId }, (err, message) ->
-        dispatch LIKE_MESSAGE_SUCCESS, { message }
+      dispatch LIKE_MESSAGE_FAIL, { err, messageId, userId }
+      return
+
+    socialapi.message.listLikers { id: messageId }, (err, likers) ->
+      kd.singletons.reactor.batch ->
+        likers.forEach (id) ->
+          dispatch LIKE_MESSAGE_SUCCESS, { userId: id, messageId }

 ###*


:lipstick:

:lipstick:

--- spec/operators-spec.coffee
+++ spec/operators-spec.coffee
@@ -23,8 +23,8 @@
     opts.raw = true
     keydown(key, opts)

-  describe "cancel operation is robust", ->
-    it "can call cancel operation, even if no operator pending", ->
+  describe "cancelling operations", ->
+    it "does not throw an error even if no operation is pending", ->
       # cancel operation pushes an empty input operation
       # doing this without a pending operation throws an exception
       expect(-> vimState.pushOperations(new Input(''))).toThrow()
@@ -34,12 +34,8 @@
       expect(vimState.isOperatorPending()).toBe true
       editor.commandModeInputView.viewModel.cancel()

-      # now again cancel op, although there is none pending
       expect(vimState.isOperatorPending()).toBe false
-
-      # which should not raise an exception
       expect(-> editor.commandModeInputView.viewModel.cancel()).not.toThrow()
-

   describe "the x keybinding", ->
     describe "on a line with content", ->
@@ -873,7 +869,6 @@
       keydown 'u'
       expect(editor.getText()).toBe "abc\n  012\n"

-
   describe "the a keybinding", ->
     beforeEach ->
       editor.getBuffer().setText("012\n")


activity: improve sanitizePayload helper

--- client/activity/lib/flux/helpers/message.coffee
+++ client/activity/lib/flux/helpers/message.coffee
@@ -1,3 +1,5 @@
+_ = require 'lodash'
+
 ###*
  * Sanitizes given payload to meet the request criteria.
  *
@@ -6,7 +8,7 @@
 ###
 sanitizePayload = (payload) ->

-  unless typeof payload is 'object'
+  unless _.isPlainObject payload
     payload = {}

   return payload


:lipstick:

:lipstick:


:white_check_mark:

--- spec/tree-view-spec.coffee
+++ spec/tree-view-spec.coffee
@@ -2078,6 +2078,8 @@
       expect(treeView.find('.directory .name:contains(test.txt)').length).toBe 1

   describe "Git status decorations", ->
+    [projectPath, modifiedFile, originalFileContent] = []
+
     beforeEach ->
       projectPath = fs.realpathSync(temp.mkdirSync('tree-view-project'))
       workingDirFixture = path.join(__dirname, 'fixtures', 'git', 'working-dir')
@@ -2130,6 +2132,31 @@
     describe "when a file is ignored", ->
       it "adds a custom style", ->
         expect(treeView.find('.file:contains(ignored.txt)')).toHaveClass 'status-ignored'
+
+    describe "when the projects is a symbolic link to the repository root", ->
+      beforeEach ->
+        symlinkPath = temp.path('tree-view-project')
+        fs.symlinkSync(projectPath, symlinkPath)
+        atom.project.setPaths([symlinkPath])
+        $(treeView.roots[0].entries).find('.directory:contains(dir)')[0].expand()
+
+        waitsFor (done) ->
+          disposable = atom.project.getRepositories()[0].onDidChangeStatuses ->
+            disposable.dispose()
+            done()
+
+      describe "when a file is modified", ->
+        it "adds custom style to it and its parent directories", ->
+          expect(treeView.find('.file:contains(b.txt)')).toHaveClass 'status-modified'
+          expect(treeView.find('.directory:contains(dir)')).toHaveClass 'status-modified'
+
+      describe "when a file looses its modified status", ->
+        it "updates custom style for it and its parent directories", ->
+          fs.writeFileSync(modifiedFile, originalFileContent)
+          atom.project.getRepositories()[0].getPathStatus(modifiedFile)
+
+          expect(treeView.find('.file:contains(b.txt)')).not.toHaveClass 'status-modified'
+          expect(treeView.find('.directory:contains(dir)')).not.toHaveClass 'status-modified'

   describe "when the resize handle is double clicked", ->
     beforeEach ->


Fix tests on Windows

Fix tests on Windows

--- spec/tree-view-spec.coffee
+++ spec/tree-view-spec.coffee
@@ -2598,7 +2598,12 @@
       describe "when a squashed directory is deleted", ->
         it "un-squashes the directories", ->
           jasmine.attachToDOM(workspaceElement)
-          piDir = $(treeView.roots[0].entries).find(".directory:contains(omicron#{path.sep}pi):first")[0]
+          if path.sep is '\\'
+            # First escape the backslashes for Coffeescript, then escape them for jQuery
+            piDir = $(treeView.roots[0].entries).find(".directory:contains(omicron\\\\pi):first")[0]
+          else
+            piDir = $(treeView.roots[0].entries).find(".directory:contains(omicron#{path.sep}pi):first")[0]
+
           treeView.focus()
           treeView.selectEntry(piDir)
           spyOn(atom, 'confirm').andCallFake (dialog) ->
@@ -2611,7 +2616,11 @@
       describe "when a file is created within a directory with another squashed directory", ->
         it "un-squashes the directories", ->
           jasmine.attachToDOM(workspaceElement)
-          piDir = $(treeView.roots[0].entries).find(".directory:contains(omicron#{path.sep}pi):first")[0]
+          if path.sep is '\\'
+            # First escape the backslashes for Coffeescript, then escape them for jQuery
+            piDir = $(treeView.roots[0].entries).find(".directory:contains(omicron\\\\pi):first")[0]
+          else
+            piDir = $(treeView.roots[0].entries).find(".directory:contains(omicron#{path.sep}pi):first")[0]
           expect(piDir).not.toBeNull()
           # omicron is a squashed dir, so searching for omicron would give us omicron/pi instead
           omicronPath = piDir.getPath().replace "#{path.sep}pi", ""
@@ -2630,7 +2639,11 @@
       describe "when a directory is created within a directory with another squashed directory", ->
         it "un-squashes the directories", ->
           jasmine.attachToDOM(workspaceElement)
-          piDir = $(treeView.roots[0].entries).find(".directory:contains(omicron#{path.sep}pi):first")[0]
+          if path.sep is '\\'
+            # First escape the backslashes for Coffeescript, then escape them for jQuery
+            piDir = $(treeView.roots[0].entries).find(".directory:contains(omicron\\\\pi):first")[0]
+          else
+            piDir = $(treeView.roots[0].entries).find(".directory:contains(omicron#{path.sep}pi):first")[0]
           expect(piDir).not.toBeNull()
           # omicron is a squashed dir, so searching for omicron would give us omicron/pi instead
           omicronPath = piDir.getPath().replace "#{path.sep}pi", ""
@@ -2735,7 +2748,7 @@
           atom.commands.dispatch(treeView.element, 'tree-view:remove')
           expect(dirView[0].directory.updateStatus).toHaveBeenCalled()

-    describe "when the project is a symbolic link to the repository root", ->
+    describe "on #darwin, when the project is a symbolic link to the repository root", ->
       beforeEach ->
         symlinkPath = temp.path('tree-view-project')
         fs.symlinkSync(projectPath, symlinkPath, 'junction')
@@ -3113,7 +3126,6 @@

       runs ->
         expect(atom.notifications.getNotifications()[0].getMessage()).toContain 'Opening folder in OS file manager failed'
-        expect(atom.notifications.getNotifications()[0].getDetail()).toContain 'ENOENT'

   describe "showCurrentFileInFileManager()", ->
     it "does nothing when no file is opened", ->


Fix session touch

Fix session touch

--- services/web/app/coffee/infrastructure/Server.coffee
+++ services/web/app/coffee/infrastructure/Server.coffee
@@ -109,8 +109,8 @@
 # Measure expiry from last request, not last login
 webRouter.use (req, res, next) ->
 	req.session.touch()
-	if req?.session?.user?
-		UserSessionsManager.touch(req.user, (err)->)
+	if AuthenticationController.isUserLoggedIn(req)
+		UserSessionsManager.touch(AuthenticationController.getSessionUser(req), (err)->)
 	next()

 webRouter.use ReferalConnect.use


Sidebar: Bind finder related events in finder pane.

--- client/ide/views/tabview/idefilestabview.coffee
+++ client/ide/views/tabview/idefilestabview.coffee
@@ -36,6 +36,12 @@

     @tabView.addPane filesPane

+    @on 'MachineMountRequested', (vmData) =>
+      @finderPane.emit 'MachineMountRequested', vmData
+
+    @on 'MachineUnmountRequested', (vmData) =>
+      @finderPane.emit 'MachineUnmountRequested', vmData
+
   createVMsPane: ->
     vmsPane    = new KDTabPaneView
       name     : 'VMs'
@@ -44,12 +50,6 @@
     vmsPane.addSubView new IDE.VMListPane
     @tabView.addPane  vmsPane

-    @on 'MachineMountRequested', (vmData) =>
-      @finderPane.emit 'MachineMountRequested', vmData
-
-    @on 'MachineUnmountRequested', (vmData) =>
-      @finderPane.emit 'MachineUnmountRequested', vmData
-
   createSettingsPane: ->
     settingsPane = new KDTabPaneView
       name       : 'Settings'


Update de.coffee

Update de.coffee

Moving translations for verification of email addresses to the root, as they aren't translated from errors.accounts within the useraccounts package.

--- t9n/de.coffee
+++ t9n/de.coffee
@@ -4,7 +4,7 @@
 de =

   t9Name: 'Deutsch'
-
+
   add: "hinzufügen"
   and: "und"
   back: "zurück"
@@ -42,7 +42,11 @@
   username: "Benutzername"
   usernameOrEmail: "Benutzername oder E-Mail"
   with: "mit"
-
+  "Verification email lost?" : "Verifizierungsemail verloren?"
+  "Send again" : "Erneut senden"
+  "Send the verification email again" : "Verifizierungsemail erneut senden"
+  "Send email again" : "Email erneut senden"
+  "A new email has been sent to you. If the email doesn't show up in your inbox, be sure to check your spam folder." : "Eine neue Email wurde verschickt. Sollte sich die Email nicht im Posteingang befinden, empfiehlt es sich, den Spamordner zu überprüfen."

   info:
     emailSent: "E-Mail gesendet"
@@ -62,7 +66,6 @@
     signupCodeRequired: "Registrierungscode benötigt."
     usernameIsEmail: "Benutzername darf keine E-Mail Adresse sein."
     usernameRequired: "Benutzername benötigt."
-

     accounts:

@@ -105,11 +108,7 @@
       "User not found": "Benutzer nicht gefunden"
       "Verify email link expired": "Link zur E-Mail Verifizierung ist abgelaufen"
       "Verify email link is for unknown address": "Link zur Verifizierung ist für eine unbekannte E-Mail Adresse"
-      "Verification email lost?" : "Verifizierungsemail verloren?"
-      "Send again" : "Erneut senden"
-      "Send the verification email again" : "Verifizierungsemail erneut senden"
-      "Send email again" : "Email erneut senden"
-      "A new email has been sent to you. If the email doesn't show up in your inbox, be sure to check your spam folder." : "Eine neue Email wurde verschickt. Sollte sich die Email nicht im Posteingang befinden, empfiehlt es sich, den Spamordner zu überprüfen."
+      "Already verified" : "Diese E-Mail-Adresse ist bereits verifiziert"

       #---- match
       "Match failed": "Abgleich fehlgeschlagen"


some small corrections

some small corrections

--- t9n/nl.coffee
+++ t9n/nl.coffee
@@ -70,14 +70,14 @@
       "Email already exists.": "Dit e-mailadres is al in gebruik."
       "Email doesn't match the criteria.": "e-mail voldoet niet aan de voorwaarden."
       "Invalid login token": "Ongeldig login token"
-      "Login forbidden": "Aanmelden verboden"
+      "Login forbidden": "Aanmelding geweigerd"
       #"Service " + options.service + " already configured":
       "Service unknown": "Sevice onbekend"
       "Unrecognized options for login request": "Onbekende optie voor login request"
       "User validation failed": "Gebruikers validatie mislukt"
       "Username already exists.": "Gebruikersnaam bestaat al."
       "You are not logged in.": "Je bent niet ingelogd."
-      "You've been logged out by the server. Please log in again.": "Je bent door de server uitgelogd. Opnieuw aanmelden svp."
+      "You've been logged out by the server. Please log in again.": "Je bent door de server afgemeld. Opnieuw aanmelden svp."
       "Your session has expired. Please log in again.": "Je sessie is verlopen. Opnieuw aanmelden svp."


Fix : `errors` and `info` translation are working back

Indentation in Coffescript is very important.

--- t9n/pl.coffee
+++ t9n/pl.coffee
@@ -40,15 +40,13 @@
   username: "Nazwa użytkownika"
   usernameOrEmail: "Nazwa użytkownika lub email"
   with: "z"
-
-
-info:
-  emailSent: "Adres email wysłany"
-  emailVerified: "Adres email zweryfikowany"
-  passwordChanged: "Hasło zmienione"
-  passwordReset: "Hasło wyzerowane"
-
-
+
+  info:
+    emailSent: "Adres email wysłany"
+    emailVerified: "Adres email zweryfikowany"
+    passwordChanged: "Hasło zmienione"
+    passwordReset: "Hasło wyzerowane"
+
   error:
     emailRequired: "Wymagany jest adres email."
     minChar: "7 znaków to minimalna długość hasła."
@@ -60,7 +58,6 @@
     signupCodeRequired: "Wymagany jest kod rejestracji."
     usernameIsEmail: "Adres email nie może być nazwą użytkownika."
     usernameRequired: "Wymagana jest nazwa użytkownika."
-

     accounts:


Now logging JavaScript exceptions to the console.

--- lib/server/browser/patches.coffee
+++ lib/server/browser/patches.coffee
@@ -39,8 +39,12 @@
                 try
                     window.run(code, filename)
                 catch e
+                    # TODO: log this based on debug flag.
+                    console.log(e.stack)
                     browser.consoleLogStream.write("JavaScript ERROR\n")
                     browser.consoleLogStream.write(e.stack + "\n")
+                    # TODO: JSDOM swallows this exception.
+                    throw e

 addDefaultHandlers = (html) ->
     html.HTMLAnchorElement.prototype._eventDefaults =


improve view panel status

improve view panel status

--- lib/stream/execute-command.coffee
+++ lib/stream/execute-command.coffee
@@ -20,15 +20,15 @@
         @agda.panelView.setContent command.content

       when 'info-action: current goal'
-        @agda.panelView.setStatus 'Current Goal'
+        @agda.panelView.setStatus 'Current Goal', 'info'
         @agda.panelView.setContent command.content

       when 'info-action: context'
-        @agda.panelView.setStatus 'Context'
+        @agda.panelView.setStatus 'Context', 'info'
         @agda.panelView.setContent command.content

       when 'info-action: goal type etc'
-        @agda.panelView.setStatus 'Goal type etc'
+        @agda.panelView.setStatus 'Goal type etc', 'info'
         @agda.panelView.setContent command.content

       when 'info-action: all goals'


Coffee.js :active-select

Coffee.js :active-select

--- app/assets/javascripts/keg_common.js.coffee
+++ app/assets/javascripts/keg_common.js.coffee
@@ -225,6 +225,13 @@
   $("[data-boolean-value]").each ->
     $(this).bind_boolean_value()

+  $("[data-active-select]").each ->
+    $url = $(this).data("active-select")
+    $(this).on
+      change: ->
+        $to_url = $url.replace /__template__/, $(this).val()
+        window.location = $to_url
+
   $("[data-token-input]").each ->
     $(this).tokenInput $(this).data("token-input"),
       theme: "facebook"


change default value logic

change default value logic

--- coffeescript/003-qwery-bonzo-bean/csmain.coffee
+++ coffeescript/003-qwery-bonzo-bean/csmain.coffee
@@ -15,7 +15,10 @@
   $ = (selector) -> bonzo(qwery(selector))

   domReady( ->
-      ps = url.params() or {a: 5, b: 10}
+      ps = url.params()
+      ps['a'] = 5 if not ps['a']
+      ps['b'] = 10 if not ps['b']
+
       ctx =
           keys: _.keys(ps)
           vals: ps


remove fake seed data from groups-page controller

--- app/components/group-page/group-page.coffee
+++ app/components/group-page/group-page.coffee
@@ -6,31 +6,8 @@
     Records.groups.findOrFetchByKey(groupId).then (group) ->
       $scope.group = group
       Records.buckets.fetchByGroupId(group.id)
-
+
     window.scrollHeight = 0;

     $scope.createProject = () ->
-      $location.path("/groups/#{$stateParams.groupId}/projects/new")
-
-    $scope.drafts = [
-      {
-        name: "90 Second Enspiral Animation",
-        author: "Alanna Krause",
-        age: 3
-      },
-      {
-        name: "Laser Cutter",
-        author: "Eugene Lynch",
-        age: 5
-      },
-      {
-        name: "Support Loomio crowdfunding campaign",
-        author: "Richard Bartlett",
-        age: 6
-      },
-      {
-        name: "Social Enterprise Weekend",
-        author: "Michael",
-        age: 10
-      }
-    ]+      $location.path("/groups/#{$stateParams.groupId}/projects/new")


Fix filtering.

Fix filtering.

--- app/js/controllers/people_controller.coffee
+++ app/js/controllers/people_controller.coffee
@@ -43,7 +43,7 @@
     officePeople = @get('model').filter(filterFunc)

     searchRegex = new RegExp(@get('searchTerm') || '', 'i')
-    officePeople.filter (item) =>
+    officePeople = officePeople.filter (item) =>
       item.matches(searchRegex)

     sortByName =


Change "current" to "HEAD" branch list indicator

--- lib/views/branch-list-view.coffee
+++ lib/views/branch-list-view.coffee
@@ -42,7 +42,7 @@
     $$ ->
       @li name, =>
         @div class: 'pull-right', =>
-          @span('Current') if current
+          @span('HEAD') if current

   confirmed: ({name}) ->
     @checkout name.match(/\*?(.*)/)[1]


FIX env

FIX env

--- src/module.coffee
+++ src/module.coffee
@@ -45,7 +45,7 @@
     deferred.promise

   on_TASK_RUNNING: (taskData, modulePreset, callback) ->
-    delay = if process.env.MCONN_MOULE_HELLOWORLD_DELAY then process.env.MCONN_MOULE_HELLOWORLD_DELAY else 250
+    delay = if process.env.MCONN_MODULE_HELLOWORLD_DELAY then process.env.MCONN_MODULE_HELLOWORLD_DELAY else 250
     Q.delay(delay)
     .then =>
       path = taskData.getData().taskId
@@ -59,7 +59,7 @@
       @failed(taskData, callback, error)

   on_TASK_FAILED: (taskData, modulePreset, callback) ->
-    delay = if process.env.MCONN_MOULE_HELLOWORLD_DELAY then process.env.MCONN_MOULE_HELLOWORLD_DELAY else 250
+    delay = if process.env.MCONN_MODULE_HELLOWORLD_DELAY then process.env.MCONN_MODULE_HELLOWORLD_DELAY else 250
     Q.delay(delay)
     .then =>
       path = taskData.getData().taskId
@@ -72,7 +72,7 @@
       @failed(taskData, callback, error)

   on_UNDEFINED_STATUS: (taskData, modulePreset, callback) ->
-    delay = if process.env.MCONN_MOULE_HELLOWORLD_DELAY then process.env.MCONN_MOULE_HELLOWORLD_DELAY else 0
+    delay = if process.env.MCONN_MODULE_HELLOWORLD_DELAY then process.env.MCONN_MODULE_HELLOWORLD_DELAY else 0
     Q.delay(delay)
     .then =>
       @logger.info("\"" + taskData.getData().taskStatus + "\" is an undefined taskStatus and the task


No <text> tag for edge if caption is not defined

--- app/scripts/alchemy/drawing/drawEdge.coffee
+++ app/scripts/alchemy/drawing/drawEdge.coffee
@@ -56,7 +56,9 @@
                 edge.append('rect')
                     .attr('class', 'edge-handler')
                 edge.append('line')
-                edge.append('text')
+
+                edge.filter((d,i) -> alchemy._edges[d.id]._rawEdge.caption?)
+                    .append('text')
         else
             @_createLink = (edge) ->
                 edge.append('path')
@@ -65,7 +67,8 @@
                 edge.append('path')
                     .attr('class', 'edge-line')
                     .attr('id', (d) -> "path-#{d.id}")
-                edge.append('text')
+                edge.filter((d,i) -> alchemy._edges[d.id]._rawEdge.caption?)
+                    .append('text')
                     .append('textPath')
                     .attr('class', 'textpath') # this is a workaround for a bug in webkit
         if not conf.curvedEdges


Added wolfcage to rowed names.

Added wolfcage to rowed names.

--- src/DOM.coffee
+++ src/DOM.coffee
@@ -58,14 +58,13 @@
             'CONTAINER':'wolfcage-thumbnailsmodal-montage-container'
         },
         'TOPROWEDITOR':{
-            'BUTTON_GENERATE': 'rowed-button-generate',
-            'BUTTON_RESET': 'rowed-button-resetrow',
-            'EDITOR_CONTAINER': 'rowed-editor-container',
-            'ROW_CONTAINER': 'rowed-slider-row-container',
-            'SLIDER_CONTAINER': 'rowed-slider-container',
-            'SLIDER':'rowed-slider',
-            'SLIDER_ARROW_LEFT':'rowed-slider-arrow-left',
-            'SLIDER_ARROW_RIGHT':'rowed-slider-arrow-right'
+            'BUTTON_GENERATE': 'wolfcage-rowed-button-generate',
+            'BUTTON_RESET': 'wolfcage-rowed-button-resetrow',
+            'EDITOR_CONTAINER': 'wolfcage-rowed-editor-container',
+            'ROW_CONTAINER': 'wolfcage-rowed-slider-row-container',
+            'SLIDER_CONTAINER': 'wolfcage-rowed-slider-container',
+            'SLIDER':'wolfcage-rowed-slider',
+            'SLIDER_TEXT':'wolfcage-rowed-slider-text',
         },
     }

@@ -87,8 +86,8 @@
             'THUMB_BOX':'wolfcage-thumbnailsmodal-rulethumb-box',
         },
         'TOPROWEDITOR':{
-            'EDITOR_CELL':'rowed-editor-cell',
-            'EDITOR_CELL_ACTIVE':'rowed-editor-cell-active',
+            'EDITOR_CELL':'wolfcage-rowed-editor-cell',
+            'EDITOR_CELL_ACTIVE':'wolfcage-rowed-editor-cell-active',
             'SLIDER_CELL_ACTIVE':'wolfcage-board-cell-active'
         },
     }
@@ -105,7 +104,7 @@
             'TAB_PREFIX':'wolfcage-tab-'
         },
         'TOPROWEDITOR':{
-            'SLIDER_COL':'rowed-slider-col-'
+            'SLIDER_COL':'wolfcage-rowed-slider-col-'
         },
     }


add ui field to intercom

add ui field to intercom

--- lineman/app/services/intercom_service.coffee
+++ lineman/app/services/intercom_service.coffee
@@ -10,6 +10,7 @@
        email: CurrentUser.email
        user_id: CurrentUser.id
        created_at: CurrentUser.createdAt
+       angular_ui: true

     shutdown: ->
       return unless window? and window.Intercom?


Fix for #290

Fix for #290

--- app/views/play/level/tome/spell_view.coffee
+++ app/views/play/level/tome/spell_view.coffee
@@ -499,4 +499,4 @@
     super()
     @firepad?.dispose()
     @ace.destroy()
-    @debugView.destroy()
+    @debugView?.destroy()


unsubstantial code formatting changes

unsubstantial code formatting changes

--- library/exposure/localized.coffee
+++ library/exposure/localized.coffee
@@ -69,11 +69,11 @@
         try _.extend shadow, request: request or null
         _.extend shadow, __isolated: yes, __origin: @
         translation = @obtainTranslation # get provider
+        setup = @setupTranslationTools # get installer
         execute = (a...) => translation.apply shadow, a
         return execute undefined, (language, messages) =>
             do -> context.translationLanguage = language
             do -> context.translationMessages = messages
-            assert setup = @setupTranslationTools or null
             send setup, (f) -> @setupTranslationTools = f
             context.inline -> @obtainTranslation = (l, c) ->
                 c @translationLanguage, @translationMessages


add toastr library to the standard preflight

--- library/membrane/preflight.coffee
+++ library/membrane/preflight.coffee
@@ -214,6 +214,7 @@
     @bower "loglevel"
     @bower "lodash"
     @bower "jquery"
+    @bower "toastr"
     @bower "chai"

     # This block here defines a set of remote dependencies that are


Resetting fields on parse.

Resetting fields on parse.

--- src/packet.coffee
+++ src/packet.coffee
@@ -177,6 +177,7 @@
     @pattern      = pattern
     @callback     = callback
     @patternIndex = 0
+    @fields       = []

     @nextField()
     @nextValue()
@@ -261,22 +262,18 @@
       # We add the parser and the user suppilied additional arguments onto the
       # callback arguments.
       #
-      # The pattern is set to null, our terminal condition, before the callback,
-      # and the fields are defensively copied, because the callback may specify
-      # a subsequent packet to parse.
+      # The pattern is set to null, our terminal condition, because the callback
+      # may specify a subsequent packet to parse.
       else if ++@patternIndex == @pattern.length
-        fields = @fields.slice()
-
-        fields.push(@pipeline(@pattern[@patternIndex -1 ], fields.pop()))
-
-        fields.push(this)
+        @fields.push(@pipeline(@pattern[@patternIndex -1 ], @fields.pop()))
+
+        @fields.push(this)
         for p in @user or []
-          fields.push(p)
+          @fields.push(p)

         @pattern        = null
-        @fields.length  = 0
-
-        @callback.apply null, fields
+
+        @callback.apply null, @fields

       # Otherwise we proceed to the next field in the packet pattern.
       else


Group no doc methods by entity file name

--- src/parser.coffee
+++ src/parser.coffee
@@ -321,15 +321,13 @@
         noDocClassNames.push noDocClass.className.cyan

       noDocMethodNames = []
-      prevFileName = ""
       noDocMethods.sort (method1, method2) ->
         method1.getShortSignature().localeCompare(method2.getShortSignature())
-      for noDocMethod in noDocMethods
-        if prevFileName != noDocMethod.entity.fileName
-          prevFileName = noDocMethod.entity.fileName
-          noDocMethodNames.push "\n#{prevFileName}".cyan
-
-        noDocMethodNames.push "  #{noDocMethod.getShortSignature()}"
+      noDocMethods = _.groupBy noDocMethods, ({entity}) -> entity.fileName
+      for fileName, methods of noDocMethods
+        noDocMethodNames.push "\n#{fileName}".cyan
+        for noDocMethod in methods
+          noDocMethodNames.push "  #{noDocMethod.getShortSignature()}"

       stats += "\nClasses missing docs:\n\n#{noDocClassNames.join('\n')}" if noDocClassNames.length > 0
       stats += "\n\nMethods missing docs:\n#{noDocMethodNames.join('\n')}" if noDocMethodNames.length > 0


Fix typo

Fix typo

--- cURLCodeGenerator.coffee
+++ cURLCodeGenerator.coffee
@@ -1,4 +1,4 @@
-# in API v1.1.0 and below (Paw 2.2.2 and below), require had no return value
+# in API v0.2.0 and below (Paw 2.2.2 and below), require had no return value
 ((root) -> root.Mustache = require("mustache.js") or root.Mustache)(this)

 addslashes = (str) ->


typos

typos

--- lib/assets/javascripts/attachinary.js.coffee
+++ lib/assets/javascripts/attachinary.js.coffee
@@ -56,8 +56,8 @@
       @files = @options.files

       @$form = @$input.closest('form')
-      @$submit = @$form.find(@options.submit_selector ? 'input[type=submit]')
-      @$wrapper = @$input.closest(@options.wrapper_container_selector) if @options.wrapper_container_selector?
+      @$submit = @$form.find(@config.submitSelector ? 'input[type=submit]')
+      @$wrapper = @$input.closest(@config.wrapperContainerSelector) if @config.wrapperContainerSelector?

       # infer operation form the received
       # data files. operation is updating if


fix params

fix params

--- src/scripts/idcf-vm-auto-stop.coffee
+++ src/scripts/idcf-vm-auto-stop.coffee
@@ -53,7 +53,7 @@
   machines.reduce (promise, i) ->
     promise
     .then ->
-      client.request action, { id: i.id }
+      client.request action, { id: i }
     .then ->
       new Promise (resolve) ->
         setTimeout resolve, 1000


facilities should have sector

facilities should have sector

--- dashboard/static/coffee/nmis/b_districts.coffee
+++ dashboard/static/coffee/nmis/b_districts.coffee
@@ -276,8 +276,11 @@
       clonedFacilitiesById

   facilityDataForSector: (sectorSlug)->
-    for own facId, fac of @facilityData when fac.sector.slug is sectorSlug
-      fac
+    for own facId, fac of @facilityData
+      if fac.sector is undefined
+        console.error("Facility does not have a sector:", fac)
+      else if fac.sector.slug is sectorSlug
+        fac

   loadData: ()->
     @_fetchModuleOnce "lga_data", "data/lga_data", (results)=>


Set superagent parser for text/javascript

--- src/Util/LiveGetter.coffee
+++ src/Util/LiveGetter.coffee
@@ -14,6 +14,8 @@
 request.parse['application/xml'] = parseXML
 request.parse['text/xml'] = parseXML

+# Some endpoint set their headers incorrectly...
+request.parse['text/javascript'] = request.parse['application/json']

 # LiveGetter manages a bunch of HTTP requests which will want to be refreshed on
 # a regular interval. A user of LiveGetter calls `liveGetter.get(myURL,


refactoring

refactoring

--- server/init/konnectors.coffee
+++ server/init/konnectors.coffee
@@ -15,7 +15,7 @@
             callback err
         else
             konnectorHash = {}
-            for konnector in konnectors
+            async.eachSeries konnectors, (konnector, callback) ->
                 konnectorHash[konnector.slug] = konnector
                 # Reset isImporting state to false if value is true
                 # This happens when the app is crashing while importing
@@ -26,6 +26,9 @@
                             log.debug "#{konnector.slug} | #{err}"
                         else
                             log.debug "#{konnector.slug}: reseting isImporting"
+                        callback()
+                else
+                    callback()

             konnectorsToCreate = []


Update the buildBinding function to take the type of binding as the first argument.

--- src/rivets.coffee
+++ src/rivets.coffee
@@ -263,7 +263,7 @@
     componentRegExp = @componentRegExp()

-    buildBinding = (node, type, declaration) =>
+    buildBinding = (binding, node, type, declaration) =>
       options = {}

       pipes = (pipe.trim() for pipe in declaration.split '|')
@@ -284,7 +284,7 @@
       if dependencies = context.shift()
         options.dependencies = dependencies.split /\s+/

-      @bindings.push new Rivets.Binding @, node, type, key, keypath, options
+      @bindings.push new Rivets[binding] @, node, type, key, keypath, options

     parse = (node) =>
       unless node in skipNodes
@@ -299,11 +299,11 @@

                 switch startToken.type
                   when 0 then node.data = startToken.value
-                  when 1 then buildBinding node, 'textNode', startToken.value
+                  when 1 then buildBinding 'TextBinding', node, null, startToken.value

                 for token in restTokens
                   node.parentNode.appendChild (text = document.createTextNode token.value)
-                  buildBinding text, 'textNode', token.value if token.type is 1
+                  buildBinding 'TextBinding', text, null, token.value if token.type is 1
         else if componentRegExp.test node.tagName
           type = node.tagName.replace(componentRegExp, '').toLowerCase()
           @bindings.push new Rivets.ComponentBinding @, node, type
@@ -328,7 +328,7 @@
           for attribute in attributes or node.attributes
             if bindingRegExp.test attribute.name
               type = attribute.name.replace bindingRegExp, ''
-              buildBinding node, type, attribute.value
+              buildBinding 'Binding', node, type, attribute.value

         parse childNode for childNode in node.childNodes