Fix AWS key references of terraformer worker in credentials module

Signed-off-by: Sonmez Kartal <d2d15c3d37396a5f2a09f8b42cf5f27d43a3fbde@koding.com>

--- config/credentials.default.coffee
+++ config/credentials.default.coffee
@@ -84,8 +84,8 @@
     region: options.region
     environment: options.environment
     aws:
-      key: credentials.awsKeys.worker_terraformer.accessKeyId
-      secret: credentials.awsKeys.worker_terraformer.secretAccessKey
+      key: awsKeys.worker_terraformer.accessKeyId
+      secret: awsKeys.worker_terraformer.secretAccessKey
       bucket: "kodingdev-terraformer-state-#{options.configName}"
     localStorePath:  "$KONFIG_PROJECTROOT/go/data/terraformer"
   paymentwebhook =


changed port to environment, fallback is 3000

--- config/app.coffee
+++ config/app.coffee
@@ -8,7 +8,7 @@

   # HTTP server (becomes secondary server when HTTPS is enabled)
   http:
-    port:         3000
+    port:         process.env.PORT || 3000
     hostname:     "0.0.0.0"

   # HTTPS server (becomes primary server if enabled)


client: appstorage: minor semantic notation

--- client/app/lib/appstorage.coffee
+++ client/app/lib/appstorage.coffee
@@ -73,8 +73,8 @@

     appId = @_applicationID
     return unless @_storage
-    return if @_storageData[group]?[appId]?['data']?[key]? then @_storageData[group][appId]['data'][key]
-    return if @_storage[group]?[appId]?['data']?[key]?     then @_storage[group][appId]['data'][key]
+    return if @_storageData[group]?[appId]?.data?[key]? then @_storageData[group][appId].data[key]
+    return if @_storage[group]?[appId]?.data?[key]?     then @_storage[group][appId].data[key]

   setValue: (key, value, callback, group = AppStorage.DEFAULT_GROUP_NAME, notify = no) ->
@@ -82,8 +82,8 @@
     appId                                    = @_applicationID
     @_storageData[group]                   or= {}
     @_storageData[group][appId]            or= {}
-    @_storageData[group][appId]['data']    or= {}
-    @_storageData[group][appId]['data'][key] = value
+    @_storageData[group][appId].data       or= {}
+    @_storageData[group][appId].data[key]    = value

     pack = @zip key, group, value


fix: clicking dropdown at mobile causes parent to close

--- client/controllers/header.coffee
+++ client/controllers/header.coffee
@@ -5,8 +5,9 @@
     $(event.currentTarget).removeClass('open')
   'click': (e) ->
     #check event.target's class to see if the click was meant to open/close a dropdown
-    if not $(e.target).hasClass("dropdown-toggle-nav") and $('.navbar-toggle').is(':visible')
-      $('.navbar-collapse').collapse('toggle')
+    if $(e.target).hasClass('dropown') and $(e.target).hasClass('open')
+      $(event.currentTarget).removeClass('open')
+
   "click #logOut": ->
     Meteor.logout()


calculate fetchIndex in controller on changes

--- client/lanes/models/Query.coffee
+++ client/lanes/models/Query.coffee
@@ -26,6 +26,7 @@
         sortBy:     type: 'any'
         component:  type: 'function'
         onColumnClick: type: 'function'
+        fetchIndex: type: 'integer'

     derived:
         default_value: deps: ['id'], fn: ->
@@ -39,12 +40,6 @@
             deps: ['model_field'], fn: ->
                 type = @model_field?.type || 'string'
                 if type == "code" then "string" else type
-        fetchIndex:
-            fn: ->
-                fetchIndex = 0
-                for field, index in this.collection.models
-                    return fetchIndex if this == field
-                    fetchIndex += 1 if field.query

     validValue: (value) ->
         if this.type == 'n'
@@ -59,6 +54,7 @@

     constructor: (models, options) ->
         @query = options.query
+        this.on('add remove reset', @calculateFetchIndexes)
         this.on('change', (changing) ->
             return unless changing.selected
             for model in @models
@@ -66,7 +62,12 @@
         )
         super
         @visible = @subcollection(where: {visible: true})
-
+        @calculateFetchIndexes()
+
+    calculateFetchIndexes: ->
+        index = 0
+        for field in @models
+            field.fetchIndex = if field.query then index++ else undefined

 class Operator extends Lanes.Models.Base
     registerForPubSub: false


Doc fix

Doc fix

--- client/modules/middleware.coffee
+++ client/modules/middleware.coffee
@@ -35,7 +35,7 @@

   # ## Middleware#dispatch
   #
-  # * (mixed) `...` - One or more values to pass to the middleware.
+  # * (mixed) `...` - Zero or more values to pass to the middleware.
   #
   # * (function) `fn` - A function invoked when the middleware stack has
   # finished. If an error occurred, it will be passed as the first argument.


rename CSS animation settings to avoid possible naming conflicts now that they are public


cleanup

cleanup

--- SingularityUI/config.coffee
+++ SingularityUI/config.coffee
@@ -1,6 +1,7 @@
 exports.config =

     paths:
+
         public: '../SingularityService/src/main/resources/static'

     files:


Rest_in bug fixes

Rest_in bug fixes

--- lib/adapters/rest_in.coffee
+++ lib/adapters/rest_in.coffee
@@ -89,10 +89,10 @@
       @queryTimeout = properties.queryTimeout

     if properties.url
-      @url = url
+      @url = properties.url
       url_props = url.parse(properties.url)
-      if typeof url_props.port is "number"
-        @port = url_props.port
+      if url_props.port and parseInt(url_props.port) > 0
+        @port = parseInt(url_props.port)

       if typeof url_props.hostname is "string" and url_props.hostname isnt "*"
         @hostname = url_props.hostname


close #4

close #4

--- lib/atom-live-server.coffee
+++ lib/atom-live-server.coffee
@@ -29,7 +29,7 @@

   getPaths: ->
     paneItem = atom.workspace.getActivePaneItem()
-    file = paneItem?.buffer.file
+    file = paneItem?.buffer?.file
     filePath = file?.path

     projectPaths = atom.project.getPaths()


Add max property to constraints parameter of Utils.textSize

When true, the constraints will only define the maximum bounding box of the textSize


:bug: fix unintended shadowing of "layerSnapshot" variable on serializeSnapshot


add easy to click toggle links

add easy to click toggle links

--- led-server.coffee
+++ led-server.coffee
@@ -17,12 +17,12 @@

 app.get '/on/:id', (req, res) ->
   io[req.params.id].set()
-  res.send('on')
+  res.send("#{req.params.id} on
 turn off")

 app.get '/off/:id', (req, res) ->
   io[req.params.id].reset()
   clearInterval beatsInterval
-  res.send('off')
+  res.send("#{req.params.id} off
 turn on")

 app.get '/beats/:id', (req, res) ->
   beatsInterval = setInterval ->
@@ -35,10 +35,12 @@

 app.get '/toggle/:id', (req, res) ->
   if io[req.params.id].value == 0
-    io[req.params.id].set()
+    io[req.params.id].set ->
+      res.send("toggled to #{io[req.params.id].value}
 toggle")
   else
-    io[req.params.id].reset()
-  res.send("toggled to #{io[req.params.id].value}")
+    io[req.params.id].set 0, ->
+      res.send("toggled to #{io[req.params.id].value}
 toggle")
+

 # tie the button to the led
 io[22].on 'change', (val) ->


reduce timeout a little

reduce timeout a little

--- src/smc-webapp/redux_account.coffee
+++ src/smc-webapp/redux_account.coffee
@@ -307,7 +307,7 @@
         # wait for sign in to finish and cookie to get set, then redirect
         f = ->
             window.location.href = "https://authenticated?api_key=#{mesg.api_key}"
-        setTimeout(f, 3000)
+        setTimeout(f, 2000)
     redux.getActions('account').set_user_type('signed_in')

 webapp_client.on 'signed_out', ->


fix express deprecated wrning for del

fix express deprecated wrning for del

--- server/controllers/routes.coffee
+++ server/controllers/routes.coffee
@@ -6,10 +6,10 @@
     'search':
         get: index.search
     'search/:id':
-        del: index.delete
+        delete: index.delete
     'doctype_meta_infos':
         get: index.doctype_meta_infos
     'doctype_delete_all' :
-        del: index.doctype_delete_all
+        delete: index.doctype_delete_all
     'initvalues.js':
         get: index.initvalues


Handle errors gracefully.

Handle errors gracefully.

--- server/express/lib/server.coffee
+++ server/express/lib/server.coffee
@@ -44,16 +44,6 @@
   gitlog = stdout
   )

-errorHandler = (res) ->
-    fired = false
-    return (error) ->
-      if !fired
-        fired = true
-        res.statusCode = 500
-        res.end 'Server ' + error
-      else
-        console.log "Allready fired " + error
-
 # Set export objects for node and coffee to a function that generates a sfw server.
 module.exports = exports = (argv) ->
   # Create the main application object, app.
@@ -89,6 +79,18 @@
   # that is passed in and then does its
   # best to supply sane defaults for any arguments that are missing.
   argv = defargs(argv)
+  errorHandler = (req, res, next) ->
+    fired = false
+    res.e = (error, status) ->
+      if !fired
+        fired = true
+        res.statusCode = status or 500
+        res.end 'Server ' + error
+        console.log("Res sent: " + res.statusCode + ' ' + error) if argv.debug
+      else
+        console.log "Allready fired " + error
+    next()
+
   app.startOpts = do ->
     options = {}
     for own k, v of argv
@@ -112,12 +114,12 @@
     path.exists(argv.id, (exists) ->
       if exists
         fs.readFile(argv.id, (err, data) ->
-          if err then throw err
+          if err then return cb err
           owner += data
           cb())
       else if id
         fs.writeFile(argv.id, id, (err) ->
-          if err then throw err
+          if err then return cb err
           console.log("Claimed by #{id}")
           owner = id
           cb())
@@ -167,7 +169,8 @@
         else
           done(null, false)
       else
-        setOwner id, ->
+        setOwner id, (e) ->
+          if e then return done(e)
           done(null, {id})
     )
   )))
@@ -226,6 +229,7 @@
     app.use(express.session({ secret: 'notsecret'}))
     app.use(passport.initialize())
     app.use(passport.session())
+    app.use(errorHandler)
     app.use(app.router)
     app.use(express.static(argv.c))
     app.use(openIDErr)
@@ -302,22 +306,21 @@
   )

   app.get ////plugins/(factory/)?factory.js///, (req, res) ->
-    onerr = errorHandler(res)
     cb = (e, catalog) ->
-      if e then return onerr(e)
+      if e then return res.e(e)
       res.write('window.catalog = ' + JSON.stringify(catalog) + ';')
       fs.createReadStream(argv.c + '/plugins/meta-factory.js').pipe(res)

     glob argv.c + '/**/factory.json', (e, files) ->
       if e then return cb(e)
       files = files.map (file) ->
-        return fs.createReadStream(file).on('error', onerr).pipe(
+        return fs.createReadStream(file).on('error', res.e).pipe(
           JSONStream.parse([false]).on 'root', (el) ->
             @.emit 'data', el
         )

       es.concat.apply(null, files)
-        .on('error', onerr)
+        .on('error', res.e)
         .pipe(es.writeArray(cb))

   ###### Json Routes ######
@@ -326,7 +329,7 @@
   app.get(///^/([a-z0-9-]+)\.json$///, cors, (req, res) ->
     file = req.params[0]
     pagehandler.get(file, (e, page, status) ->
-      if e then throw e
+      if e then return res.e e
       logWatchSocket.emit 'fetch', page unless status
       res.json(page, status)
     )
@@ -357,13 +360,13 @@
     path.exists(argv.status, (exists) ->
       if exists
         fs.writeFile(favLoc, buf, (e) ->
-          if e then throw e
+          if e then return res.e e
           res.send('Favicon Saved')
         )
       else
         mkdirp(argv.status, 0777, ->
           fs.writeFile(favLoc, buf, (e) ->
-            if e then throw e
+            if e then return res.e e
             res.send('Favicon Saved')
           )
         )
@@ -421,7 +424,7 @@
     action = JSON.parse(req.body.action)
     # Handle all of the possible actions to be taken on a page,
     actionCB = (e, page, status) ->
-      if e then throw e
+      if e then return res.e e
       if status is 404
         res.send(page, status)
       console.log page if argv.debug
@@ -462,7 +465,7 @@
       page.journal.push(action)
       console.log page
       pagehandler.put(req.params[0], page, (e) ->
-        if e then throw e
+        if e then return res.e e
         res.send('ok')
         console.log 'saved' if argv.debug
       )
@@ -518,7 +521,9 @@

   #### Start the server ####
   # Wait to make sure owner is known before listening.
-  setOwner( null, ->
+  setOwner( null, (e) ->
+    # Throw if you can't find the initial owner
+    if e then return throw e
     app.listen(argv.p, argv.o if argv.o)
     console.log("Smallest Federated Wiki server listening on #{app.address().port} in mode: #{app.settings.env}")
   )


Ignore parameter of OBJECT

Ignore parameter of OBJECT

--- lib/Parser.coffee
+++ lib/Parser.coffee
@@ -1,5 +1,5 @@
 { nodes } = require 'coffee-script'
-{ Value, Code, Block, Literal, For, Obj, Assign, Access } = require '../node_modules/coffee-script/lib/coffee-script/nodes'
+{ Value, Code, Block, Literal, For, Obj, Assign } = require '../node_modules/coffee-script/lib/coffee-script/nodes'
 { Range } = require 'atom'
 { inspect } = require 'util'

@@ -77,15 +77,15 @@

     target

-  @traverseCode: (code, target, dests = [], depth = 0) ->
+  @traverseCode: (parent, target, dests = []) ->
     isFixed = false

-    code.eachChild (child) ->
+    parent.eachChild (child) ->
       if child instanceof Code
         isContains = Parser.isContains child, target
         isDeclared = Parser.isDeclared child, target
         if isContains
-          [ childDests, isChildFixed ] = Parser.traverseCode child, target, null, depth++
+          [ childDests, isChildFixed ] = Parser.traverseCode child, target, null
           if isDeclared or isChildFixed
             dests = childDests
             isFixed = true
@@ -95,6 +95,8 @@
         else if isDeclared
           return false

+      return true if child instanceof Value and parent.context is 'object' and parent instanceof Assign
+
       if child instanceof For
         if Parser.isSameLiteral child.name, target
           dests.push child.name
@@ -103,7 +105,7 @@
       if Parser.isSameLiteral child, target
         dests.push child

-      [ childDests, isChildFixed ] = Parser.traverseCode child, target, dests, depth++
+      [ childDests, isChildFixed ] = Parser.traverseCode child, target, dests
       if isChildFixed
         dests = childDests
         isFixed = true


Fix detail view on spawn error

Fix detail view on spawn error

--- lib/ghc-modi-process.coffee
+++ lib/ghc-modi-process.coffee
@@ -41,7 +41,7 @@
     if res.error?
       atom.notifications.addError "Haskell-ghc-mod: ghc-mod failed to launch
         it is probably missing or misconfigured",
-        details: res.error
+        detail: res.error
         dismissable: true
     if res.status != 0
       # no redirect support


added comment providing the provenance for the jQuery AJAX transport. Also changed the guard to look explicitly for IE versions 8 and 9, since earlier versions don't have XDomainRequest and version 10's XHR object will support CORS

--- lib/assets/javascripts/firehose/long_poll.js.coffee
+++ lib/assets/javascripts/firehose/long_poll.js.coffee
@@ -127,7 +127,9 @@
   xhr

 # Let's try to hack in support for IE8+ via the XDomainRequest object!
-if window.XDomainRequest?
+# This code was shamelessly stolen from:
+# https://github.com/jaubourg/ajaxHooks/blob/master/src/ajax/xdr.js
+if $.browser.msie and parseInt($.browser.version, 10) in [8, 9]
   jQuery.ajaxTransport (s) ->
     if s.crossDomain and s.async
       if s.timeout


Get the active text editor from the workspace instead of the element

Atom 1.13.0 started sending elements without a model field.

Fixes #147

--- lib/idris-controller.coffee
+++ lib/idris-controller.coffee
@@ -48,8 +48,7 @@
     @statusbar.destroy()

   # get the word or operator under the cursor
-  getWordUnderCursor: (editorView) ->
-    editor = editorView.model
+  getWordUnderCursor: (editor) ->
     options =
       wordRegex: /(^[	 ]*$|[^\s\/\\\(\)":,\.;<>~!@#\$%\^&\*\|\+=\[\]\{\}`\?\-…]+)|(\?[-!#\$%&\*\+\.\/<=>@\\\^\|~:]+|[-!#\$%&\*\+\.\/<=>@\\\^\|~:][-!#\$%&\*\+\.\/<=>@\\\^\|~:\?]*)+/g
     cursorPosition = editor.getLastCursor().getCurrentWordBufferRange options
@@ -64,6 +63,9 @@
       @messages.attach()
       @messages.hide()
     @model.setCompilerOptions compilerOptions
+
+  getEditor: () ->
+    atom.workspace.getActiveTextEditor()

   stopCompiler: =>
     @model?.stop()
@@ -109,10 +111,10 @@
     else
       atom.workspace.saveActivePaneItemAs()

-  typecheckFile: ({ target }) =>
-    # the file needs to be saved for typechecking
-    @saveFile target.model
-    uri = target.model.getURI()
+  typecheckFile: (event) =>
+    editor = @getEditor()
+    @saveFile editor
+    uri = editor.getURI()
     @messages.setTitle 'Idris: Typechecking...'
     @messages.clear()

@@ -128,8 +130,9 @@
       .subscribe successHandler, @displayErrors

   getDocsForWord: ({ target }) =>
-    word = Symbol.serializeWord @getWordUnderCursor(target)
-    uri = target.model.getURI()
+    editor = @getEditor()
+    uri = editor.getURI()
+    word = Symbol.serializeWord @getWordUnderCursor(editor)

     successHandler = ({ responseType, msg }) =>
       [type, highlightingInfo] = msg
@@ -151,10 +154,9 @@
       .subscribe successHandler, @displayErrors

   getTypeForWord: ({ target }) =>
-    editor = target.model
-    @saveFile editor
-    uri = editor.getURI()
-    word = Symbol.serializeWord @getWordUnderCursor(target)
+    editor = @getEditor()
+    uri = editor.getURI()
+    word = Symbol.serializeWord @getWordUnderCursor(editor)

     successHandler = ({ responseType, msg }) =>
       [type, highlightingInfo] = msg
@@ -175,12 +177,12 @@
       .subscribe successHandler, @displayErrors

   doCaseSplit: ({ target }) =>
-    editor = target.model
+    editor = @getEditor()
     @saveFile editor
     uri = editor.getURI()
     cursor = editor.getLastCursor()
     line = cursor.getBufferRow()
-    word = @getWordUnderCursor target
+    word = @getWordUnderCursor editor

     successHandler = ({ responseType, msg }) ->
       [split] = msg
@@ -194,11 +196,11 @@
       .subscribe successHandler, @displayErrors

   doAddClause: ({ target }) =>
-    editor = target.model
+    editor = @getEditor()
     @saveFile editor
     uri = editor.getURI()
     line = editor.getLastCursor().getBufferRow()
-    word = @getWordUnderCursor target
+    word = @getWordUnderCursor editor

     successHandler = ({ responseType, msg }) ->
       [clause] = msg
@@ -221,11 +223,11 @@
       .subscribe successHandler, @displayErrors

   doMakeWith: ({ target }) =>
-    editor = target.model
+    editor = @getEditor()
     @saveFile editor
     uri = editor.getURI()
     line = editor.getLastCursor().getBufferRow()
-    word = @getWordUnderCursor target
+    word = @getWordUnderCursor editor

     successHandler = ({ responseType, msg }) ->
       [clause] = msg
@@ -246,11 +248,11 @@
       .subscribe successHandler, @displayErrors

   doMakeLemma: ({ target }) =>
-    editor = target.model
+    editor = @getEditor()
     @saveFile editor
     uri = editor.getURI()
     line = editor.getLastCursor().getBufferRow()
-    word = @getWordUnderCursor target
+    word = @getWordUnderCursor editor

     successHandler = ({ responseType, msg }) ->
       [lemty, param1, param2] = msg
@@ -294,11 +296,11 @@
       .subscribe successHandler, @displayErrors

   doMakeCase: ({ target }) =>
-    editor = target.model
+    editor = @getEditor()
     @saveFile editor
     uri = editor.getURI()
     line = editor.getLastCursor().getBufferRow()
-    word = @getWordUnderCursor target
+    word = @getWordUnderCursor editor

     successHandler = ({ responseType, msg }) ->
       [clause] = msg
@@ -318,7 +320,7 @@
       .subscribe successHandler, @displayErrors

   showHoles: ({ target }) =>
-    editor = target.model
+    editor = @getEditor()
     @saveFile editor
     uri = editor.getURI()

@@ -339,11 +341,11 @@
       .subscribe successHandler, @displayErrors

   doProofSearch: ({ target }) =>
-    editor = target.model
+    editor = getEditor()
     @saveFile editor
     uri = editor.getURI()
     line = editor.getLastCursor().getBufferRow()
-    word = @getWordUnderCursor target
+    word = @getWordUnderCursor editor

     successHandler = ({ responseType, msg }) ->
       [res] = msg
@@ -366,8 +368,9 @@
       .subscribe successHandler, @displayErrors

   printDefinition: ({ target }) =>
-    word = Symbol.serializeWord @getWordUnderCursor(target)
-    uri = target.model.getURI()
+    editor = @getEditor()
+    uri = editor.getURI()
+    word = Symbol.serializeWord @getWordUnderCursor(editor)

     successHandler = ({ responseType, msg }) =>
       [type, highlightingInfo] = msg
@@ -389,8 +392,7 @@
       .subscribe successHandler, @displayErrors

   openREPL: ({ target }) =>
-    editor = target.model
-    uri = editor.getURI()
+    uri = @getEditor().getURI()

     successHandler = ({ responseType, msg }) ->
       options =
@@ -405,8 +407,7 @@
       .subscribe successHandler, @displayErrors

   apropos: ({ target }) =>
-    editor = target.model
-    uri = editor.getURI()
+    uri = @getEditor().getURI()

     successHandler = ({ responseType, msg }) ->
       options =


changing layout for markdown

changing layout for markdown

--- core/utils.coffee
+++ core/utils.coffee
@@ -106,7 +106,7 @@

   applyLineBreaks: (text)->
     return null unless text
-    text.replace "\n", "
"
+    text.replace /\n/g, "
"

   applyTextExpansions: (text)->
     return null unless text


actually count properly

actually count properly

--- lib/indent-detective.coffee
+++ lib/indent-detective.coffee
@@ -3,6 +3,8 @@
 selector = require './selector'

 module.exports = GuessIndent =
+
+  possibleIndentations: [2, 3, 4, 6, 8]

   activate: (state) ->
     @manual = new Set()
@@ -64,9 +66,8 @@
       if @isblank l then continue
       if @iscomment [row, 0], ed then continue
       next = @indent l
-      if next == last
-        @count votes, next
-        continue
+      # only count differences in indentation
+      if next == last then continue
       if next.startsWith last
         @count votes, @after next, last
       else if last.startsWith next
@@ -100,8 +101,7 @@

   select: ->
     items = [{text: "Automatic"}]
-    items.push {text: "1 Space", length: 1}
-    items.push(({text: "#{n} Spaces", length: n} for n in [2, 3, 4, 6, 8])...)
+    items.push(({text: "#{n} Spaces", length: n} for n in @possibleIndentations)...)
     items.push {text: "Tabs"}
     s = selector.show items, ({text, length}={}) =>
       ed = atom.workspace.getActiveTextEditor()


Refactor MiniProfileView::fetchProfile()

--- lib/assets/javascripts/views/mini_profile.js.coffee
+++ lib/assets/javascripts/views/mini_profile.js.coffee
@@ -18,18 +18,14 @@
   fetchProfile: (entity) =>
     return unless entity
     return if entity == @profile()?.get('entity')
-    if profile = TentStatus.Models.MetaProfile.find(entity: entity)
-      @current_profile_cid = profile.cid
-      @render(@context(profile))
-    else
-      TentStatus.Models.MetaProfile.fetch({ entity: entity},
-        failure: (res, xhr) =>
-          @render()
+    TentStatus.Models.MetaProfile.find({entity: entity},
+      success: (profile) =>
+        @current_profile_cid = profile.cid
+        @render(@context(profile))

-        success: (profile, xhr) =>
-          @current_profile_cid = profile.cid
-          @render(@context(profile))
-      )
+      failure: =>
+        @render()
+    )

   profile: =>
     TentStatus.Models.MetaProfile.find(cid: @current_profile_cid)


Removed unnecessary div

Removed unnecessary div

--- lib/line-diff-worker.coffee
+++ lib/line-diff-worker.coffee
@@ -139,15 +139,14 @@
     @content: (message) ->
         isRemoval = message.length is 0
         message = "(Remove new lines)" if isRemoval
-        @div style: "opacitiy: 0", =>
-            @div class: "bubble", =>
-                @div class: "action-buttons", =>
-                    @button click: "removeView", class: "btn diff-button", title: "Close", =>
-                        @span class: "text-success icon icon-x"
-                    @button click: "revertAndClose", class: "btn diff-button", title: "Revert", =>
-                        @span class: "text-warning icon icon-history"
-                    unless isRemoval
-                        @button click: "copyToClipboard", class: "btn diff-button", title: "Copy", =>
-                            @span class: "text-primary icon icon-clippy"
-                @div class: "bubble-code", => @span message
+        @div class: "bubble", =>
+            @div class: "action-buttons", =>
+                @button click: "removeView", class: "btn diff-button", title: "Close", =>
+                    @span class: "text-success icon icon-x"
+                @button click: "revertAndClose", class: "btn diff-button", title: "Revert", =>
+                    @span class: "text-warning icon icon-history"
+                unless isRemoval
+                    @button click: "copyToClipboard", class: "btn diff-button", title: "Copy", =>
+                        @span class: "text-primary icon icon-clippy"
+            @div class: "bubble-code", => @span message
 module.exports = LineDiffWorker


Add endpoints for silencing channels.

Add endpoints for silencing channels.

--- js/src/http/UserDirectoryApi.coffee
+++ js/src/http/UserDirectoryApi.coffee
@@ -166,4 +166,33 @@
         })
       ))

+    getMutedChannels: ->
+      Promise.resolve(axios(
+        Requests.wrapCredentials({
+          url: getUserUrl() + '/setting/' + MUTED_CHANNEL
+          headers: DEFAULT_HEADERS
+          method: 'GET'
+        })
+      ))
+
+    addMutedChannel: (channelId) ->
+      Promise.resolve(axios(
+        Requests.wrapCredentials({
+          url: getUserUrl() + '/setting/' + MUTED_CHANNEL
+          headers: DEFAULT_HEADERS
+          method: 'PUT'
+          data: [channelId]
+        })
+      ))
+
+    removeMutedChannel: (channelId) ->
+      Promise.resolve(axios(
+        Requests.wrapCredentials({
+          url: getUserUrl() + '/setting/' + MUTED_CHANNEL
+          headers: DEFAULT_HEADERS
+          method: 'DELETE'
+          data: [channelId]
+        })
+      ))
+
   return UserDirectoryApi


cleanded docpad dev comments

cleanded docpad dev comments

--- lib/docpad.coffee
+++ lib/docpad.coffee
@@ -1,18 +1,6 @@
 ###
 Docpad by Benjamin Lupton
 The easiest way to generate your static website.
-
-Recent things since last release:
-
-	1. Added plugin infrastructure
-	2. Moved clean urls to plugin
-	3. Moved relations to plugin
-	4. Moved jade and markdown parsing to plugin
-
-Things to do before next release:
-
-	1. Add plugin scanning and loading
-	2. Add better commenting structure (like Buildr's)
 ###

 # Requirements


Update format.coffee

Update format.coffee

--- lib/format.coffee
+++ lib/format.coffee
@@ -35,9 +35,61 @@
       return

     grammar = editor.getGrammar()?.scopeName
+    mainCursor = editor.getCursors()[0]
+    textBuffer = editor.getBuffer()
+    nonWhitespaceRegex = /\S/g
+    whitespaceRegex = /\s/g
+    currentCursorPosition = mainCursor.getBufferPosition()
+    mainCursor.setBufferPosition([currentCursorPosition.row, currentCursorPosition.column + 1])
+    isInsideWord = mainCursor.isInsideWord()
+    mainCursor.setBufferPosition(currentCursorPosition)
+
+    if mainCursor.isInsideWord()
+      # The cursor is inside a word, so let's use the beginning as the reference
+      #
+      currentPosition = mainCursor.getBeginningOfCurrentWordBufferPosition()
+
+      # ideally we could do mainCursor.setBufferPosition([currentCursorPosition.row, currentCursorPosition.column + 1]).isInsideWord()
+      # but .setBufferPosition returns undefined :(
+      # So we have to define some stuff above instead...
+
+    else if isInsideWord
+      # The cursor is right before a word in this case, so let's use the current cursor position as a reference
+      #
+      mainCursor.setBufferPosition(currentCursorPosition)
+      currentPosition = currentCursorPosition()
+
+    whitespaceText = textBuffer.getTextInRange([[0, 0], currentPosition])
+
+    nonWhitespaceCharacters = whitespaceText.match(nonWhitespaceRegex)
+    whitespaceCharacterCount = whitespaceText.match(whitespaceRegex)
+
+    if !whitespaceCharacterCount
+      whitespaceCharacterCount = 0
+    else
+      whitespaceCharacterCount = whitespaceCharacterCount.length
+
+    if !nonWhitespaceCharacters
+      nonWhitespaceCharacters = 0
+    else
+      nonWhitespaceCharacters = nonWhitespaceCharacters.length

     if grammar is 'source.json' or grammar is 'source.js'
       @formatJavascript editor
+
+      nonWhitespaceCount = 0
+      text = editor.getText()
+
+      for i in [0...text.length]
+        if /\S/.test(text.charAt(i))
+          nonWhitespaceCount++
+          if nonWhitespaceCount == nonWhitespaceCharacters.length
+            break
+
+      newCursorPosition = textBuffer.positionForCharacterIndex(nonWhitespaceCount + whitespaceCharacterCount);
+
+      mainCursor.setBufferPosition(newCursorPosition)
+
     else
       notification = new FileTypeNotSupportedView(state)
       atom.workspaceView.append(notification)
@@ -58,6 +110,7 @@

     if @selectionsAreEmpty editor
       editor.setText(jsbeautify(editor.getText(), opts))
+
     else
       for selection in editor.getSelections()
         selection.insertText(jsbeautify(selection.getText(), opts), {select:true})
@@ -67,7 +120,7 @@
       return false unless selection.isEmpty()
     true

-  subscribeToEvents: ->
+  subscribeToEvents: (state) ->
     if atom.config.get('jsformat.format_on_save') ? @configDefaults['format_on_save']
       @editorCreationSubscription = atom.workspaceView.eachEditorView (editorView) =>
         editor = editorView.getEditor()
@@ -78,7 +131,7 @@

           @editorSaveSubscriptions[editor.id] = buffer.onWillSave =>
             buffer.transact =>
-              @formatJavascript(editor)
+              @format(state)

           @editorCloseSubscriptions[editor.id] = buffer.onDidDestroy =>
             @editorSaveSubscriptions[editor.id].dispose()


Fix Issue #9 : Strip out tag's namespace prefix of received soap message.

--- lib/services/Service.coffee
+++ lib/services/Service.coffee
@@ -9,7 +9,7 @@
 url = require 'url'
 gen_uuid = require 'node-uuid'
 xml = require 'xml'
-{ Parser: XmlParser } = require 'xml2js'
+{ processors, Parser: XmlParser } = require 'xml2js'

 { HttpError, SoapError } = require '../errors'
 _ = require '../utils'
@@ -35,8 +35,8 @@

   # Control action. Most actions build a SOAP response and calls back.
   action: (action, data, cb) ->
-    (new XmlParser).parseString data, (err, data) =>
-      @actionHandler action, data['s:Envelope']['s:Body'][0]["u:#{action}"][0], cb
+    (new XmlParser {"tagNameProcessors":[processors.stripPrefix]}).parseString data, (err, data) =>
+      @actionHandler action, data['Envelope']['Body'][0]["#{action}"][0], cb

   # Create model attribute getter/setter property.


Update Account E-mail Settings, use VerifyPINModal

--- client/landing/app/Applications/Account.kdapplication/account/accSettingsPersUsernameEmail.coffee
+++ client/landing/app/Applications/Account.kdapplication/account/accSettingsPersUsernameEmail.coffee
@@ -12,19 +12,26 @@
     # #
     @addSubView @emailForm = emailForm = new KDFormView
       callback     : (formData)->
-        new KDNotificationView
-          type  : "mini"
-          title : "Currently disabled!"
+        bongo.api.JUser.changeEmail
+          email : formData.email
+        , (err, result)=>
+          log err
+          if err and err.name isnt 'PINExistsError'
+            new KDNotificationView
+              title    : err.message
+              duration : 2000
+          else
+            new VerifyPINModal 'Update E-Mail', (pin)=>
+              bongo.api.JUser.changeEmail
+                email : formData.email
+                pin   : pin
+              , (err)->
+                new KDNotificationView
+                  title    : if err then err.message else "E-mail changed!"
+                  duration : 2000
+                # FIXME update the view in some way

-        # bongo.api.JUser.changeEmail formData.email, (err,docs)=>
-        #   if err then warn err
-        #   else
-        #     emailSwappable.swapViews()
-
-        #   new KDNotificationView
-        #     type     : "growl"
-        #     title    : if err then err.msg else "Email successfully updated!"
-        #     duration : 1000
+          emailSwappable.swapViews()

     emailForm.addSubView emailLabel = new KDLabelView
       title        : "Your email"


Reference support

Reference support

--- grammars/latex.cson
+++ grammars/latex.cson
@@ -144,7 +144,7 @@
       { include: '#metaFontStyling' } # eg. \emph
       # { include: '#marginpar' }
       { include: '#metaFootnote' }
-      # { include: '#metaReferences' } # maybe include \ref \label as well?
+      { include: '#metaReferences' } # maybe include \ref \label as well?
       # { include: '#verbScantokens' } # not sure what this is for
       # { include: '#constants' } # words that represent constants
     ]
@@ -372,16 +372,128 @@
           2:
             name: 'punctuation.definition.function.latex'
           3:
-            name: 'punctuation.definition.argument.begin.latex'
+            name: 'punctuation.definition.arguments.begin.latex'
         end: '\\}'
         endCaptures:
           0:
-            name: 'punctuation.definition.argument.end.latex'
+            name: 'punctuation.definition.arguments.end.latex'
         contentName: 'meta.footnote.latex'
         patterns: [{ include: '$self' }]
       }
     ]
   }
+  metaReferences: {
+    comment: 'The following have all been taken (mostly) directly from language-latex.'
+    patterns: [
+      {
+        comment: 'Taken from language-latex'
+        begin: '((\\\\)(?:\\w*[rR]ef\\*?))(\\{)'
+        beginCaptures:
+          1:
+            name: 'keyword.control.ref.latex'
+          2:
+            name: 'punctuation.definition.keyword.latex'
+          3:
+            name: 'punctuation.definition.arguments.begin.latex'
+        end: '\\}'
+        endCaptures:
+          0:
+            name: 'punctuation.definition.arguments.begin.latex'
+        contentName: 'meta.reference.latex'
+        patterns: [
+          { include: '#controlWord' }
+          { include: '#controlSymbol' }
+          {
+            match: '[!\u0028-\u007A\u00A1-\u017F\u3001-\u30FF\u0391-\u03CE\u0410-\u044F\u4E00-\u9FFF\uFF0C\uFF0E]'
+            name: 'constant.other.reference.latex'
+          }
+        ]
+      }
+      {
+        comment: 'Taken from language-latex'
+        begin: '((\\\\)label)(\\{)'
+        beginCaptures:
+          1:
+            name: 'keyword.control.label.latex'
+          2:
+            name: 'punctuation.definition.keyword.latex'
+          3:
+            name: 'punctuation.definition.arguments.begin.latex'
+        end: '\\}'
+        endCaptures:
+          0:
+            name: 'punctuation.definition.arguments.end.latex'
+        name: 'meta.definition.latex'
+        patterns: [
+          { include: '#controlWord' }
+          { include: '#controlSymbol' }
+          {
+            match: '[!\u0028-\u007A\u00A1-\u017F\u3001-\u30FF\u0391-\u03CE\u0410-\u044F\u4E00-\u9FFF\uFF0C\uFF0E]'
+            name: 'constant.other.reference.latex'
+          }
+        ]
+      }
+      {
+        comment: 'Taken from language-latex'
+        begin: '''(?x)
+                    ((\\\\)(?:text)?(?:paren)?(?:auto)?(?:foot)?(?:full)?(?:no)?(?:short)?[cC]ites?(?:al)?(?:t|p|author|year(?:par)?|title)?[ANP]*\\*?)
+                    (?:(\\[)[^\\]]*(\\]))?
+                    (?:(\\[)[^\\]]*(\\]))?
+                    (\\{)
+                 '''
+        captures:
+          1:
+            name: 'keyword.control.cite.latex'
+          2:
+            name: 'punctuation.definition.keyword.latex'
+          3:
+            name: 'punctuation.definition.arguments.optional.begin.latex'
+          4:
+            name: 'punctuation.definition.arguments.optional.end.latex'
+          5:
+            name: 'punctuation.definition.arguments.optional.begin.latex'
+          6:
+            name: 'punctuation.definition.arguments.optional.end.latex'
+          7:
+            name: 'punctuation.definition.arguments.latex'
+        end: '\\}'
+        endCaptures:
+          0:
+            name: 'punctuation.definition.arguments.latex'
+        name: 'meta.citation.latex'
+        patterns: [
+          { include: '#controlWord' }
+          { include: '#controlSymbol' }
+          {
+            match: '[!\u0028-\u007A\u00A1-\u017F\u3001-\u30FF\u0391-\u03CE\u0410-\u044F\u4E00-\u9FFF\uFF0C\uFF0E]'
+            name: 'constant.other.reference.citation.latex'
+          }
+        ]
+      }
+      {
+        comment: 'Taken from language-latex'
+        begin: '(\\\\bibitem)(\\{)'
+        beginCaptures:
+          1:
+            name: 'keyword.control.bibitem.latex'
+          2:
+            name: 'punctuation.definition.arguments.begin.latex'
+        end: '\\}'
+        endCaptures:
+          0:
+            name: 'punctuation.definition.arguments.end.latex'
+        patterns: [
+          { include: '#controlWord' }
+          { include: '#controlSymbol' }
+          {
+            match: '[!\u0028-\u007A\u00A1-\u017F\u3001-\u30FF\u0391-\u03CE\u0410-\u044F\u4E00-\u9FFF\uFF0C\uFF0E]'
+            name: 'constant.other.reference.bibitem.latex'
+          }
+        ]
+      }
+    ]
+  }
+
 # Other
   escapedCharacter: {
     comment: 'Finds escaped characters like \$ and \%. Uses this regex so unique capture groups can be used.'


simplify some matches that don't need parentheses


Fire scroll event when animating

Fire scroll event when animating

--- framer/Components/ScrollComponent.coffee
+++ framer/Components/ScrollComponent.coffee
@@ -320,6 +320,8 @@

 	_onAnimationStep: (event) =>
 		@content.emit(Events.Move, @content.point)
+		@emit(Events.Scroll, event)
+
 	_onAnimationStop: =>
 		@content.off("change:frame", @_onAnimationStep)


Add separate _updateKnob() function for width, height, scale, knobSize changes on DragStart

--- framer/Components/SliderComponent.coffee
+++ framer/Components/SliderComponent.coffee
@@ -59,7 +59,7 @@

 		@knob.on("change:x", @_updateFill)
 		@knob.on("change:x", @_updateValue)
-		@knob.on("change:size", @_updateFrame)
+		@knob.on("change:size", @_updateKnob)
 		@knob.on(Events.DragMove, @_updateFrame)

 		# On click/touch of the slider, update the value
@@ -78,6 +78,10 @@
 	_updateFill: =>
 		@fill.width = @knob.midX

+	_updateKnob: =>
+		@knob.midX = @fill.width
+		@knob.centerY()
+
 	_updateFrame: =>
 		@knob.draggable.constraints =
 			x: -@knob.width / 2
@@ -86,7 +90,6 @@
 			height: @height + @knob.height

 		@knob.centerY()
-		# @knob.midX = @fill.width

 	_setRadius: =>
 		radius = @borderRadius


clean up code

clean up code

--- app/lib/canvas-graph.coffee
+++ app/lib/canvas-graph.coffee
@@ -247,22 +247,22 @@
         mark.element.style.left = parseFloat(scaledMin) + "px"
         mark.save(scaledMin, scaledMax)

-        # console.log """
-        #               -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-        #               ---------------- RESCALE MARKS ----------------
-        #                                     val: #{val}  <--- slider value
-        #                       canvasGraph.scale: #{@scale}
-        #                                    xMin: #{xMin}  <------------- lightcurve display limits
-        #                                    xMax: #{xMax}
-        #                               scaledMin: #{scaledMin} <---/------ mark limits
-        #                               scaledMax: #{scaledMax} <--/
-        #                        mark.dataXMinRel: #{mark.dataXMinRel} <-- data limits
-        #                        mark.dataXMaxRel: #{mark.dataXMaxRel}
-        #                       mark width (data): #{(mark.dataXMaxRel-mark.dataXMinRel)}
-        #                     mark width (canvas): #{mark.element.style.width}       <----- CSS style
-        #                 mark.element.style.left: #{mark.element.style.left}
-        #               -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-        #             """
+        console.log """
+                      -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+                      ---------------- RESCALE MARKS ----------------
+                                            val: #{val}  <--- slider value
+                              canvasGraph.scale: #{@scale}
+                                           xMin: #{xMin}  <------------- lightcurve display limits
+                                           xMax: #{xMax}
+                                      scaledMin: #{scaledMin} <---/------ mark limits
+                                      scaledMax: #{scaledMax} <--/
+                               mark.dataXMinRel: #{mark.dataXMinRel} <-- data limits
+                               mark.dataXMaxRel: #{mark.dataXMaxRel}
+                              mark width (data): #{(mark.dataXMaxRel-mark.dataXMinRel)}
+                            mark width (canvas): #{mark.element.style.width}       <----- CSS style
+                        mark.element.style.left: #{mark.element.style.left}
+                      -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+                    """

   drawXTickMarks: (xMin, xMax) ->
@@ -432,12 +432,13 @@
     step = 1.5
     zoom = setInterval (=>

+      # gradually expand zooming bounds
       cMin -= step
       if cMin < wMin then cMin = wMin
       cMax += step
       if cMax > wMax then cMax = wMax

-      console.log "[cMin,cMax] = [#{cMin},#{cMax}]"
+      # console.log "[cMin,cMax] = [#{cMin},#{cMax}]"
       @plotPoints(cMin,cMax)

       if cMin <= wMin and cMax >= wMax  # finished zooming
@@ -472,50 +473,6 @@
         @plotPoints(wMin,wMax)
         @rescaleMarks(wMin,wMax)
     ), 30
-
-  # zoomOut: (callback) ->
-  #   classifier.el.find('#graph').addClass('is-zooming')
-  #   classifier.el.find('#ui-slider').val(0) # reset slider
-  #   classifier.zoomLevel = 0 # reset zoom level index
-
-  #   [cMin, cMax] = [@xMin, @xMax]
-  #   [wMin, wMax] = [@smallestX, @largestX]
-
-  #   zoom = setInterval (=>
-
-  #       @plotPoints(cMin,cMax) # this line is problematic. why?
-  #       console.log '*****************************'
-  #       console.log '**** plotPoints(',cMin,',',cMax,') ****'
-  #       console.log '*****************************'
-
-  #       if (cMin-1.0) > wMin
-  #         cMin -= 1.0
-  #       else
-  #         console.log 'LEFT DONE!'
-
-  #       if (cMax+1.0) < wMax
-  #         cMax += 1.0
-  #       else
-  #         console.log 'RIGHT DONE!'
-
-  #     if cMin <= wMin and cMax >= wMax  # finished zooming
-  #       console.log 'CONSDOSNDKLSJDFHSLKJDHSKLDJHSLKJDHSKJDFHLKJSHFGLEUIRBLCIUW:DN:X WJKB:FHLKJSHD'
-  #       clearInterval zoom
-  #       classifier.el.find('#graph').removeClass('is-zooming')
-  #       @plotPoints(wMin, wMax)
-  #       unless callback is undefined
-  #         callback.apply()
-  #         classifier.el.find("#zoom-button").removeClass("zoomed")
-  #         classifier.el.find("#zoom-button").removeClass("allowZoomOut") # for last zoom level
-  #         classifier.el.find('#ui-slider').attr('disabled',true)
-  #         classifier.el.find('.noUi-handle').fadeOut(150)
-
-  #       # cMin -= 1.5 unless cMin <= wMin
-  #       # cMax += 1.5 unless cMax >= wMax
-
-  #   ), 30
-
-  #   return

   clearCanvas: -> @ctx.clearRect(0,0,@canvas.width, @canvas.height)


Redid my bobbing fix b286b24 in a way that doesn't break the LankBoss position test.

--- app/lib/surface/Lank.coffee
+++ app/lib/surface/Lank.coffee
@@ -171,9 +171,10 @@
   update: (frameChanged) ->
     # Gets the sprite to reflect what the current state of the thangs and surface are
     return false if @stillLoading
-    if (frameChanged and @thang and @thang.stateChanged) or (@thang and @thang.bobHeight) or @notOfThisWorld
+    thangUnchanged = @thang and @thang.stateChanged is false
+    if (frameChanged and not thangUnchanged) or (@thang and @thang.bobHeight) or @notOfThisWorld
       @updatePosition()
-    return false if @thang and @thang.stateChanged is false
+    return false if thangUnchanged
     frameChanged = frameChanged or @targetScaleFactorX isnt @scaleFactorX or @targetScaleFactorY isnt @scaleFactorY
     if frameChanged
       @handledDisplayEvents = {}


Add another comment to clarify what we're doing with the allroute and wrapper function

--- guts/routing.coffee
+++ guts/routing.coffee
@@ -124,5 +124,7 @@
                                                 # log that error.
                                                 console.log "There has been an error: #{e}"
                                                 res.send 500, message: 'There has been an error'
-
+
+                        # As stated above, wrapper will return a new function based on what
+                        # we send in for "allRoutes"
                         app[method](endpoint, wrapper(allRoutes))


fix(app generator/router): make a locale switch do a proper `@refresh()`

Accordingly:
  * Adapt the $appRoot's `lang` attribute;
  * Adapt the environment setting;

--- generators/app/templates/src/router.coffee
+++ generators/app/templates/src/router.coffee
@@ -458,14 +458,11 @@
             localeManager.setLocale( locale ).then(

                 () =>
-                    ##  Unload the current view.
-                    ##
-                    @pageView.remove()
-                    @pageView = undefined
-
-                    ##  And then reload it with the new locale active.
-                    ##
-                    window.history.back()
+
+                    settings.get( '$appRoot' ).attr( 'lang', locale )
+                    settings.set( 'locale', locale )
+
+                    @refresh()

                     return


:bug: Fix an ES6 Usage

:bug: Fix an ES6 Usage

--- lib/linter.coffee
+++ lib/linter.coffee
@@ -15,7 +15,7 @@
       @Emitter.emit 'linters-observe', CurrentEditorLinter
       Editor.onDidDestroy =>
         CurrentEditorLinter.destroy()
-        @EditorLinters.delete CurrentEditorLinter
+        delete @EditorLinters[ CurrentEditorLinter ]

   getActiveEditorLinter:->
     ActiveEditor = atom.workspace.getActiveEditor()


Extract helper function in spec

Extract helper function in spec

--- spec/command-palette-spec.coffee
+++ spec/command-palette-spec.coffee
@@ -25,18 +25,21 @@
     runs ->
       palette = $(workspaceElement.querySelector('.command-palette')).view()

+  expectCommandsForElement = (element) ->
+    keyBindings = atom.keymap.findKeyBindings(target: element)
+    for {name, displayName} in atom.commands.findCommands(target: element)
+      eventLi = palette.list.children("[data-event-name='#{name}']")
+      expect(eventLi).toExist()
+      expect(eventLi.find('span')).toHaveText(displayName)
+      expect(eventLi.find('span').attr('title')).toBe(name)
+      for binding in keyBindings when binding.command is name
+        expect(eventLi.text()).toContain(_.humanizeKeystroke(binding.keystrokes))
+
   describe "when command-palette:toggle is triggered on the root view", ->
     it "shows a list of all valid command descriptions, names, and keybindings for the previously focused element", ->
       keyBindings = atom.keymap.findKeyBindings(target: editorElement)
       commands = atom.commands.findCommands(target: editorElement)
-
-      for {name, displayName} in commands
-        eventLi = palette.find("[data-event-name='#{name}']")
-        expect(eventLi).toExist()
-        expect(eventLi.find('span')).toHaveText(displayName)
-        expect(eventLi.find('span').attr('title')).toBe(name)
-        for binding in keyBindings when binding.command is name
-          expect(eventLi.find(".key-binding:contains(#{_.humanizeKeystroke(binding.keystrokes)})")).toExist()
+      expectCommandsForElement(editorElement)

     it "focuses the mini-editor and selects the first command", ->
       expect(palette.filterEditorView.hasFocus()).toBeTruthy()
@@ -79,26 +82,11 @@
       atom.commands.dispatch(workspaceElement, 'command-palette:toggle')
       document.activeElement.blur()
       atom.commands.dispatch(workspaceElement, 'command-palette:toggle')
-
-      keyBindings = atom.keymap.findKeyBindings(target: workspaceElement)
-      for {name, displayName} in atom.commands.findCommands(target: workspaceElement)
-        eventLi = palette.list.children("[data-event-name='#{name}']")
-        expect(eventLi).toExist()
-        expect(eventLi.find('span')).toHaveText(displayName)
-        expect(eventLi.find('span').attr('title')).toBe(name)
-        for binding in keyBindings when binding.command is name
-          expect(eventLi.text()).toContain(_.humanizeKeystroke(binding.keystrokes))
+      expectCommandsForElement(workspaceElement)

   describe "when the body has focus", ->
     it "uses the root view as the element to display and trigger events for", ->
       atom.commands.dispatch(workspaceElement, 'command-palette:toggle')
       document.body.focus()
       atom.commands.dispatch(workspaceElement, 'command-palette:toggle')
-      keyBindings = atom.keymap.findKeyBindings(target: workspaceElement)
-      for {name, displayName} in atom.commands.findCommands(target: workspaceElement)
-        eventLi = palette.list.children("[data-event-name='#{name}']")
-        expect(eventLi).toExist()
-        expect(eventLi.find('span')).toHaveText(displayName)
-        expect(eventLi.find('span').attr('title')).toBe(name)
-        for binding in keyBindings when binding.command is name
-          expect(eventLi.find(".key-binding:contains(#{_.humanizeKeystroke(binding.keystrokes)})")).toExist()
+      expectCommandsForElement(workspaceElement)


Fix failing test in git-pull-spec

Fix failing test in git-pull-spec

--- spec/models/git-pull-spec.coffee
+++ spec/models/git-pull-spec.coffee
@@ -10,6 +10,8 @@
   beforeEach -> spyOn(git, 'cmd').andReturn Promise.resolve true

   it "calls git.cmd with ['remote'] to get remote repositories", ->
+    atom.config.set('git-plus.experimental', false)
+    atom.config.set('git-plus.alwaysPullFromCurrentBranch', false)
     GitPull(repo)
     expect(git.cmd).toHaveBeenCalledWith ['remote'], options


:white_check_mark: Add failing spec for disabling an already disabled package

--- spec/package-manager-spec.coffee
+++ spec/package-manager-spec.coffee
@@ -1026,6 +1026,16 @@
         expect(atom.packages.enablePackage("this-doesnt-exist")).toBeNull()
         expect(console.warn.callCount).toBe 1

+      fit "does not disable an already disabled package", ->
+        packageName = 'package-with-main'
+        atom.config.pushAtKeyPath('core.disabledPackages', packageName)
+        atom.packages.observeDisabledPackages()
+        expect(atom.config.get('core.disabledPackages')).toContain packageName
+
+        atom.packages.disablePackage(packageName)
+        packagesDisabled = atom.config.get('core.disabledPackages').filter((pack) -> pack is packageName)
+        expect(packagesDisabled.length).toEqual 1
+
     describe "with themes", ->
       didChangeActiveThemesHandler = null


re-tweak scroll for move-to-occurrence

re-tweak scroll for move-to-occurrence

--- lib/motion.coffee
+++ lib/motion.coffee
@@ -30,6 +30,7 @@
   setBufferColumn
   limitNumber
   getIndex
+  smartScrollToBufferPosition
 } = require './utils'

 swrap = require './selection-wrapper'
@@ -1069,11 +1070,14 @@
         when 'next' then @getCount(-1)
         when 'previous' then -@getCount(-1)
       range = @ranges[getIndex(index + offset, @ranges)]
-
-      cursor.setBufferPosition(range.start, autoscroll: false)
+      point = range.start
+
+      cursor.setBufferPosition(point, autoscroll: false)
+
       if cursor.isLastCursor()
-        @editor.unfoldBufferRow(range.start.row)
-        cursor.autoscroll(center: true)
+        @editor.unfoldBufferRow(point.row)
+        smartScrollToBufferPosition(@editor, point)
+
       if settings.get('flashOnMoveToOccurrence')
         @vimState.flash(range, type: 'search')


:bug: Fix missing minimap version check in plugin activation

--- lib/minimap-find-and-replace.coffee
+++ lib/minimap-find-and-replace.coffee
@@ -8,6 +8,9 @@

     return @deactivate() unless findPackage? and minimapPackage?

+    minimap = require(minimapPackage.path)
+    return @deactivate() unless minimap.versionMatch('2.x')
+
     @binding = new MinimapFindAndReplaceBinding findPackage, minimapPackage

   deactivate: ->


JSession::createSession: check for errors first then do the rest, code tidy up

--- workers/social/lib/social/models/session.coffee
+++ workers/social/lib/social/models/session.coffee
@@ -68,22 +68,19 @@

     JUser.fetchGuestUser (err, resp) =>

-      if not resp
+      return @emit 'error', err  if err
+
+      unless resp
         console.error message = "Failed to create guest user :/ ~ This is critical!"
         return @emit 'error', {message}

       {account} = resp
+      username  = safeGuestSessionName account.profile.nickname
+      session   = new JSession { clientId, username }

-      if err then @emit 'error', err
-      else
-        {nickname: username} = account.profile
-        username = safeGuestSessionName username
-        session  = new JSession { clientId, username }
-        session.save (err)->
-          if err
-            callback err
-          else
-            callback null, { session, account }
+      session.save (err)->
+        if err then callback err
+        else callback null, { session, account }

   @fetchSession = (clientId, callback)->


Handle pasting of just-<pre> HTML, cleanup regex

--- client/message.coffee
+++ client/message.coffee
@@ -602,21 +602,24 @@
               paste = e.clipboardData.getData 'text/html'
               .replace //g, ''
               .replace /<\/?(html|head|body|meta)\b[^<>]*>/ig, ''
-              .replace /<b\s+style="font-weight:\s*normal[^<>]*>(.*?)<\/b>/ig, '$1'
-              .replace /<span\s+style="([^"]*)"[^<>]*>(.*?)<\/span>/ig, (match, style, body) ->
+              .replace /<b\s+style="font-weight:\s*normal[^<>]*>([^]*?)<\/b>/ig, '$1'
+              .replace /<span\s+style="([^"]*)"[^<>]*>([^]*?)<\/span>/ig, (match, style, body) ->
                 body = "#{body}" if style.match /font-style:\s*italic/
                 body = "#{body}" if style.match /font-weight:\s*[6789]00/
                 body
               .replace /(\s+)(<\/i>(<\/b>)?|<\/b>)/, '$2$1'
               .replace /<(p|li) dir="ltr"/ig, '<$1'
-              .replace /<(p|li|ul) style="[^"]*"/ig, '<$1'
-              .replace /<(br) class="[^"]*"/ig, '<$1'
+              .replace /<(\w+[^<>]*) class=("[^"]*"|'[^']*')/ig, '<$1'
+              .replace /<(p|li|ul|pre) style=("[^"]*"|'[^']*')/ig, '<$1'
               .replace /<\/(p|li)>/ig, ''
               .replace /(<li[^<>]*>)
/ig, '$1'
               .replace /<(li|ul|\/ul|br|p)\b/ig, '\n$&'
-              .split /\r\n?|\n/
-              ## Remove blank lines
-              paste = (line for line in paste when line.length)
+              if match = /^\s*<pre[^<>]*>([^]*)<\/pre>\s*$/.exec paste
+                paste = match[1].split /\r\n?|\n/
+              else
+                paste = paste.split /\r\n?|\n/
+                ## Remove blank lines
+                paste = (line for line in paste when line.length)
             else if 'text/plain' in e.clipboardData.types
               text = e.clipboardData.getData 'text/plain'
               if match = parseCoauthorMessageUrl text


Copy over tutorial to edit

Copy over tutorial to edit

--- games/edit.coffee
+++ games/edit.coffee
@@ -0,0 +1,80 @@
+#
+# edit.coffee
+#
+# The followup Hour of Node Tutorial
+#
+# Role: explain how to create and share your own levels
+#
+# Key Interface Elements:
+# * edit / save
+# * action bricks (forward, right, left)
+# * run program (run loop)
+# * bump program (interrupt handler)
+
+# TODO:
+# Gate by default should send _victory action when interrupted
+# Turtle defaults to reverse on interrupt, to avoid invisible loop
+# Implicitly add: assume, per-level turtle and gate (if absent)
+# Check and send 'done -1' if infinite loop (e.g., no interrupt)
+
+# COMMENT
+# Scores for each level are based on analogs of real-world metrics
+# - Clicks (programmer hours)
+# - Bricks (lines of code)
+# - Ticks (execution time)
+# [with apologies to Dr. Seuss and "Fox in Socks"]
+#
+# Advanced players seeking to optimize their score will need to make
+# similar tradeoffs to what we faced in writing this app!
+#
+
+exports.game = {
+  name: 'The Hour of NODE'
+  assume: 'baseline'
+  comment: "The original Hour of NODE tutorial"
+  author: {name: 'David Huffman', url: 'mailto:david%40theswanfactory.com'}
+  license: {
+    name: 'Creative Commons Attribution 4.0 International'
+    url: 'http://creativecommons.org/licenses/by/4.0/'
+  }
+
+  levels: [
+    {
+      name: 'Click "Play" to Move Turtle to Exit Pad'
+      comment: '
+      Teach kids to use a run loop rather than direct manipulation.
+      They can also experiment with the other control buttons.
+      Everything else is disabled to avoid confusion.
+      '
+      message: 'You did it!'
+      bricks: 1
+      action_limit: 1
+      goal: { clicks: 0, bricks: 1, ticks: 4 }
+      sprites: [
+        { kind: 'gate', actions: {interrupt: ['_victory']}, position: [1,1] }
+        { kind: 'turtle', actions: {run: ['forward', 'right']}, editable: false }
+      ]
+    }
+    {
+      name: 'Click "Edit" to Modify. Click Sprite to Modify.'
+      comment: '
+      Now students know enough to start designing their own levels.
+      - Click "Edit" to enable design mode.
+      - Click on the Blue Grid to create more sprites.
+      NOTE: edit mode is usually disabled the first time through a level
+      '
+      edit_mode: true
+      bricks: 2
+      goal: { clicks: 1, bricks: 2, ticks: 11 }
+      sprites: [
+        { kind: 'gate', actions: {interrupt: ['_victory']}, position: [4,4] }
+        {
+          kind: 'turtle'
+          actions: { run: ['forward'], interrupt: ['right'] }
+        }
+      ]
+    }
+    # TODO: change the kind of sprite
+    # TODO: replace level and game description
+  ]
+}


runner: go Finished log

runner: go Finished log

--- lib/runner.coffee
+++ lib/runner.coffee
@@ -42,7 +42,7 @@
     do @_createNewContext if @_config.runner.startTestsWithNewBrowser

     testFile = @_files[@_fileIndex]
-    console.log 'Started: ' + testFile.replace @_config.root, ''
+    console.log '\nStarted: ' + testFile.replace @_config.root, ''

     @testCase = new (require testFile) @_wd, @_browser, @_config, @errorHandler
     @_context = @testCase
@@ -58,7 +58,9 @@
   finish: ->
     @_context
       .then => do @_browser.quit
-      .done => process.exit @_errorCount
+      .done =>
+        console.log '\nFinished' + if @_errorCount then " with errors count: #{@_errorCount}" else ''
+        process.exit @_errorCount

   errorHandler: (error) =>
     @_errorCount++


Create a stack trace only if Error.captureStackTrace is available

--- drivers/javascript/errors.coffee
+++ drivers/javascript/errors.coffee
@@ -3,7 +3,8 @@
         @name = @constructor.name
         @msg = msg
         @message = msg
-        Error.captureStackTrace @, @
+        if Error.captureStackTrace?
+            Error.captureStackTrace @, @

 class RqlServerError extends Error
     constructor: (msg, term, frames) ->
@@ -17,7 +18,8 @@
                 @message = "#{msg} in:\n#{RqlQueryPrinter::printQuery(term)}\n#{RqlQueryPrinter::printCarrots(term, frames)}"
         else
             @message = "#{msg}"
-        Error.captureStackTrace @, @
+        if Error.captureStackTrace?
+            Error.captureStackTrace @, @

 class RqlRuntimeError extends RqlServerError


Removed process.on"uncaughtException"

Removed process.on"uncaughtException"

--- lib/command.coffee
+++ lib/command.coffee
@@ -18,6 +18,8 @@
   --help                   Show this message.
 """

+_error = if argv.color then clc.red.bold else (x)->x
+
 run = ->
     if argv.help
         console.log usage
@@ -31,14 +33,10 @@
     mozrepl = new Mozrepl argv.host, argv.port
     mozrepl.connect (err)->
         if err
-            console.error clc.red.bold("Error occured while connecting Mozrepl")
-            console.error(err.stack || err.toString())
-            return
+            console.error _error("An error occured while connecting Mozrepl")
+            console.error (err.stack || err.toString())
+            process.exit 1
         mozfee = new Mozfee mozrepl, stdin, stdout, options
         mozfee.run()

-# Log an error.
-process.on 'uncaughtException', (err)->
-    console.error (err.stack or err.toString())
-
 exports.run = run


Better name for escapeCurlyBraces

Better name for escapeCurlyBraces

--- lib/compile.coffee
+++ lib/compile.coffee
@@ -41,7 +41,7 @@
 selfClosingTags = 'area, base, br, col, command, embed, hr, img, input,
   keygen, link, meta, param, source, track, wbr'.split /,\s*/

-escapeCurlyBraces = (str) ->
+htmlEscapeCurlyBraces = (str) ->
   str
     .replace(/\{/g, '{')
     .replace(/\}/g, '}')
@@ -293,7 +293,7 @@
       #   helpers.logVerbose 'match 4'
       #   updated = true

-      #   escapedMatch = escapeCurlyBraces( match
+      #   escapedMatch = htmlEscapeCurlyBraces( match
       #     .replace(/\{\{/g, "{{expression '")
       #     .replace(/\}\}/g, "'}}")
       #   )
@@ -330,7 +330,7 @@
         helpers.logVerbose 'match 7', attrName: attrName, attrVal: attrVal
         updated = true
         hrefStr = """href="{{urlPath}}?action=#{encodeURIComponent attrVal}" """
-        anchorStr = escapeBraces """<a #{hrefStr} data-ng-#{escapeCurlyBraces hrefStr}"""
+        anchorStr = escapeBraces """<a #{hrefStr} data-ng-#{htmlEscapeCurlyBraces hrefStr}"""

         index = interpolated.indexOf match
         beforeStr = interpolated.substr 0, index
@@ -373,7 +373,7 @@
               match.replace /\[|\]/g, '.'

           trimmedMatch = trimmedMatch.replace attrVal, escapeBraces newAttrVal
-          """#{trimmedMatch} data-ng-attr-#{attrName}="#{escapeCurlyBraces attrVal}">"""
+          """#{trimmedMatch} data-ng-attr-#{attrName}="#{htmlEscapeCurlyBraces attrVal}">"""
       )


Show task keys (#4594)

Show task keys (#4594)

--- app/pages/lab/workflow.cjsx
+++ app/pages/lab/workflow.cjsx
@@ -140,6 +140,7 @@
                           {tasks[definition.type].getTaskText definition}
                           {if key is @props.workflow.first_task
                              (first)}
+                          {key}
                         </button>

}


resolve workflow conflict

resolve workflow conflict

--- app/pages/lab/workflow.cjsx
+++ app/pages/lab/workflow.cjsx
@@ -8,6 +8,11 @@
 RetirementRulesEditor = require '../../components/retirement-rules-editor'
 {Navigation} = require 'react-router'
 tasks = require '../../classifier/tasks'
+
+DEMO_SUBJECT_SET_ID = if process.env.NODE_ENV is 'production'
+  '6' # Cats
+else
+  '1166' # Ghosts

 EditWorkflowPage = React.createClass
   displayName: 'EditWorkflowPage'
@@ -120,7 +125,6 @@

-

           {if @state.selectedTaskKey? and @props.workflow.tasks[@state.selectedTaskKey]?
             TaskEditorComponent = tasks[@props.workflow.tasks[@state.selectedTaskKey].type].Editor
@@ -135,20 +139,27 @@
     projectAndWorkflowSubjectSets = Promise.all [
       @props.project.get 'subject_sets'
       @props.workflow.get 'subject_sets'
-      # TODO: @props.workflow.get 'expert_subject_set'
     ]

-    <PromiseRenderer promise={projectAndWorkflowSubjectSets}>{([projectSubjectSets, workflowSubjectSets, expertSubjectSet]) =>
-

-        {for subjectSet in projectSubjectSets
-          assigned = subjectSet in workflowSubjectSets
-          cantChange = subjectSet is expertSubjectSet or subjectSet.id is @props.workflow.links.expert_subject_set
-          toggle = @handleSubjectSetToggle.bind this, subjectSet
-

-            <input type="checkbox" checked={assigned} disabled={cantChange} onChange={toggle} />
-            {subjectSet.display_name}
-
}
-

+    <PromiseRenderer promise={projectAndWorkflowSubjectSets}>{([projectSubjectSets, workflowSubjectSets]) =>
+

+

+

+            {for subjectSet in projectSubjectSets
+              assigned = subjectSet in workflowSubjectSets
+              toggle = @handleSubjectSetToggle.bind this, subjectSet
+

+                <input type="checkbox" checked={assigned} onChange={toggle} />
+                {subjectSet.display_name}
+
}
+

+

+        {if projectSubjectSets.length is 0
+

+            This project has no subject sets.{' '}
+            <button type="button" onClick={@addDemoSubjectSet}>Add an example subject set</button>
+
}
+

     }</PromiseRenderer>

   addNewTask: (type) ->
@@ -182,6 +193,13 @@
         @props.workflow.addLink 'subject_sets', [subjectSet.id]
       else
         @props.workflow.removeLink 'subject_sets', subjectSet.id
+
+  addDemoSubjectSet: ->
+    @props.project.addLink 'subject_sets', [DEMO_SUBJECT_SET_ID]
+      .then =>
+        @props.project.get 'subject_sets'
+      .then ([subjectSet]) =>
+        @props.workflow.addLink 'subject_sets', [subjectSet.id]

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


Fix classify links

Fix classify links

--- app/pages/project/home.cjsx
+++ app/pages/project/home.cjsx
@@ -27,9 +27,8 @@
     workflows: []

   render: ->
-    linkParams =
-      owner: @props.owner.login
-      name: @props.project.slug
+    [owner, name] = @props.project.slug.split('/')
+    linkParams = {owner, name}


Sort board preview request by updated_at

- Closes #1223

--- app/talk/board-preview.cjsx
+++ app/talk/board-preview.cjsx
@@ -25,7 +25,7 @@

         <p>{@props.data.description}</p>

-        <PromiseRenderer promise={talkClient.type('discussions').get({board_id: @props.data.id, sort_linked_comments: 'created_at'}).index(0)}>{(discussion) =>
+        <PromiseRenderer promise={talkClient.type('discussions').get({board_id: @props.data.id, sort: '-updated_at', sort_linked_comments: 'created_at'}).index(0)}>{(discussion) =>
           if discussion?
             <LatestCommentLink {...@props} title={true} project={@props.project} discussion={discussion} />
         }</PromiseRenderer>


Refactor alerts

Refactor alerts

--- coffee/rungame.coffee
+++ coffee/rungame.coffee
@@ -240,11 +240,7 @@
 triggerUIEndGame = () ->
 	$("#answers_heading").css("display", "block")
 	if !game.allDone() # user ran out of time
-		slowWarningAlert("Game Over!",
-			"Your game has ended.
" +
-			"Your score was " + game.getScore() +
-			" points." +
-			"

Thanks for playing! Answers will now be displayed.")
+		alertGameLost()
 	updateSidebarHard()
 	loadDiagramIntoUI(game.currDiagram())

@@ -373,12 +369,19 @@

 # }}}
 # Alerts {{{
-fastSuccessAlert = (title, text, time=3000) ->
+
+
+alertDiagramDone = () ->
+	title = "Diagram complete!"
+	text = "You earned " +
+		game.currDiagram().getScore() +
+		" points for this diagram."
+	time = 3000
 	if time < game.getTimeLeft()
 		swal({
 			title: title,
 			text: text,
-			type: "success",
+			type: "info",
 			html: true,
 			timer: time,
 			showConfirmButton: false,
@@ -388,13 +391,18 @@
 		swal({
 			title: title,
 			text: text,
-			type: "success",
+			type: "info",
 			html: true,
 			showConfirmButton: false,
 			allowOutsideClick: true,
 		})

-slowSuccessAlert = (title, text) ->
+alertGameWon = () ->
+	title = "You won! Congratulations!"
+	text = "You earned " +
+			game.currDiagram().getScore() + " points " +
+			"for this last diagram.
Your total score was " +
+			game.getScore() + " points. Thanks for playing!"
 	swal({
 		title: title,
 		text: text,
@@ -403,7 +411,13 @@
 		allowOutsideClick: false,
 	})

-slowWarningAlert = (title, text) ->
+
+alertGameLost = () ->
+	title = "Game Over!"
+	text = "Your game has ended.
" +
+			"Your score was " + game.getScore() +
+			" points." +
+			"

Thanks for playing! Answers will now be displayed."
 	swal({
 		title: title,
 		text: text,
@@ -458,15 +472,9 @@
 	if diagram.complete
 		tempAddClass "#done_button", "button_green"
 		if game.allDone()
-			slowSuccessAlert("You win! Congratulations!", "You earned " +
-				game.currDiagram().getScore() + " points "+
-				"for this last diagram.
Your total score was " +
-				game.getScore() + " points. Thanks for playing!")
+			alertGameWon()
 		else
-			fastSuccessAlert("Diagram complete!",
-				"You earned " +
-				game.currDiagram().getScore() +
-				" points for this diagram.")
+			alertDiagramDone()
 		updateSidebarHard()
 	else
 		tempAddClass "#done_button", "button_red"


descriptive header comment

descriptive header comment

--- imports/redux/middleware/navigation.coffee
+++ imports/redux/middleware/navigation.coffee
@@ -1,6 +1,9 @@
+#
+# Redux middleware that implements navigation to urls upon certain actions
+#

 module.exports = (browserHistory) -> ({ getState, dispatch }) -> (next) -> (action) ->
   switch action.type
     when 'APP_SELECTED' then browserHistory.push "/apps/#{action.value.name}/#{action.value.version}"
-    when 'START_APP_REQUEST' then browserHistory.push "/instance/new/#{action.app.name}/#{action.app.version}"
+    when 'START_APP_REQUEST' then browserHistory.push "/instance/new/#{action.app.name}/#{action.app.version}"
     else next action


:bug: Reject promise with error object instead of string

--- lib/helpers.coffee
+++ lib/helpers.coffee
@@ -26,7 +26,7 @@
       exit = ->
         if options.stream is 'stdout'
           if data.stderr.length and options.throwOnStdErr
-            reject(data.stderr.join(''))
+            reject(new Error(data.stderr.join('')))
           else
             resolve(data.stdout.join(''))
         else


:art: Simplify execNode a bit

:art: Simplify execNode a bit

--- lib/helpers.coffee
+++ lib/helpers.coffee
@@ -23,9 +23,7 @@
       if isNodeExecutable
         options.env ?= {}
         options.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE = '1' # Needed for electron
-        spawnedProcess = child_process.spawn(command, args, options)
-      else
-        spawnedProcess = child_process.spawn(command, args, options)
+      spawnedProcess = child_process.spawn(command, args, options)
       data = []
       if options.stream is 'stdout'
         spawnedProcess.stdout.on 'data', (d) -> data.push(d.toString())


add regression test

add regression test

--- modules/data-table/test/spec.coffee
+++ modules/data-table/test/spec.coffee
@@ -1227,6 +1227,16 @@
           clock.restore()
           done()

+      it 'should update the filter input when changing the filter with the api', (done) ->
+        container = hx.detached('div')
+        dt = new hx.DataTable(container.node())
+        feed = hx.dataTable.objectFeed(threeRowsData)
+        dt.feed(feed)
+        input = container.select('.hx-data-table-filter')
+        input.value().should.equal('')
+        dt.filter 'filter-term', ->
+          input.value().should.equal('filter-term')
+          done()

     describe 'showSearchAboveTable', ->


Time Shim

Time Shim

--- atom/common/lib/asar.coffee
+++ atom/common/lib/asar.coffee
@@ -38,11 +38,11 @@
     uid: uid,
     gid: gid,
     rdev: 0,
-    atime: stats.atime,
-    birthtime: stats.birthtime,
-    mtime: stats.mtime,
-    ctime: stats.ctime,
-    size: stats.size
+    atime: stats.atime || new Date(),
+    birthtime: stats.birthtime || new Date(),
+    mtime: stats.mtime || new Date(),
+    ctime: stats.ctime || new Date(),
+    size: stats.size,
     isFile: -> stats.isFile
     isDirectory: -> stats.isDirectory
     isSymbolicLink: -> stats.isLink


Refactor

Refactor

--- app/assets/javascripts/rglossa/react/components/centre/search_inputs/cwb_multiword_input.jsx.coffee
+++ app/assets/javascripts/rglossa/react/components/centre/search_inputs/cwb_multiword_input.jsx.coffee
@@ -2,16 +2,22 @@

 ###* @jsx React.DOM ###

-createTerm = ->
-  word:     ''
-  pos:      null
-  features: []
-  min:      null
-  max:      null
+createTerm = (overrides = {}) ->
+  term =
+    word:     ''
+    pos:      null
+    features: []
+    min:      null
+    max:      null

-  isLemma: false
-  isStart: false
-  isEnd:   false
+    isLemma: false
+    isStart: false
+    isEnd:   false
+
+  for k, v of overrides
+    term[k] = v
+
+  term

 window.CwbMultiwordInput = React.createClass
@@ -46,13 +52,8 @@
         isEnd   = /^\.\+/.test(word)
         word = word.replace(/^(?:\.\+)?(.+?)/, "$1").replace(/(.+?)(?:\.\+)?$/, "$1")

-        dq.push
-          word:     word
-          features: []
-          min:      min
-          max:      max
-          isStart:  isStart
-          isEnd:    isEnd
+        term = createTerm(word: word, min: min, max: max, isStart: isStart, isEnd: isEnd)
+        dq.push(term)

         min = null
         max = null
@@ -79,10 +80,7 @@

   handleAttributes: (m, min, max) ->
     attributes = m[1].split(/\s*&\s*/)
-    term =
-      min: min
-      max: max
-      features: []
+    term = createTerm(min: min, max: max)

     for attr in attributes
       m2 = attr.match(/\(?(\S+)\s*=\s*"(\S+)"/)


members/activity: change the way content is showed up

--- client/app/Applications/Members.kdapplication/ContentDisplays/ContentDisplayControllerMember.coffee
+++ client/app/Applications/Members.kdapplication/ContentDisplays/ContentDisplayControllerMember.coffee
@@ -135,11 +135,11 @@
         discussions         : @createFilter("Discussions", account, ['CDiscussionActivity'])
         tutorials           : @createFilter("Tutorials", account, ['CTutorialActivity'])
       sort                  :
+        'modifiedAt'        :
+          title             : "Latest activity"
+          direction         : -1
         'sorts.likesCount'  :
           title             : "Most popular"
-          direction         : -1
-        'modifiedAt'        :
-          title             : "Latest activity"
           direction         : -1
         'sorts.repliesCount':
           title             : "Most activity"


Disable some code for now

Disable some code for now

--- src/components/ScrollWall.coffee
+++ src/components/ScrollWall.coffee
@@ -154,8 +154,8 @@
     @targetSpeed(speed, options)

   setHeight: (deltaY) ->
-    @y += deltaY
-    Crafty.viewport.y = -@y
+    #@y += deltaY
+    #Crafty.viewport.y = -@y

   setAllowPushing: (@allowPushing) ->


fix menu for mobile

fix menu for mobile

--- src/components/menu/index.coffee
+++ src/components/menu/index.coffee
@@ -139,7 +139,6 @@
               z.router.link \
                 z "a.section[href=/#{link.key}]",
                   link.text
-              if page is link.key or link.key is 'api'
-                _.map link.children, (child) ->
-                  z.router.link \
-                    z "a.link[href=/#{link.key}##{child.key}]", child.text
+              _.map link.children, (child) ->
+                z.router.link \
+                  z "a.link[href=/#{link.key}##{child.key}]", child.text


Fix Title propTypes to allow arrays.

Fix Title propTypes to allow arrays.

They are supported, so it shouldn’t warn against them.

--- components/Title.cjsx
+++ components/Title.cjsx
@@ -4,7 +4,7 @@
     displayName: '_Title'

     propTypes:
-        title   : React.PropTypes.string
+        title   : React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.array])
         level   : React.PropTypes.oneOf([1,2,3,4,5,6])
         link    : React.PropTypes.string


Add options: max line length, ignore error codes

Added option to specify maximum line length and ignore specified error codes

--- lib/linter-python-flake8.coffee
+++ lib/linter-python-flake8.coffee
@@ -21,7 +21,27 @@
     atom.config.observe 'linter-python-flake8.executableDir', =>
       @executablePath = atom.config.get 'linter-python-flake8.executableDir'

+    atom.config.observe 'linter-python-flake8.maxLineLength', =>
+      @updateCommand()
+
+    atom.config.observe 'linter-python-flake8.ignoreErrorCodes', =>
+      @updateCommand()
+
   destroy: ->
+    atom.config.unobserve 'linter-python-flake8.maxLineLength'
+    atom.config.unobserve 'linter-python-flake8.ignoreErrorCodes'
     atom.config.unobserve 'linter-python-flake8.executableDir'

+  updateCommand: ->
+    cmd = 'flake8'
+    maxLineLength = atom.config.get 'linter-python-flake8.maxLineLength'
+    errorCodes = atom.config.get 'linter-pep8.ignoreErrorCodes'
+
+    if maxLineLength
+      cmd = "#{cmd} --max-line-length=#{maxLineLength}"
+
+    if errorCodes and errorCodes.length > 0
+      cmd += " --ignore=#{errorCodes.toString()}"
+
+    @cmd = cmd
 module.exports = LinterFlake8


spatial match bugfix + clarification

spatial match bugfix + clarification

--- matching.coffee
+++ matching.coffee
@@ -164,35 +164,39 @@
 spatial_match_helper = (password, graph, graph_name) ->
   result = []
   i = 0
-  while i < password.length
+  while i < password.length - 1
     j = i + 1
     last_direction = null
     turns = 0
     shifted_count = 0
     loop
       prev_char = password.charAt(j-1)
-      cur_char = password.charAt(j)
       found = false
       found_direction = -1
       cur_direction = -1
       adjacents = graph[prev_char] or []
-      for adj in adjacents
-        cur_direction += 1
-        if adj and adj.indexOf(cur_char) != -1
-          found = true
-          found_direction = cur_direction
-          if adj.indexOf(cur_char) == 1
-            # index 1 in the adjacency means the key is shifted, 0 means unshifted: A vs a, % vs 5, etc.
-            # for example, 'q' is adjacent to the entry '2@'. @ is shifted w/ index 1, 2 is unshifted.
-            shifted_count += 1
-          if last_direction != found_direction
-            # adding a turn is correct even in the initial case when last_direction is null:
-            # every spatial pattern starts with a turn.
-            turns += 1
-            last_direction = found_direction
-          break
+      # consider growing pattern by one character if j hasn't gone over the edge.
+      if j < password.length
+        cur_char = password.charAt(j)
+        for adj in adjacents
+          cur_direction += 1
+          if adj and adj.indexOf(cur_char) != -1
+            found = true
+            found_direction = cur_direction
+            if adj.indexOf(cur_char) == 1
+              # index 1 in the adjacency means the key is shifted, 0 means unshifted: A vs a, % vs 5, etc.
+              # for example, 'q' is adjacent to the entry '2@'. @ is shifted w/ index 1, 2 is unshifted.
+              shifted_count += 1
+            if last_direction != found_direction
+              # adding a turn is correct even in the initial case when last_direction is null:
+              # every spatial pattern starts with a turn.
+              turns += 1
+              last_direction = found_direction
+            break
+      # if a pattern was found, extend j and try to grow again
       if found
         j += 1
+      # otherwise push the pattern discovered so far, if any...
       else
         if j - i > 2 # only consider length-3 chains and up
           result.push
@@ -204,6 +208,7 @@
             turns: turns
             shifted_count: shifted_count
         break
+      # ...and start a new search for the rest of the password.
     i = j
   result

@@ -300,7 +305,8 @@
     j: j
     token: password[i..j]

-year_rx = /19\d\d|200\d|201\d/ # 4-digit years only. 2-digit years have the same entropy as 2-digit brute force.
+# 4-digit years only. 2-digit years have the same entropy as 2-digit brute force.
+year_rx = /19\d\d|200\d|201\d/
 year_match = (password) ->
   for match in findall password, year_rx
     [i, j] = [match.i, match.j]


:lipstick: Fix git error using sideview

:lipstick: Fix git error using sideview

--- lib/merge-conflicts-view.coffee
+++ lib/merge-conflicts-view.coffee
@@ -97,6 +97,8 @@
   sideResolver: (side) ->
     (event) ->
       p = $(event.target).find('.path').text()
+      p = $(event.target).parent()?.find('.path').text() unless p.length>0
+      p = $(event.target).parent()?.parent()?.find('.path').text() unless p.length>0
       GitBridge.checkoutSide side, p, ->
         full = path.join atom.project.path, p
         atom.emit 'merge-conflicts:resolved', file: full, total: 1, resolved: 1


Add x, y axis, fix scale

Add x, y axis, fix scale

--- coffee/vis.coffee
+++ coffee/vis.coffee
@@ -16,24 +16,28 @@
   graphHeight = 180
   # padding used underneath the bars to make space
   # for the names of the countries
-  yPadding = 12
-  xPadding = 12
+  yPadding = 20
+  xPadding = 20
   # placeholder for the data
   data = []
+
+  #place holder for x and y maxes
+  xMax = 0
+  yMax = 0

   # using an ordinal scale for X as our
   # data is categorical (the names of countries)
   # xScale = d3.scale.ordinal()
   #   .rangeRoundBands([0, graphWidth], 0.1)

-  xScale = d3.scale.linear().range([0, graphWidth - xPadding])
+

   # names will also be used to color the bars
   #colorScale = d3.scale.ordinal()
   #  .range(["#ff7f0e", "#1f77b4", "#2ca02c", "#d62728", "#8c564b", "#9467bd"])

   # yPadding is removed to make room for country names
-  yScale = d3.scale.linear().range([0, graphHeight - yPadding])
+

   # This is the amount by which we will enlarge the small chart
   # when displaying it in detail display
@@ -48,7 +52,7 @@
     selection.each (rawData) ->
       # store our data and set the scale domains
       data = rawData
-      setScales()
+      #setScales()
       #createLegend()

       # bind data to svg elements so there will be a svg for
@@ -101,14 +105,26 @@
       .attr("width", graphWidth)
       .attr("height", graphHeight)
       .attr("class", "background")
+
+    paddingFactor = 2
+
+    #set different scale for each graph with padding factors for margins
+    xScale = d3.scale.linear().range([0, graphWidth - xPadding*paddingFactor ])
+    yScale = d3.scale.linear().range([graphHeight - yPadding*paddingFactor, 0])
+
+    xMax = 0
+    yMax = 0
+
+    xMax = setXScale(xScale, d)
+    yMax = setYScale(yScale, d)

     # create the dots for the scatter plot
     graph = base.append("g")
     graph.selectAll("circle")
       .data((d) -> d.values) #d now contains exp_ratio, ten_year_return, index
       .enter().append("circle") # the code below will execute for each attr on circle
-      .attr("cx", (d) -> xPadding + xScale(d.exp_ratio))
-      .attr("cy", (d) -> (graphHeight - yScale(d.ten_year_return) - yPadding))
+      .attr("cx", (d) -> xScale(d.exp_ratio) + xPadding)
+      .attr("cy", (d) -> yScale(d.ten_year_return) + yPadding)
       .attr("r", 2)
       .attr("fill", "orange")
       .attr("stroke", "gray")
@@ -120,6 +136,35 @@
       .attr("text-anchor", "middle")
       .attr("x", graphWidth / 2)
       .attr("dy", "1.3em")
+
+    xValues = []
+
+    for i in [0..xMax] by .5
+      xValues.push(i)
+
+    #define xAxis
+    xAxis = d3.svg.axis()
+      .scale(xScale)
+      .orient("bottom")
+      #.ticks(xValues.length) #can only take multiples of 2, 5, 10
+      #.tickValues(xValues)
+
+    #draw x axis
+    graph.append("g")
+      .attr("class", "x axis")
+      .attr("transform", "translate(" + xPadding + "," + (graphHeight - yPadding) + ")")
+      .call(xAxis)
+
+    #define yAxis
+    yAxis = d3.svg.axis()
+      .scale(yScale)
+      .orient("left")
+
+    #draw y axis
+    graph.append("g")
+      .attr("class", "y axis")
+      .attr("transform", "translate(" + xPadding + "," + yPadding + ")")
+      .call(yAxis)

   # This creates the additional text displayed for
   # the detail view.
@@ -271,20 +316,25 @@
   # expects 'data' to be accessible and set to our
   # data.
   # ---
+
+  setXScale = (xScale, d) ->
+    xMax = d3.max(d.values, (e) -> e.exp_ratio) #takes the max of exp_ratio in the values array
+    console.log(xMax)
+    xOffSet = 0.5
+    xScale.domain([0,xMax + xOffSet])
+    xMax
+
+  setYScale = (yScale, d) ->
+    yMax = d3.max(d.values, (e) -> e.ten_year_return)
+    console.log(yMax)
+    yOffset = 7
+    yScale.domain([0,yMax + yOffset]) #change yMax + 500000 to yMax + 7
+    yMax
+
   setScales = () ->
-    #yMax = d3.max(data, (d) -> d3.max(d.values, (e) -> e.value)) #change to e.ten_year_return
-
-    yMax = d3.max(data, (d) -> d3.max(d.values, (e) -> e.ten_year_return))
-
     # this scale is expanded past its max to provide some white space
     # on the top of the bars
     #yScale.domain([0,yMax + 500000]) #change yMax + 500000 to yMax + 5
-
-    yScale.domain([0,yMax + 5]) #change yMax + 500000 to yMax + 5
-
-    xMax = d3.max(data, (d) -> d3.max(d.values, (e) -> e.exp_ratio))
-
-    xScale.domain([0,xMax + 0.5])

     # names = data[0].values.map (d) -> d.name
     # xScale.domain(names)


(#34) Fix path determination when editor isn't active pane item

--- lib/manager.coffee
+++ lib/manager.coffee
@@ -94,8 +94,8 @@

   findMainSelf: ->
     docRegex = /\\begin{document}/
-    editor = atom.workspace.getActivePaneItem()
-    currentPath = editor?.buffer.file?.path
+    editor = atom.workspace.getActiveTextEditor()
+    currentPath = editor?.getPath()
     currentContent = editor?.getText()

     if currentPath and currentContent
@@ -107,8 +107,8 @@

   findMainSelfMagic: ->
     magicRegex = /(?:%\s*!TEX\sroot\s*=\s*([^\s]*\.tex)$)/m
-    editor = atom.workspace.getActivePaneItem()
-    currentPath = editor?.buffer.file?.path
+    editor = atom.workspace.getActiveTextEditor()
+    currentPath = editor?.getPath()
     currentContent = editor?.getText()

     if currentPath and currentContent


Replace the replaced.

Replace the replaced.

Ugh, thank god for that test.

--- lib/notification-element.coffee
+++ lib/notification-element.coffee
@@ -229,8 +229,7 @@

   encodeURI: (str) ->
     str = encodeURI(str)
-    str.replace(/#/g, '%23')
-    str.replace(/;/g, '%3B')
+    str.replace(/#/g, '%23').replace(/;/g, '%3B')

   getRepoUrl: ->
     packageName = @getPackageName()


Add comment

Add comment

--- lib/pg-hoff-results-view.coffee
+++ lib/pg-hoff-results-view.coffee
@@ -3,6 +3,10 @@
 Type = require('./pg-hoff-types').Type

 class PgHoffResultsView
+    # There are only two rules of PgHoffResultsView...
+    # 1. It should update @element on update(resultsets)
+    # 2. Never remove @element from DOM
+
     constructor: (serializedState) ->
         @element = document.createElement('div')
         @element.classList.add('pg-hoff-results-view')


Don't return an array from renderResults

--- lib/project/results-view.coffee
+++ lib/project/results-view.coffee
@@ -64,6 +64,8 @@
       resultView = new ResultView(filePath, result)
       @append(resultView)
       @lastRenderedResultIndex++
+
+    null # dont return an array

   shouldRenderMoreResults: ->
     @prop('scrollHeight') <= @height() + @pixelOverdraw or @scrollBottom() + @pixelOverdraw >= @prop('scrollHeight')


Prepend data to attribute

Prepend data to attribute

--- lib/one-tab.coffee
+++ lib/one-tab.coffee
@@ -28,12 +28,12 @@
         tabView = paneView.querySelector '.tab-bar'

         if pane.getItems().length is 1
-            tabView.setAttribute 'one-tab-height', tabView.style.height
+            tabView.setAttribute 'data-one-tab-height', tabView.style.height
             tabView.style.height = '1px'
         else
-            oldValue = tabView.getAttribute 'one-tab-height'
+            oldValue = tabView.getAttribute 'data-one-tab-height'
             if oldValue isnt null
                 tabView.style.height = oldValue
-                tabView.removeAttribute 'one-tab-height'
+                tabView.removeAttribute 'data-one-tab-height'

 module.exports = new OneTab()


Refactor

Refactor

--- lib/rubocop-auto-correct.coffee
+++ lib/rubocop-auto-correct.coffee
@@ -37,11 +37,10 @@
     @subscriptions.add(bufferSavedSubscription)
     @subscriptions.add(editorDestroyedSubscription)

-  autoCorrect: (editor)  ->
+  autoCorrect: (buffer)  ->
+    command = atom.config.get('rubocop-auto-correct.rubocopCommandPath')
     tempFilePath = @makeTempFile("rubocop.rb")
-    buffer = editor.getBuffer()
     fs.writeFileSync(tempFilePath, buffer.getText())
-    command = atom.config.get('rubocop-auto-correct.rubocopCommandPath')
     args = ['-a', tempFilePath]
     options = { encoding: 'utf-8', timeout: 5000 }

@@ -68,7 +67,7 @@
   run: (editor) ->
     unless editor.getGrammar().scopeName.match("ruby")
       return atom.notifications.addError("Only use source.ruby")
-    @autoCorrect(editor)
+    @autoCorrect(editor.getBuffer())

   makeTempFile: (filename) ->
     directory = temp.mkdirSync()


Gracefully handle errors with spate.pool, too

--- lib/project.coffee
+++ lib/project.coffee
@@ -63,9 +63,7 @@
           projectPath: currentFile.replace ///^#{@root + '/'}///, ''
           targetPath:  if currentFile == indexPath then 'index' else fileMap[currentFile]

-        style.renderFile data, fileInfo, (error) =>
-          return callback error if error
-          done()
+        style.renderFile data, fileInfo, done

     pool.exec (error) =>
       return callback error if error


Cleaning up coffeescript a bit more

Cleaning up coffeescript a bit more

--- lib/psc-ide.coffee
+++ lib/psc-ide.coffee
@@ -2,7 +2,7 @@
 {XRegExp} = require 'xregexp'
 fs = require 'fs'

-{ getModulePrefix, getProjectRoot } = require './utils'
+{ getProjectRoot } = require './utils'

 pscIde = require './psjs/IdePurescript.PscIde'
 psAtomCompletion = require './psjs/IdePurescript.Atom.Completion'
@@ -67,9 +67,6 @@
   getType: (text, modulePrefix) =>
     pscIde.getType(text)(modulePrefix||"")(@editors.getUnqualActiveModules())(@editors.getQualModule)()

-  abbrevType: (type) ->
-    type.replace(/(?:\w+\.)+(\w+)/g, "$1")
-
   loadDeps: (editor) ->
     main = @editors.getMainModuleForEditor editor
     if main
@@ -77,11 +74,9 @@
     else
       Promise.resolve()

-  getSuggestions: ({editor, bufferPosition, scopeDescriptor, prefix}) =>
-    line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])
-
+  getSuggestions: ({editor, bufferPosition}) =>
     psAtomCompletion.getSuggestions({
-      line: line
+      line: editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])
       moduleInfo:
         modules: @editors.getUnqualActiveModules()
         getQualifiedModule: @editors.getQualModule


runtime: Only reset microcontroller on start, not stop

--- lib/runtime.coffee
+++ lib/runtime.coffee
@@ -371,9 +371,17 @@
     subscribeEdges runtime, edges, callback

 handleNetworkCommand = (command, payload, connection, runtime, transport, debugLevel) ->
-    if command is "start" or command is "stop"
+    if command is "start"
         # TODO: handle stop command separately, actually pause the graph
         handleNetworkStartStop runtime, connection, debugLevel
+    else if command is "stop"
+        m =
+            protocol: "network"
+            command: "stopped"
+            payload:
+                running: false
+                started: false
+        sendAck connection, m
     else if command is "edges"
         # TOD: merge with those of exported outports
         runtime.edgesForInspection = payload.edges


Added more documentation to Runtime

Added more documentation to Runtime

--- lib/runtime.coffee
+++ lib/runtime.coffee
@@ -17,6 +17,10 @@
     _.each @formatters, (formatter) => formatter.listen(@runner)

   # Public: Adds a new formatter and asks it to listen for {Runner} events
+  #
+  # A formatter should have two methods:
+  # * `listen(runner)` - in which you can subscribe to {Runner} events
+  # * `destroy` - where you can do your cleanup
   addFormatter: (formatter) ->
     @formatters.push(formatter)
     formatter.listen(@runner)


runtime: Send acks for graph change messages, disable "output"

Makes a couple of more FBP protocol tests pass

--- lib/runtime.coffee
+++ lib/runtime.coffee
@@ -35,7 +35,7 @@
     return a

 connectionsWithoutEdge = (connections, findConn) ->
-    edgeEq (a, b) ->
+    edgeEq = (a, b) ->
         JSON.stringify a == JSON.stringify b
     newList = []
     connections.forEach (conn) ->
@@ -179,24 +179,37 @@
         console.log "Unknown NoFlo UI command on 'component' protocol:", command, payload
     return

+sendAck = (connection, msg) ->
+    connection.send msg
+
 handleGraphCommand = (command, payload, connection, runtime) ->
     graph = runtime.graph
     if command is "clear"
         graph.processes = {}
         graph.connections = []
+        graph.name = payload.name or ''
         graph.nodeMap = {} # nodeName->numericNodeId
+        sendAck connection, { protocol: 'graph', command: command, payload: payload }
     else if command is "addnode"
         graph.processes[payload.id] = payload
+        sendAck connection, { protocol: 'graph', command: command, payload: payload }
     else if command is "removenode"
         delete graph.processes[payload.id]
+        sendAck connection, { protocol: 'graph', command: command, payload: payload }
     else if command is "addedge"
         graph.connections.push wsConnectionFormatToFbp(payload)
+        sendAck connection, { protocol: 'graph', command: command, payload: payload }
     else if command is "removeedge"
         graph.connections = connectionsWithoutEdge(graph.connections, wsConnectionFormatToFbp(payload))
+        sendAck connection, { protocol: 'graph', command: command, payload: payload }
     else if command is "addinitial"
         graph.connections.push wsConnectionFormatToFbp(payload)
+        sendAck connection, { protocol: 'graph', command: command, payload: payload }
     else if command is "removeinitial"
         graph.connections = connectionsWithoutEdge(graph.connections, wsConnectionFormatToFbp(payload))
+        sendAck connection, { protocol: 'graph', command: command, payload: payload }
+
+    # PROTOCOL: Inconsistent that these don't ack on same format?
     else if command is "addinport"
         graph.inports = {} if not graph.inports?
         graph.inports[payload.public] =
@@ -281,7 +294,8 @@
             command: "output"
             payload:
                 message: string
-        send msg
+        # send msg
+        # Should only be used for "output" from program in the runtime itself

 handleNetworkStartStop = (runtime, connection, transport, debugLevel) ->


more fixes to the compilation code

more fixes to the compilation code

--- library/nucleus/cakefile.coffee
+++ library/nucleus/cakefile.coffee
@@ -120,8 +120,9 @@
             assert sources = try readdirSyncRecursive artifacts
             assert sources = _.reject sources, isDirS artifacts
             o = (source) -> optimize("#{artifacts}/#{source}")
-            try logger.info produce, artifacts, s for s in sources
-            (o(s); logger.info(op, artifacts, s)) for s in sources
+            wsources = (fun) -> return try _.each sources, fun
+            wsources (s) -> logger.info produce, artifacts, s
+            wsources (s) -> o s; logger.info op, artifacts, s
             logger.info success.green if status is 0

     # This task launches an instance of application where this task


Check in revamped describe implementation

--- library/vending/describe.coffee
+++ library/vending/describe.coffee
@@ -56,6 +56,27 @@
     # mainly is used to exclude or account for abstract classes.
     @abstract yes

+    # Traverse all of the services that are registered with the router
+    # and collect the documentation for each method, then given this
+    # information, build a hierarhical tree object of all the methods
+    # and the services that implement them and return to the invoker.
+    collectSpecifications: (substitution) ->
+        services = @kernel?.router?.registry
+        services = substitution if substitution?
+        assert _.isArray(services), "invalid services"
+        logger.debug "Collecting API documentation"
+        _.map services, (service) => do (service) =>
+            unsupported = service.unsupported
+            supported = service.constructor.SUPPORTED
+            implemented = (m) -> service[m] isnt unsupported
+            fix = (m) => @constructor.specification service[m], ->
+            doc = (m) => (service[m].document or fix(m)).blankSlate()
+            filtered = _.filter supported, implemented
+            methods = _.object filtered, _.map(filtered, doc)
+            args = (method) => [method, service, @kernel]
+            doc.descriptor? args(m)... for m, doc of methods
+        return service: service, methods: methods
+
     # Describe the supplied method of arbitrary service, in a structured
     # and expected way, so that it can later be used to programmatically
     # process such documentation and do with it whatever is necessary.
@@ -66,28 +87,10 @@
         assert _.isFunction(method), noMethod
         assert _.isFunction(descriptor), noDescriptor
         method.document ?= new Document
-        previous = method.document.descriptor
-        method.document.descriptor = ->
-            ok = _.isFunction previous
-            previous.apply @, arguments if ok
-            descriptor.apply @, arguments
-
-    # Traverse all of the services that are registered with the router
-    # and collect the documentation for each method, then given this
-    # information, build a hierarhical tree object of all the methods
-    # and the services that implement them and return to the invoker.
-    collectSpecifications: (substitution) ->
-        services = @kernel?.router?.registry
-        services = substitution if substitution?
-        assert _.isArray(services), "invalid services"
-        logger.debug "Collecting API documentation"
-        _.map services, (service) -> do (service) ->
-            unsupported = service.unsupported
-            supported = service.constructor.SUPPORTED
-            implemented = (m) -> service[m] isnt unsupported
-            doc = (m) -> service[m].document or new Document
-            filtered = _.filter supported, implemented
-            methods = _.object filtered, _.map(filtered, doc)
-            args = (method) -> [method, service, @kernel]
-            doc.descriptor? args(m)... for m, doc of methods
-            service: service, methods: methods
+        method.document.descriptor = descriptor
+        method.document.blankSlate = ->
+            document = new Document
+            document.descriptor = @descriptor
+            document.blankSlate = @blankSlate
+            return document
+        return method.document


changing name mangling for parasites

changing name mangling for parasites

--- library/membrane/auxes.coffee
+++ library/membrane/auxes.coffee
@@ -84,7 +84,7 @@
     # value is a function that evaluates inclusions conditions every
     # time when any auxilliary-powered services is being executed.
     @parasite: (signature) ->
-        assert uid = try _.uniqueId "parasite_"
+        assert uid = try _.uniqueId "__parasite_"
         vector = Auxiliaries.$parasites ?= Array()
         return vector unless arguments.length >= 1
         identity = try this?.identify?().toString?()