Test the case of anonymous read-write token access being turned on

--- services/web/test/UnitTests/coffee/TokenAccess/TokenAccessControllerTests.coffee
+++ services/web/test/UnitTests/coffee/TokenAccess/TokenAccessControllerTests.coffee
@@ -104,6 +104,82 @@
 				expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
 				done()

+
+		describe 'when there is no user', ->
+			beforeEach ->
+				@AuthenticationController.getLoggedInUserId =
+					sinon.stub().returns(null)
+
+			describe 'when anonymous read-write access is enabled', ->
+				beforeEach ->
+					@TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED = true
+					@req = new MockRequest()
+					@res = new MockResponse()
+					@next = sinon.stub()
+					@req.params['read_and_write_token'] = @readAndWriteToken
+					@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
+						.callsArgWith(1, null, @project)
+					@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
+						.callsArgWith(2, null)
+					@ProjectController.loadEditor = sinon.stub()
+					@TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
+					@TokenAccessController.readAndWriteToken @req, @res, @next
+
+				it 'should not add the user to the project with read-write access', (done) ->
+					expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
+						.to.equal 0
+					done()
+
+				it 'should give the user session token access', (done) ->
+					expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
+						.to.equal 1
+					expect(@TokenAccessHandler.grantSessionTokenAccess.calledWith(
+						@req, @projectId, @readAndWriteToken
+					))
+						.to.equal true
+					done()
+
+				it 'should pass control to loadEditor', (done) ->
+					expect(@req.params.Project_id).to.equal @projectId.toString()
+					expect(@ProjectController.loadEditor.callCount).to.equal 1
+					expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
+					done()
+
+			describe 'when anonymous read-write access is not enabled', ->
+				beforeEach ->
+					@TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED = false
+					@req = new MockRequest()
+					@res = new MockResponse()
+					@next = sinon.stub()
+					@req.params['read_and_write_token'] = @readAndWriteToken
+					@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
+						.callsArgWith(1, null, @project)
+					@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
+						.callsArgWith(2, null)
+					@ProjectController.loadEditor = sinon.stub()
+					@TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
+					@TokenAccessController.readAndWriteToken @req, @res, @next
+
+				it 'should not add the user to the project with read-write access', (done) ->
+					expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
+						.to.equal 0
+					done()
+
+				it 'should give the user session token access', (done) ->
+					expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
+						.to.equal 0
+					done()
+
+				it 'should not pass control to loadEditor', (done) ->
+					expect(@ProjectController.loadEditor.callCount).to.equal 0
+					expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
+					done()
+
+				it 'should call next with an error', (done) ->
+					expect(@next.callCount).to.equal 1
+					expect(@next.lastCall.args[0]).to.be.instanceof Error
+					done()
+
 		describe 'when findProject produces an error', ->
 			beforeEach ->
 				@req = new MockRequest()
@@ -142,99 +218,105 @@
 		describe 'when findProject does not find a project', ->
 			beforeEach ->

-			describe 'when token access is off, but user has higher access anyway', ->
-				beforeEach ->
-					@req = new MockRequest()
-					@res = new MockResponse()
-					@res.redirect = sinon.stub()
-					@next = sinon.stub()
-					@req.params['read_and_write_token'] = @readAndWriteToken
-					@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
-						.callsArgWith(1, null, null)
-					@TokenAccessHandler.findProjectWithHigherAccess =
-						sinon.stub()
-						.callsArgWith(2, null, @project)
-					@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
-						.callsArgWith(2, null)
-					@ProjectController.loadEditor = sinon.stub()
-					@TokenAccessController.readAndWriteToken @req, @res, @next
-
-				it 'should try to find a project with this token', (done) ->
-					expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
-						.to.equal 1
-					expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
-						.to.equal true
-					done()
-
-				it 'should check if user has higher access to the token project', (done) ->
-					expect(
-						@TokenAccessHandler.findProjectWithHigherAccess.callCount
-					).to.equal 1
-					done()
-
-				it 'should not add the user to the project with read-write access', (done) ->
-					expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
-						.to.equal 0
-					done()
-
-				it 'should not pass control to loadEditor', (done) ->
-					expect(@ProjectController.loadEditor.callCount).to.equal 0
-					expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
-					done()
-
-				it 'should not call next with a not-found error', (done) ->
-					expect(@next.callCount).to.equal 0
-					done()
-
-				it 'should redirect to the canonical project url', (done) ->
-					expect(@res.redirect.callCount).to.equal 1
-					expect(@res.redirect.calledWith(302, "/project/#{@project._id}")).to.equal true
-					done()
-
-			describe 'when higher access is not available', ->
-				beforeEach ->
-					@req = new MockRequest()
-					@res = new MockResponse()
-					@next = sinon.stub()
-					@req.params['read_and_write_token'] = @readAndWriteToken
-					@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
-						.callsArgWith(1, null, null)
-					@TokenAccessHandler.findProjectWithHigherAccess =
-						sinon.stub()
-						.callsArgWith(2, null, null)
-					@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
-						.callsArgWith(2, null)
-					@ProjectController.loadEditor = sinon.stub()
-					@TokenAccessController.readAndWriteToken @req, @res, @next
-
-				it 'should try to find a project with this token', (done) ->
-					expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
-						.to.equal 1
-					expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(
-						@readAndWriteToken
-					)).to.equal true
-					done()
-
-				it 'should check if user has higher access to the token project', (done) ->
-					expect(
-						@TokenAccessHandler.findProjectWithHigherAccess.callCount
-					).to.equal 1
-					done()
-
-				it 'should not add the user to the project with read-write access', (done) ->
-					expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
-						.to.equal 0
-					done()
-
-				it 'should not pass control to loadEditor', (done) ->
-					expect(@ProjectController.loadEditor.callCount).to.equal 0
-					expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
-					done()
-
-				it 'should call next with a not-found error', (done) ->
-					expect(@next.callCount).to.equal 1
-					expect(@next.lastCall.args[0]).to.be.instanceof Error
-					done()
+			describe 'when user is present', ->
+				beforeEach ->
+					@AuthenticationController.getLoggedInUserId =
+						sinon.stub().returns(@userId.toString())
+
+				describe 'when token access is off, but user has higher access anyway', ->
+					beforeEach ->
+						@req = new MockRequest()
+						@res = new MockResponse()
+						@res.redirect = sinon.stub()
+						@next = sinon.stub()
+						@req.params['read_and_write_token'] = @readAndWriteToken
+						@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
+							.callsArgWith(1, null, null)
+						@TokenAccessHandler.findProjectWithHigherAccess =
+							sinon.stub()
+							.callsArgWith(2, null, @project)
+						@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
+							.callsArgWith(2, null)
+						@ProjectController.loadEditor = sinon.stub()
+						@TokenAccessController.readAndWriteToken @req, @res, @next
+
+					it 'should try to find a project with this token', (done) ->
+						expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
+							.to.equal 1
+						expect(@TokenAccessHandler.findProjectWithReadAndWriteToken
+							.calledWith(@readAndWriteToken)
+						).to.equal true
+						done()
+
+					it 'should check if user has higher access to the token project', (done) ->
+						expect(
+							@TokenAccessHandler.findProjectWithHigherAccess.callCount
+						).to.equal 1
+						done()
+
+					it 'should not add the user to the project with read-write access', (done) ->
+						expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
+							.to.equal 0
+						done()
+
+					it 'should not pass control to loadEditor', (done) ->
+						expect(@ProjectController.loadEditor.callCount).to.equal 0
+						expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
+						done()
+
+					it 'should not call next with a not-found error', (done) ->
+						expect(@next.callCount).to.equal 0
+						done()
+
+					it 'should redirect to the canonical project url', (done) ->
+						expect(@res.redirect.callCount).to.equal 1
+						expect(@res.redirect.calledWith(302, "/project/#{@project._id}")).to.equal true
+						done()
+
+				describe 'when higher access is not available', ->
+					beforeEach ->
+						@req = new MockRequest()
+						@res = new MockResponse()
+						@next = sinon.stub()
+						@req.params['read_and_write_token'] = @readAndWriteToken
+						@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
+							.callsArgWith(1, null, null)
+						@TokenAccessHandler.findProjectWithHigherAccess =
+							sinon.stub()
+							.callsArgWith(2, null, null)
+						@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
+							.callsArgWith(2, null)
+						@ProjectController.loadEditor = sinon.stub()
+						@TokenAccessController.readAndWriteToken @req, @res, @next
+
+					it 'should try to find a project with this token', (done) ->
+						expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
+							.to.equal 1
+						expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(
+							@readAndWriteToken
+						)).to.equal true
+						done()
+
+					it 'should check if user has higher access to the token project', (done) ->
+						expect(
+							@TokenAccessHandler.findProjectWithHigherAccess.callCount
+						).to.equal 1
+						done()
+
+					it 'should not add the user to the project with read-write access', (done) ->
+						expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
+							.to.equal 0
+						done()
+
+					it 'should not pass control to loadEditor', (done) ->
+						expect(@ProjectController.loadEditor.callCount).to.equal 0
+						expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
+						done()
+
+					it 'should call next with a not-found error', (done) ->
+						expect(@next.callCount).to.equal 1
+						expect(@next.lastCall.args[0]).to.be.instanceof Error
+						done()

 		describe 'when adding user to project produces an error', ->
 			beforeEach ->


Fix touch restart.txt daemon test

Fix touch restart.txt daemon test

--- test/test_daemon.coffee
+++ test/test_daemon.coffee
@@ -47,8 +47,11 @@
     daemon = new Daemon configuration

     daemon.start()
-    touch restartFilename, ->
-      daemon.once "restart", ->
-        fs.exists restartFilename, (exists) ->
-          test.ok !exists
-          test.done()
+
+    daemon.once "restart", ->
+      fs.exists restartFilename, (exists) ->
+        test.ok !exists
+        daemon.stop()
+        test.done()
+
+    touch restartFilename


:new: Implement basic linter-views::rner

--- lib/linter-views.coffee
+++ lib/linter-views.coffee
@@ -24,7 +24,13 @@

   # This message is called in editor-linter.coffee
   render: ->
+    return @panel.hide() unless @linter.activeEditor
+    return @panel.hide() unless @linter.activeEditor?.getPath()

+    activeLinter = @linter.getActiveEditorLinter()
+    messages = LinterViews._extractMessages(@linter.messagesProject)
+    messages = messages.concat(LinterViews._extractMessages(activeLinter.messages)) if activeLinter
+    @messages = messages

   # This method is called when we get the status-bar service
   attachBottom: (statusBar)->
@@ -42,4 +48,8 @@
   deactivate: ->
     @panel.removeDecorations()
     @panelWorkspace.destroy()
+
+  # This method is called in render, and classifies the messages according to scope
+  @_extractMessages: (Gen)->
+
 module.exports = LinterViews


subscribe active buffer `changed`

subscribe active buffer `changed`

--- lib/minimap-view.coffee
+++ lib/minimap-view.coffee
@@ -17,10 +17,11 @@
   configs: {}

   constructor: (@paneView) ->
+    super
+
     @scaleX = 0.2
     @scaleY = @scaleX * 0.8
     @minimapScale = @scale(@scaleX, @scaleY)
-    super

   initialize: ->
     @attach()
@@ -31,9 +32,6 @@
     @subscribe @paneView.model.$activeItem, @onActiveItemChanged
     @subscribe @paneView.model, 'destroy', => @destroy()
     @subscribe $(window), 'resize:end', @resizeend
-
-    #@subscribe atom.workspaceView, 'cursor:moved', =>
-    #  @update()

   attach: ->
     themeProp = 'minimap.theme'
@@ -47,6 +45,7 @@
     @unsubscribe @paneView.model.$activeItem
     @unsubscribe @paneView.model, 'destroy'
     @unsubscribe $(window), 'resize:end'
+    @unsubscribeBuffer()

     @paneView.removeClass('with-minimap')
     @remove()
@@ -59,10 +58,12 @@
     @attr 'data-theme': this.configs.theme

   onActiveItemChanged: (item) =>
-    # Fix called twice when open minimap!
+    # Fix called twice when opening minimap!
     return if @activeItem == item
     @activeItem = item
     @getActiveEditor()
+    @getActiveBuffer()
+    @subscribeBuffer()
     @updateMinimapView()

   getActiveEditor: ->
@@ -72,7 +73,7 @@
       return @editor = @scrollView = null

     @editor = @editorView.getEditor()
-    @scrollView = @editorView.find('.scroll-view')
+    @scrollView = @editorView.scrollView
     @scrollViewLines = @scrollView.find('.lines')

     # current editor bind scrollTop event
@@ -81,6 +82,17 @@
     @editor.off 'scroll-left-changed.editor'
     @editor.on 'scroll-left-changed.editor', @scrollLeft

+  getActiveBuffer: ->
+    @buffer = @editor?.getBuffer?()
+
+  unsubscribeBuffer: =>
+    @buffer.off 'changed', @onActiveBufferChanged if @buffer
+
+  subscribeBuffer: =>
+    @buffer.on 'changed', @onActiveBufferChanged if @buffer
+
+  onActiveBufferChanged: =>
+    @updateMinimapView()

   # wtf? Long long function!
   updateMinimapView: ->
@@ -108,7 +120,7 @@
     # offset minimap
     @offset({ 'top': @editorView.offset().top })

-    # reset minimap layer size
+    # reset size of minimap layer
     @reset()

     # get rects
@@ -117,11 +129,14 @@
     @miniScrollViewRect = @miniEditorView.getClientRect()

     # reset minimap-overlayer
+    # top will be set 0 when reseting
+    @miniOverlayer.addClass 'hide'
     @miniOverlayer.css
       width: @scrollViewRect.width
       height: @editorViewRect.height
       '-webkit-transform': @translateY()
       transform: @translateY()
+    @miniOverlayer.removeClass 'hide'

     @transform @miniWrapper[0], @minimapScale


:memo: #87

:memo: #87

--- lib/mode-manager.coffee
+++ lib/mode-manager.coffee
@@ -168,7 +168,9 @@

       @eachSelection (s) ->
         swrap(s).resetProperties()
-        s.selectLeft() unless (s.isReversed() or s.isEmpty())
+        # `c`, `s` from visual-mode make selection empty
+        unless (s.isReversed() or s.isEmpty())
+          s.selectLeft()
         s.clear(autoscroll: false)

   restoreCharacterwiseRange: ->


Fix typo

Fix typo

--- lib/pg-hoff-util.coffee
+++ lib/pg-hoff-util.coffee
@@ -8,13 +8,13 @@
                 reject(error)

             fulfil(stdout)
-        )
+        )en recepp
     )

 spawnHoffServer = (command, args) ->
     resolved = false
     return new Promise((fulfil, reject) ->
-        s = spawn('pghoffserver', [''], { env: process.env, detatched: true })
+        s = spawn('pghoffserver', [''], { env: process.env, detached: true })

         s.stdout.on 'data', (data)      -> fulfil(data.toString()) if not resolved
         s.stderr.on 'data', (data)      -> fulfil('stderr ' + data.toString()) if not resolved


[WIP] Use existing products and exchange prices.

--- lib/price-import.coffee
+++ lib/price-import.coffee
@@ -4,8 +4,9 @@
 Promise = require 'bluebird'
 slugify = require 'underscore.string/slugify'
 {SphereClient, ProductSync} = require 'sphere-node-sdk'
+ProductImport = require './product-import'

-class PriceImport
+class PriceImport extends ProductImport

   constructor: (@logger, options = {}) ->
     @sync = new ProductSync
@@ -27,17 +28,17 @@
   @_processBatches: (prices) ->
     batchedList = _.batchList(prices, 30) # max parallel elements to process
     Promise.map batchedList, (pricesToProcess) =>
-      @_wrapPricesIntoProducts(pricesToProcess)
-      .then (wrappedProducts) =>
-        skus = @_extractUniqueSkus(wrappedProducts)
-        predicate = @_createProductFetchBySkuQueryPredicate(skus)
-        @client.productProjections
-        .where(predicate)
-        .staged(true)
-        .fetch()
-        .then (results) =>
-          debug 'Fetched products: %j', results
-          queriedEntries = results.body.results
+      skus = @_extractUniqueSkus(pricesToProcess)
+      predicate = @_createProductFetchBySkuQueryPredicate(skus)
+      @client.productProjections
+      .where(predicate)
+      .staged(true)
+      .fetch()
+      .then (results) =>
+        debug 'Fetched products: %j', results
+        queriedEntries = results.body.results
+        @_wrapPricesIntoProducts(pricesToProcess, queriedEntries)
+        .then (wrappedProducts) =>
           @_createOrUpdate wrappedProducts, queriedEntries
           .then (results) =>
             _.each results, (r) =>
@@ -47,60 +48,25 @@
             Promise.resolve()
     ,{concurrency: 1}

+  _wrapPricesIntoProducts: (prices, products) ->
+    sku2index = {}
+    _.each prices.prices, (p, index) ->
+      if not _.has(sku2index, p.sku)
+        sku2index[p.sku] = []
+      sku2index[p.sku].push index
+    console.log "sku2index", sku2index

+    _.each products.products, (p) =>
+      @_wrapPriceIntoVariant p.masterVariant, prices.prices, sku2index
+      _.each p.variants, (v) =>
+        @_wrapPriceIntoVariant v, prices.prices, sku2index

-  _createOrUpdate: (productsToProcess, existingProducts) ->
-    debug 'Products to process: %j', {toProcess: productsToProcess, existing: existingProducts}
-
-    posts = _.map productsToProcess, (prodToProcess) =>
-      existingProduct = @_isExistingEntry(prodToProcess, existingProducts)
-      if existingProduct?
-        synced = @sync.buildActions(prodToProcess, existingProduct)
-        if synced.shouldUpdate()
-          @client.products.byId(synced.getUpdateId()).update(synced.getUpdatePayload())
-        else
-          Promise.resolve statusCode: 304
-      else
-        @_summary.unknownSKUCount++
-        Promise.resolve statusCode: 404
-
-    debug 'About to send %s requests', _.size(posts)
-    Promise.all(posts)
-
-
-  _wrapPricesIntoProducts: (prices) ->
-    new Promise(resolve, reject) ->
-      products = []
-      # Some wrapping magic from @Hajo
-      resolve products
-
-
-  _createProductFetchBySkuQueryPredicate: (skus) ->
-    skuString = "sku in (\"#{skus.join('", "')}\")"
-    return "masterVariant(#{skuString}) or variants(#{skuString})"
-
-  _extractUniqueSkus: (products) ->
-    skus = []
-    for product in products
-      if product.masterVariant?.sku
-        skus.push(product.masterVariant.sku)
-      else @_summary.emptySKU++
-      if product.variants and not _.isEmpty(product.variants)
-        for variant in product.variants
-          if variant.sku
-            skus.push(variant.sku)
-          else @_summary.emptySKU++
-    return _.uniq(skus,false)
-
-
-  _isExistingEntry: (prodToProcess, existingProducts) ->
-    prodToProcessSkus = @_extractUniqueSkus([prodToProcess])
-    _.find existingProducts, (existingEntry) =>
-      existingProductSkus =  @_extractUniqueSkus([existingEntry])
-      matchingSkus = _.intersection(prodToProcessSkus,existingProductSkus)
-      if matchingSkus.length > 0
-        true
-      else
-        false
+  _wrapPriceIntoVariant: (variant, prices, sku2index) ->
+    if _.has(sku2index, variant.sku)
+      variant.prices = []
+      _.each sku2index[variant.sku], (index) ->
+        price = _.deepClone prices[index]
+        delete price.sku
+        variant.prices.push price

 module.exports = PriceImport


removed console log debug line

removed console log debug line

--- lib/tab-bar-view.coffee
+++ lib/tab-bar-view.coffee
@@ -234,7 +234,6 @@
       false

   onDragLeave: (event) =>
-    console.log("leaving")
     @removePlaceholder()

   onDragEnd: (event) =>


Add icon

Add icon

--- lib/timecop-view.coffee
+++ lib/timecop-view.coffee
@@ -81,3 +81,5 @@
   getUri: -> @uri

   getTitle: -> 'Timecop'
+
+  getIconName: -> 'dashboard'


remove references to removed specs

remove references to removed specs

--- spec/runner.coffee
+++ spec/runner.coffee
@@ -1,7 +1,5 @@
 define 'runner', (require) ->
   specs = [
-    'settings',
-    'context',
     'notebook',
     'github',
     'graphite'


修改模块配置时，顺便更新应用配置信息

修改模块配置时，顺便更新应用配置信息

--- lib/utils/client.coffee
+++ lib/utils/client.coffee
@@ -10,14 +10,14 @@
     defaultsParams =
       baseUrl: config.serverUrl
       method: 'GET'
-    console.log defaultsParams.baseUrl+params.url
+    # console.log defaultsParams.baseUrl+params.url
     if params.sendCookie and util.store('chameleon-cookie').length > 0
       cookie = request.cookie(util.store('chameleon-cookie'))
       j.setCookie(cookie, config.serverUrl)
       params.jar = j
     params = $.extend defaultsParams, params
     cb = (err, httpResponse, body) =>
-      console.log httpResponse
+      # console.log httpResponse
       if !err && httpResponse.statusCode is 200

         headerCookie = if typeof httpResponse.headers['set-cookie'] is 'undefined' then '' else httpResponse.headers['set-cookie'][0]


Update note

Update note

--- lib/welcome-view.coffee
+++ lib/welcome-view.coffee
@@ -83,9 +83,8 @@
           @li => @raw 'Discuss Atom at discuss.atom.io.'
           @li => @raw 'The Atom Org. This is where all GitHub created Atom packages can be found.'
         @p class: 'welcome-note', =>
-           @raw 'Note: To help us improve Atom, we anonymously track usage metrics. See the
-           atom/metrics package for details on what
-           information is tracked and for instructions on how to disable it.'
+           @raw 'Note: To help us improve Atom, we anonymously track usage metrics, such as launch time, screen size, used version etc. See the
+           atom/metrics package for details and for instructions on how to disable it.'

       @footer class:'welcome-footer', =>
         @raw 'atom.io × '


fix back list button in mediatheque

fix back list button in mediatheque

--- BackofficeBundle/Resources/public/coffee/mediatheque/GalleryCollectionView.coffee
+++ BackofficeBundle/Resources/public/coffee/mediatheque/GalleryCollectionView.coffee
@@ -5,8 +5,9 @@
   initialize: (options) ->
     @options = @reduceOption(options, [
       'medias'
+      'title'
+      'listUrl'
       'domContainer'
-      'title'
       'modal'
     ])
     @loadTemplates [
@@ -44,13 +45,12 @@

   clickAdd: (event) ->
     event.preventDefault()
-    options = @options
     viewContext = @
     if $('#main .' + $(event.target).attr('class')).length
       displayLoader('div[role="container"]')
       Backbone.history.navigate('/add')
       $.ajax
-        url: options.medias.get('links')._self_add
+        url: @options.medias.get('links')._self_add
         method: 'GET'
         success: (response) ->
           new FullPageFormView(viewContext.addOption(


Explicitly check in view after scroll

Explicitly check in view after scroll

--- angular/core/services/scroll_service.coffee
+++ angular/core/services/scroll_service.coffee
@@ -6,5 +6,6 @@
       elem      = document.querySelector(target)
       container = document.querySelector('.lmo-main-content')
       if elem && container
-        angular.element(container).scrollToElement(elem, offset, speed)
+        angular.element(container).scrollToElement(elem, offset, speed).then ->
+          angular.element(window).triggerHandler('checkInView')
         elem.focus()


Increase polling to 150 seconds maximum before showing error message.

--- app/assets/javascripts/admin/orders/controllers/bulk_invoice_controller.js.coffee
+++ app/assets/javascripts/admin/orders/controllers/bulk_invoice_controller.js.coffee
@@ -21,7 +21,7 @@
     .error (data) ->
       $scope.poll++

-      if $scope.poll > 10
+      if $scope.poll > 30
         $scope.loading = false
         $scope.error = t('js.admin.orders.index.bulk_invoice_failed')
         return


payment: only store "oldSubscription" if needed

We were storing oldSubscription even if it was the same as the new subscription

--- client/app/Applications/Environments.kdapplication/views/vms/vmproductform.coffee
+++ client/app/Applications/Environments.kdapplication/views/vms/vmproductform.coffee
@@ -7,8 +7,9 @@
     { subscription } = @collector.data
     return callback { message: 'no subscription' }  unless subscription?
     subscription.checkUsage pack, (err, usage) =>
-      @collectData oldSubscription: subscription
-      @clearData 'subscription'  if err
+      if err
+        @collectData oldSubscription: subscription
+        @clearData 'subscription'

       callback err, usage


Don't try to move startup.dekstop

Don't try to move startup.dekstop

--- tasks/build.coffee
+++ tasks/build.coffee
@@ -56,12 +56,6 @@
         toPath = './build/' + dist + '/usr/share/applications/' + manifest.name + '.desktop'
         fs.copy fromPath, toPath, utils.log callback, fromPath, '=>', toPath

-      # Move the app's .desktop file to be used on startup
-      (callback) ->
-        fromPath = './build/resources/linux/startup.desktop'
-        toPath = './build/' + dist + '/opt/' + manifest.name + '/startup.desktop'
-        fs.copy fromPath, toPath, utils.log callback, fromPath, '=>', toPath
-
       # Move icons
       async.apply async.waterfall, [
         async.apply fs.readdir, './build/resources/linux/icons'


Fixes based on CR feedback

Fixes based on CR feedback

--- test/lib/httpReceiver.test.coffee
+++ test/lib/httpReceiver.test.coffee
@@ -11,11 +11,8 @@
 # the License.

 should = require 'should'
-assert = require 'assert'
 supertest = require 'supertest'
 async = require 'async'
-path = require 'path'
-fs = require 'fs'
 runner = require '../../lib/receiver'

 TEST_URL = 'http://localhost:7777'


Changed wording in remove card dialog.

Changed wording in remove card dialog.

--- packages/landsofillusions/components/account/paymentmethods/paymentmethods.coffee
+++ packages/landsofillusions/components/account/paymentmethods/paymentmethods.coffee
@@ -106,7 +106,7 @@
       dialog = new LOI.Components.Dialog
         message: "Do you really want to remove this payment method?"
         buttons: [
-          text: "Yes"
+          text: "Remove"
           value: true
         ,
           text: "Cancel"


added test for selecting a package and getting a subset of nodes

Signed-off-by: Dominik Richter <b7323add517e187efe0283b76511b7ed762bfe13@gmail.com>

--- test/spec/controllers/main.coffee
+++ test/spec/controllers/main.coffee
@@ -235,6 +235,18 @@
     scope.updateNodeSelection()
     expect( scope.nodes ).toBe( scope.allNodes )

+  it 'should provide only the node which has the selected package', () ->
+    scope.allNodes = allNodes1
+    scope.packageByName['p'] =
+      'versions': [{ 'id': 'pid' }]
+    scope.package['pid'] = {}
+    scope.package['pid'].nodes = [ { 'id': allNodes1[0].id } ]
+    scope.packageSelected['p'] = true
+    scope.updateNodeSelection()
+    expect( scope.nodes.length ).toBe( 1 )
+    expect( scope.nodes[0].id ).toBe( allNodes1[0].id )
+
+
   it 'should provide all packages if no node is selected', () ->
     scope.allPackages = allPackages1
     scope.updatePackageSelection()


UPDATE: FullScreenApp is now using the iOS "black" status-bar-style instead of "black-transparent" - it just wasn't worth every app having to take care of this special case in terms of layout

--- source/Art/Engine/FullScreenApp.coffee
+++ source/Art/Engine/FullScreenApp.coffee
@@ -81,7 +81,7 @@
     nameContentMetas = merge
       "viewport": "user-scalable=no, width=device-width, initial-scale=1.0"
       "apple-mobile-web-app-capable": "yes"
-      "apple-mobile-web-app-status-bar-style": "black-translucent"
+      "apple-mobile-web-app-status-bar-style": "black" #"black-translucent"
       "format-detection": "telephone=no"
       meta


Improve timer static things

Improve timer static things

--- src/6.timer.coffee
+++ src/6.timer.coffee
@@ -13,6 +13,7 @@

 class Date.Timer
     @_endOfTime: new Date("9999-12-30T00:00:00Z")
+    @_precision: null
     @enable: (precision = 30) ->
         Date.Timer._precision = precision
         @_internalTimer = setInterval(=>
@@ -21,9 +22,12 @@
         undefined
     @disable: ->
         clearInterval(@_internalTimer)
+        Date.Timer._precision = null
         undefined
     @getPrecision: ->
         Date.Timer._precision
+    @getEnabled: ->
+        Date.Timer._precision?
     @_onCheck: eventField()
     constructor: (options) ->
         @targetTime = options?.targetTime ? Date.Timer._endOfTime


Remove unneeded activatePackage calls

Remove unneeded activatePackage calls

These are already done in the root beforeEach

--- spec/app/text-mate-grammar-spec.coffee
+++ spec/app/text-mate-grammar-spec.coffee
@@ -515,7 +515,6 @@
       lines = null

       beforeEach ->
-        atom.activatePackage('ruby-tmbundle', sync: true)
         atom.activatePackage('todo-tmbundle', sync: true)
         grammar = syntax.selectGrammar('main.rb')
         lines = grammar.tokenizeLines "# TODO be nicer"
@@ -631,8 +630,6 @@

     describe "HTML (Ruby - ERB)", ->
       beforeEach ->
-        atom.activatePackage('html-tmbundle', sync: true)
-        atom.activatePackage('ruby-tmbundle', sync: true)
         grammar = syntax.selectGrammar('page.erb')
         lines = grammar.tokenizeLines '<% page_title "My Page" %>'

@@ -648,7 +645,6 @@

     describe "Surrogate pair characters", ->
       beforeEach ->
-        atom.activatePackage('javascript-tmbundle', sync: true)
         grammar = syntax.selectGrammar('main.js')
         lines = grammar.tokenizeLines "'\uD835\uDF97'"


style(test-runner-test.coffee): Reformat Whitespace

--- test/unit/test-runner-test.coffee
+++ test/unit/test-runner-test.coffee
@@ -53,7 +53,7 @@
         options =
           server: "#{ABAO_IO_SERVER}"

-        runner = new TestRunner options , ''
+        runner = new TestRunner options, ''

         runCallback = sinon.stub()
         runCallback(done)
@@ -155,6 +155,7 @@
         # it 'should call after hook', () ->
         #   assert.ok hooksStub.runAfter.calledWith(test)

+
     describe 'Interact with #test', () ->

       test = ''
@@ -192,9 +193,10 @@
       it 'should call #test.run', () ->
         assert.ok test.run.calledOnce

+
     describe 'when test has no response code', () ->
-      before (done) ->
-
+
+      before (done) ->
         testFactory = new TestFactory()
         test = testFactory.create()
         test.name = 'GET /machines -> 200'
@@ -230,9 +232,10 @@
         assert.equal tests.length, 1
         assert.ok tests[0].pending

+
     describe 'when test skipped in hooks', () ->
-      before (done) ->
-
+
+      before (done) ->
         testFactory = new TestFactory()
         test = testFactory.create()
         test.name = 'GET /machines -> 200'
@@ -274,9 +277,10 @@
         assert.equal tests.length, 1
         assert.ok tests[0].pending

+
     describe 'when test has no response schema', () ->
-      before (done) ->
-
+
+      before (done) ->
         testFactory = new TestFactory()
         test = testFactory.create()
         test.name = 'GET /machines -> 200'
@@ -313,12 +317,12 @@
         assert.equal tests.length, 1
         assert.notOk tests[0].pending

+
     describe 'when test throws AssertionError', () ->

       afterAllHook = ''

       before (done) ->
-
         testFactory = new TestFactory()
         test = testFactory.create()
         test.name = 'GET /machines -> 200'
@@ -351,13 +355,13 @@
       it 'should call afterAll hook', () ->
         afterAllHook.should.have.been.called

+
     describe 'when beforeAllHooks throws UncaughtError', () ->

       beforeAllHook = ''
       afterAllHook = ''

       before (done) ->
-
         testFactory = new TestFactory()
         test = testFactory.create()
         test.name = 'GET /machines -> 200'
@@ -394,11 +398,12 @@
       it 'should call afterAll hook', () ->
         afterAllHook.should.have.been.called

+
   describe '#run with options', () ->

     describe 'list all tests with `names`', () ->
-      before (done) ->
-
+
+      before (done) ->
         testFactory = new TestFactory()
         test = testFactory.create()
         test.name = 'GET /machines -> 200'
@@ -435,6 +440,7 @@
       it 'should print tests', () ->
         assert.ok console.log.calledWith('GET /machines -> 200')

+
     describe 'add additional headers with `headers`', () ->

       receivedTest = ''
@@ -473,6 +479,7 @@

       it 'should add headers into test', () ->
         assert.deepEqual receivedTest.request.headers, header
+

     describe 'run test with hooks only indicated by `hooks-only`', () ->

@@ -487,7 +494,6 @@
       suiteStub = ''

       before (done) ->
-
         options =
           server: "#{SERVER}"
           'hooks-only': true
@@ -523,7 +529,7 @@
       it 'should run mocha', () ->
         assert.ok runner.mocha.run.called

-      it 'should add a pending test', () ->
+      it 'should add a pending test'
         # TODO(quanlong): Implement this test
         # console.log suiteStub.addTest.printf('%n-%c-%C')
         # assert.ok suiteStub.addTest.calledWithExactly('GET /machines -> 200')


change scope

change scope

--- snippets/emoji-html.cson
+++ snippets/emoji-html.cson
@@ -1,4 +1,4 @@
-".text.html":
+".text.html.basic":
   "😀":
     body: "😀"
     prefix: "ji:grinning-face"


refactoring persistence-sel-spec

refactoring persistence-sel-spec

--- spec/persistent-selectionr-spec.coffee
+++ spec/persistent-selectionr-spec.coffee
@@ -19,7 +19,14 @@
     textForMarker = (marker) ->
       editor.getTextInBufferRange(marker.getBufferRange())

-    ensurePersistentSelection = (options) ->
+    ensurePersistentSelection = (args...) ->
+      switch args.length
+        when 1 then [options] = args
+        when 2 then [_keystroke, options] = args
+
+      if _keystroke?
+        keystroke(_keystroke)
+
       markers = vimState.persistentSelection.getMarkers()
       if options.length?
         expect(markers).toHaveLength(options.length)
@@ -52,14 +59,19 @@
     describe "basic behavior", ->
       describe "create-persistent-selection", ->
         it "create-persistent-selection create range marker", ->
-          keystroke('g m i w')
-          ensurePersistentSelection length: 1, text: ['ooo']
-          keystroke('j .')
-          ensurePersistentSelection length: 2, text: ['ooo', 'xxx']
+          ensurePersistentSelection 'g m i w',
+            length: 1
+            text: ['ooo']
+          ensurePersistentSelection 'j .',
+            length: 2
+            text: ['ooo', 'xxx']
+
       describe "[No behavior diff currently] inner-persistent-selection and a-persistent-selection", ->
         it "apply operator to across all persistent-selections", ->
-          keystroke('g m i w j . 2 j g m i p') # Mark 2 inner-word and 1 inner-paragraph
-          ensurePersistentSelection length: 3, text: ['ooo', 'xxx', "ooo xxx ooo\nxxx ooo xxx\n"]
+          ensurePersistentSelection 'g m i w j . 2 j g m i p',  # Mark 2 inner-word and 1 inner-paragraph
+            length: 3
+            text: ['ooo', 'xxx', "ooo xxx ooo\nxxx ooo xxx\n"]
+
           ensure 'g U a r',
             text: """
             OOO xxx ooo
@@ -79,9 +91,11 @@

       it "select all instance of cursor word only within marked range", ->
         runs ->
-          keystroke('g m i p } } j .') # Mark 2 inner-word and 1 inner-paragraph
           paragraphText = "ooo xxx ooo\nxxx ooo xxx\n"
-          ensurePersistentSelection length: 2, text: [paragraphText, paragraphText]
+          ensurePersistentSelection 'g m i p } } j .', # Mark 2 inner-word and 1 inner-paragraph
+            length: 2
+            text: [paragraphText, paragraphText]
+
         waitsFor ->
           update.callCount is 1
         runs ->
@@ -103,23 +117,28 @@

     describe "clearPersistentSelections command", ->
       it "clear persistentSelections", ->
-        keystroke('g m i w')
-        ensurePersistentSelection length: 1, text: ['ooo']
+        ensurePersistentSelection 'g m i w',
+          length: 1
+          text: ['ooo']
+
         dispatch(editorElement, 'vim-mode-plus:clear-persistent-selection')
         expect(vimState.persistentSelection.hasMarkers()).toBe(false)

     describe "clearPersistentSelectionOnResetNormalMode", ->
       describe "default setting", ->
         it "it won't clear persistentSelection", ->
-          keystroke('g m i w')
-          ensurePersistentSelection length: 1, text: ['ooo']
+          ensurePersistentSelection 'g m i w',
+            length: 1
+            text: ['ooo']
+
           dispatch(editorElement, 'vim-mode-plus:reset-normal-mode')
           ensurePersistentSelection length: 1, text: ['ooo']

       describe "when enabled", ->
         it "it clear persistentSelection on reset-normal-mode", ->
           settings.set('clearPersistentSelectionOnResetNormalMode', true)
-          keystroke('g m i w')
-          ensurePersistentSelection length: 1, text: ['ooo']
+          ensurePersistentSelection 'g m i w',
+            length: 1
+            text: ['ooo']
           dispatch(editorElement, 'vim-mode-plus:reset-normal-mode')
           expect(vimState.persistentSelection.hasMarkers()).toBe(false)


:green_heart: Fix false negative

:green_heart: Fix false negative

--- spec/text-editor-presenter-spec.coffee
+++ spec/text-editor-presenter-spec.coffee
@@ -910,7 +910,7 @@
           expect(presenter.getState().content.scrollTop).toBe 13

         it "scrolls down automatically when the model is changed", ->
-          presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 20)
+          presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 10)

           editor.setText("")
           editor.insertNewline()
@@ -918,6 +918,9 @@

           editor.insertNewline()
           expect(presenter.getState().content.scrollTop).toBe(10)
+
+          editor.insertNewline()
+          expect(presenter.getState().content.scrollTop).toBe(20)

         it "never exceeds the computed scroll height minus the computed client height", ->
           didChangeScrollTopSpy = jasmine.createSpy()


Reseting some more module's cache to prevent tests going crazy

--- tests/unit/polvo.coffee
+++ tests/unit/polvo.coffee
@@ -57,6 +57,9 @@
       '../../lib/core/file'
       '../../lib/core/files'
       '../../lib/core/server'
+
+      '../../lib/scanner/resolve'
+      '../../lib/scanner/scan'
     ]

     for m in mods
@@ -223,7 +226,7 @@
     polvo = require '../../lib/polvo'
     server = polvo options, stdio

-  it 'should compile app with mock_NPM dependencies and index files', (done)->
+  it 'should compile app with NPM dependencies and index files', (done)->
     errors = outs = 0
     checker = /✓ public\/app\.js/


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/follow.coffee
+++ test/follow.coffee
@@ -17,7 +17,7 @@
   enemy.include(Follow)
   enemy.follow(player)

-  ok enemy.I.direction.equal(Point(1, 0)), 'enemy should head toward player with a direction Point(1, 0)'
+  ok enemy.I.velocity.equal(Point(1, 0)), 'enemy should head toward player with a direction Point(1, 0)'

   rightEnemy = GameObject
     x: 100


Follow mixin

Follow mixin

--- test/follow.coffee
+++ test/follow.coffee
@@ -15,6 +15,6 @@

   enemy.include(Follow)

-
+  ene

 module()


pre-released fix auto reveal broken

pre-released fix auto reveal broken

--- lib/provider/provider-base.coffee
+++ lib/provider/provider-base.coffee
@@ -51,7 +51,7 @@
       when 'always'
         true
       when 'on-input'
-        @options.query?.length
+        @query?.length

   initialize: ->
     # to override
@@ -102,10 +102,11 @@

     @bindEditor(editorToBind)
     @restoreEditorState = saveEditorState(@editor)
+    @query = @getInitialQuery(editor)

     @checkReady().then (ready) =>
       if ready
-        @ui = new Ui(this, query: @getInitialQuery(editor))
+        @ui = new Ui(this, {@query})
         @initialize()
         @ui.open(pending: @options.pending)


Improve prompt unit test harness.

Improve prompt unit test harness.

--- test/prompt.coffee
+++ test/prompt.coffee
@@ -5,7 +5,6 @@

 describe 'Prompt', ->
-  prompt = new Impromptu.Prompt
   sections =
     a:
       content: 'a'
@@ -20,16 +19,21 @@
       background: 'red'
       foreground: 'default'

+  makePrompt = (keys) ->
+    prompt = new Impromptu.Prompt
+    for key in keys
+      prompt.section key, sections[key]
+    prompt

   before (done) ->
     Impromptu.db.client().on 'connect', done

   it 'should add sections', ->
-    for key, section of sections
-      prompt.section key, section
+    prompt = makePrompt ['a', 'b', 'c']
     prompt._orderedSections.length.should.equal 3

   it 'should assemble a prompt', (done) ->
+    prompt = makePrompt ['a', 'b', 'c']
     prompt.build (err, result) ->
       a = '\x1B[44m\x1B[37m a \x1B[0m'
       b = '\x1B[42m\x1B[37m b \x1B[0m'


Cannot install via npm #1

Cannot install via npm #1

--- lib/tick/FrameTickProvider.coffee
+++ lib/tick/FrameTickProvider.coffee
@@ -91,12 +91,12 @@
   # dispatchTick: (timestamp = Date.now()) =>
   dispatchTick: (timestamp) =>
     @begin() if @showStats
-    @dispatch(timestamp)
-    # temp = @previousTime or timestamp
-    # @previousTime = timestamp
-    # frameTime = (timestamp - temp) * 0.001
-    # @dispatch(frameTime)
-    # requestAnimationFrame(@dispatchTick)
+    # @dispatch(timestamp)
+    temp = @previousTime or timestamp
+    @previousTime = timestamp
+    frameTime = (timestamp - temp) * 0.001
+    @dispatch(frameTime)
+    requestAnimationFrame(@dispatchTick)
     @end() if @showStats
     requestAnimationFrame(@dispatchTick)
     return # Void


Kandan.js refactor

Kandan.js refactor

Signed-off-by: Akash Manohar J <e4cf979cf717fd295f4e4edc427ee1aee78fa7dc@akash.im>

--- app/assets/javascripts/backbone/kandan.js.coffee
+++ app/assets/javascripts/backbone/kandan.js.coffee
@@ -36,47 +36,54 @@
     window.broadcaster = new Kandan.Broadcasters.FayeBroadcaster()
     window.broadcaster.subscribe "/channels/*" ##{channel.get('id')}

+
+  initChatbox: ()->
+    chatbox = new Kandan.Views.Chatbox()
+    $(".main-area").append(chatbox.render().el)
+
+
+  initTabs: ()->
+    $('#channels').tabs({
+      select: (event, ui)->
+        $(document).data('active_channel_id',
+          Kandan.Helpers.Channels.getChannelIdByTabIndex(ui.index))
+        Kandan.Data.Channels.runCallbacks('change')
+    })
+
+    $("#channels").tabs 'option', 'tabTemplate', '''
+

+        #{label}
+        x
+

+    '''
+
+  initChatArea: (channels)->
+    chatArea = new Kandan.Views.ChatArea({channels: channels})
+    $(".main-area").html(chatArea.render().el)
+
+  bindEventCallbacks: ()->
+    $(document).bind 'changeData', (element, name, value)->
+      Kandan.Data.ActiveUsers.runCallbacks('change') if name=="active_users"
+
   init: ->
     channels = new Kandan.Collections.Channels()
-    channels.fetch({success: ()=>
-      chat_area = new Kandan.Views.ChatArea({channels: channels})
-
+    channels.fetch({success: (channelsCollection)=>
       @initBroadcasterAndSubscribe()
-
-      $(document).bind 'changeData', (element, name, value)->
-        if(name=="active_users")
-          Kandan.Data.ActiveUsers.runCallbacks('change')
+      @bindEventCallbacks()

       active_users = new Kandan.Collections.ActiveUsers()
       active_users.fetch({
-        success: (collection)->
-          collection.add([$(document).data('current_user')]) if not Kandan.Helpers.ActiveUsers.collectionHasCurrentUser(collection)
+        success: (activeUsersCollection)=>

-          Kandan.Helpers.ActiveUsers.setFromCollection(collection)
+          if not Kandan.Helpers.ActiveUsers.collectionHasCurrentUser(activeUsersCollection)
+            activeUsersCollection.add([Kandan.Helpers.Users.currentUser()])

-          # NOTE init plugins so that modifiers are registered
+          Kandan.Helpers.ActiveUsers.setFromCollection(activeUsersCollection)
           Kandan.register_plugins()
           Kandan.Plugins.init_all()
-
-
-          $(".main-area").html(chat_area.render().el)
-          chatbox = new Kandan.Views.Chatbox()
-          $(".main-area").append(chatbox.render().el)
-          $('#channels').tabs({
-            select: (event, ui)->
-              $(document).data('active_channel_id',
-                Kandan.Helpers.Channels.getChannelIdByTabIndex(ui.index))
-              console.log "channel changed to index", ui.index
-              Kandan.Data.Channels.runCallbacks('change')
-          })
-
-          $("#channels").tabs 'option', 'tabTemplate', '''
-

-              #{label}
-              x
-

-          '''
-
+          @initChatArea(channelsCollection)
+          @initChatbox()
+          @initTabs()
           Kandan.Widgets.init_all()
       })
     })


Fix incorrect translation key

Fix incorrect translation key

--- app/assets/javascripts/admin/subscriptions/directives/confirm_order_edit.js.coffee
+++ app/assets/javascripts/admin/subscriptions/directives/confirm_order_edit.js.coffee
@@ -5,5 +5,5 @@
     element.bind "click", (event) ->
       unless scope.proxyOrder.order_id?
         event.preventDefault()
-        ConfirmDialog.open('error', t('admin.subscriptions.orders.confirm_edit'), {confirm: t('yes_i_am_sure')}).then ->
+        ConfirmDialog.open('error', t('admin.subscriptions.orders.confirm_edit'), {confirm: t('admin.subscriptions.yes_i_am_sure')}).then ->
           $window.open(attrs.href)


groups: permission grid / add role dialog, when canceled, will now cancel the loader of the Add Role button

--- client/landing/app/Applications/Groups.kdapplication/Views/permissionsmodal.coffee
+++ client/landing/app/Applications/Groups.kdapplication/Views/permissionsmodal.coffee
@@ -146,7 +146,7 @@
                 style     : "add-role-cancel modal-cancel"
                 cssClass  : 'add-role-cancel'
                 callback  : ()=>
-                  @buttons["Save"].hideLoader()
+                  @buttons["Add Role"].hideLoader()
                   addRoleDialog.hide()

           addRoleDialog.addSubView wrapper = new KDView


Disable codeshare shortcut for now

Disable codeshare shortcut for now

--- client/landing/app/MainApp/filetree/controllers/findercontextmenucontroller.coffee
+++ client/landing/app/MainApp/filetree/controllers/findercontextmenucontroller.coffee
@@ -145,9 +145,9 @@
         separator                 : yes
       Refresh                     :
         action                    : 'refresh'
-        separator                 : yes
-      'Create a CodeShare'        :
-        action                    : 'codeShare'
+      #   separator                 : yes
+      # 'Create a CodeShare'        :
+      #   action                    : 'codeShare'

     if fileView.expanded
       delete items.Expand


新建项目目录为atom默认项目目录

新建项目目录为atom默认项目目录

--- lib/utils/text-description.coffee
+++ lib/utils/text-description.coffee
@@ -16,7 +16,7 @@
   newProject: '新建项目'
   syncProject: '同步账号中的项目'
   registerUrl : ''
-  newProjectDefaultPath: 'D:/_Study/atom/package/newPackage'
+  newProjectDefaultPath: atom.config.get('core').projectHome
   appConfigPath: atom.project.getPaths()[0]+'\\config\\appconf.txt'
   moduleConfigPath: atom.project.getPaths()[0]+'\\config\\moduleconf.txt'
   configPath: atom.project.getPaths()[0]+'\\config'


Fixed percentage overflow on progress bar

--- app/coffee/modules/common/components.coffee
+++ app/coffee/modules/common/components.coffee
@@ -410,6 +410,8 @@
         element = angular.element($el)

         $scope.$watch $attrs.tgProgressBar, (percentage) ->
+            percentage = _.max([0 , percentage])
+            percentage = _.min([100, percentage])
             render($el, percentage)

         $scope.$on "$destroy", ->


Fix handlebars translate method bug

Fix handlebars translate method bug

--- app/coffeescripts/handlebars_helpers.coffee
+++ app/coffeescripts/handlebars_helpers.coffee
@@ -8,13 +8,14 @@
   'compiled/util/semanticDateRange'
   'compiled/util/dateSelect'
   'compiled/str/convertApiUserContent'
+  'compiled/str/underscore'
   'jquery.instructure_date_and_time'
   'jquery.instructure_misc_helpers'
   'jquery.instructure_misc_plugins'
-], (ENV, Handlebars, I18n, $, _, htmlEscape, semanticDateRange, dateSelect, convertApiUserContent) ->
+], (ENV, Handlebars, I18n, $, _, htmlEscape, semanticDateRange, dateSelect, convertApiUserContent, underscore) ->

   Handlebars.registerHelper name, fn for name, fn of {
-    t : (key, defaultValue, options) ->
+    t : (word, defaultValue, options) ->
       wrappers = {}
       options = options?.hash ? {}
       for key, value of options when key.match(/^w\d+$/)
@@ -22,7 +23,10 @@
         delete options[key]
       options.wrapper = wrappers if wrappers['*']
       options = $.extend(options, this) unless this instanceof String or typeof this is 'string'
-      I18n.scoped(options.scope).t(key, defaultValue, options)
+      format_scope = for s in options.scope.split('.')
+        underscore(s)
+      delete options.scope
+      I18n.scoped( format_scope.join('.') ).t(word, defaultValue, options)

     hiddenIf : (condition) -> " display:none; " if condition


JSUserDefaults update

JSUserDefaults update

--- JSKit/01_JSUserDefaults.coffee
+++ JSKit/01_JSUserDefaults.coffee
@@ -11,18 +11,20 @@
 		$.post "syslibs/library.php",
 			"mode": "setUserDefaults"
 			"forKey": forKey
-			"value": value
+			"value": JSON.stringify(value)

 	stringForKey:(forKey, action)->
 		$.post "syslibs/library.php",
 			"mode": "getUserDefaults"
 			"forKey": forKey
 		, (data)=>
-			action(data)
+			if (typeof(data) == "object")
+				data2 = JSON.parse(data)
+			else
+				data2 = data
+			action(data2)

 	removeObjectForKey:(forKey)->
 		$.post "syslibs/library.php",
 			"mode": "removeUserDefaults"
 			"forKey": forKey
-		, (data)=>
-			alert(data)


Fixed key press issues in Firefox.

Fixed key press issues in Firefox.

Key listener should be attached to document, not document.body.

--- media/js/blokjes.coffee
+++ media/js/blokjes.coffee
@@ -231,7 +231,7 @@
   .mouseleave (e) ->
     canvasMouseDown = false

-$(document.body).keypress (e) ->
+$(document).keypress (e) ->
   char = String.fromCharCode(e.which)
   if '0' <= char <= '9'
     setCurrentBlockType(parseInt(char))


fix fa

fix fa

--- lineman/config/application.coffee
+++ lineman/config/application.coffee
@@ -64,12 +64,7 @@
           expand: true
           cwd: 'vendor/bower_components/components-font-awesome/fonts'
           src: ['*.*']
-          dest: 'generated/fonts'
-        ,
-          expand: true
-          cwd: 'generated/'
-          src: ['*.html']
-          dest: 'dist/'
+          dest: 'dist/fonts'
         ]

   sass:


Use nicer exports syntax. [#89369394]

Use nicer exports syntax. [#89369394]

--- source/scripts/lib/current-backup.coffee
+++ source/scripts/lib/current-backup.coffee
@@ -16,16 +16,17 @@
     else if mtimeA > mtimeB
       -1

-exports.path = ->
-  if process.env.NW_ENV == 'cucumber'
-    home = fs.readFileSync "#{process.env.PWD}/tmp/.test_home"
-  else
-    home = process.env.HOME
+module.exports =
+  path: ->
+    if process.env.NW_ENV == 'cucumber'
+      home = fs.readFileSync "#{process.env.PWD}/tmp/.test_home"
+    else
+      home = process.env.HOME

-  backupDir = "#{home}/Library/Application Support/MobileSync/Backup"
+    backupDir = "#{home}/Library/Application Support/MobileSync/Backup"

-  # TODO: can we make this asynchronous?
-  backups = fs.readdirSync(backupDir).map (backup) -> [backupDir, backup].join '/'
-  backups = backups.filter (backup) ->
-    fs.readdirSync(backup).indexOf(smsDb) != -1
-  sortByMtime(backups)[0]+    # TODO: can we make this asynchronous?
+    backups = fs.readdirSync(backupDir).map (backup) -> [backupDir, backup].join '/'
+    backups = backups.filter (backup) ->
+      fs.readdirSync(backup).indexOf(smsDb) != -1
+    sortByMtime(backups)[0]


Refactored query parameter for groupings, since prefix was added. (#87, #88)

--- packages/custom/transparency/coffee/public/controllers/topEntriesController.coffee
+++ packages/custom/transparency/coffee/public/controllers/topEntriesController.coffee
@@ -135,11 +135,13 @@
     #navigate to some other page
     $scope.go = (d) ->
         window.scrollTo 0, 0
+        if d.data.isGrouping
+            groupName = d.data.key.slice(4) # removing the group prefix "(G) "
         $state.go 'showflow',
             {
                 name: d.data.key if not d.data.isGrouping
                 orgType: $scope.orgType
-                grouping: d.data.key if d.data.isGrouping
+                grouping: groupName if d.data.isGrouping
                 from: $scope.periods[$scope.slider.from/5].period
                 to: $scope.periods[$scope.slider.to/5].period
                 fedState: $scope.selectedFederalState.iso if $scope.selectedFederalState


Electron: Tray: handle{U,M}ount: use this.loadMachineMenu

--- elektron/src/trayicon.coffee
+++ elektron/src/trayicon.coffee
@@ -123,7 +123,7 @@

       if err
         @setMenu 'Mount failed', yes
-        setTimeout loadMachineMenu, 1000
+        setTimeout @loadMachineMenu, 1000
       else
         @loadMachineMenu()
         do handleOpen mountTo
@@ -139,7 +139,7 @@

       if err
         @setMenu 'Unmount failed', yes
-        setTimeout loadMachineMenu, 1000
+        setTimeout @loadMachineMenu, 1000
       else
         @loadMachineMenu()


chat: change handle threshold method to be stand alone

When it's only connected to handleFocus, the subclasses would suffer from this. This is a preparation for IDE.ChatPane

--- client/Social/Activity/views/privatemessage/pane.coffee
+++ client/Social/Activity/views/privatemessage/pane.coffee
@@ -430,7 +430,10 @@

     {wrapper} = @scrollView
     wrapper.on 'TopLazyLoadThresholdReached', KD.utils.throttle 200, @bound 'listPreviousReplies'
-    wrapper.on 'LazyLoadThresholdReached', KD.utils.throttle 200, @bound 'handleFocus'
+    wrapper.on 'LazyLoadThresholdReached', KD.utils.throttle 200, @bound 'handleThresholdReached'
+
+
+  handleThresholdReached: -> @handleFocus()

   editLastMessage: ->


Fix #5

Fix #5

--- coffeescript/app.coffee
+++ coffeescript/app.coffee
@@ -125,6 +125,19 @@
 			@timer = setTimeout ->
 				window.noted.save()
 			, 10000
+		.on "keydown", (e) ->
+			# Fixes Tabs
+			if e.keyCode is 9
+				myValue = "    "
+				startPos = @selectionStart
+				endPos = @selectionEnd
+				scrollTop = @scrollTop
+				@value = @value.substring(0, startPos) + myValue + @value.substring(endPos, @value.length)
+				@focus()
+				@selectionStart = startPos + myValue.length
+				@selectionEnd = startPos + myValue.length
+				@scrollTop = scrollTop
+				e.preventDefault()

 	getReadOnly: ->
 		@el.prop("disabled")


update user on single fact page (within profile) after loading.

--- core/app/backbone/controllers/profile_controller.coffee
+++ core/app/backbone/controllers/profile_controller.coffee
@@ -96,7 +96,8 @@
   withFact: (fact, params={})->
     @main.contentRegion.show new DiscussionView(model: fact, tab: params.tab)

-    username = fact.get('created_by').username
+    user = new User(fact.get('created_by'))
+    username = user.get('username')
     return_to_text = "#{ username.capitalize() }'s profile"

     title_view = new ExtendedFactTitleView(
@@ -107,6 +108,8 @@
     @main.titleRegion.show( title_view )

     @showChannelListing(fact.get('created_by').username)
+    user.fetch
+      success: => @showUserLarge(user)

   showChannelListing: (username)->
     changed = window.Channels.setUsernameAndRefresh(username)


Don’t rename .ino filenames in errors

Don’t rename .ino filenames in errors

--- lib/views/compile-errors-view.coffee
+++ lib/views/compile-errors-view.coffee
@@ -20,22 +20,6 @@
     splitFilename = filename.split path.sep
     path.join.apply this, splitFilename.slice(2)

-  fixInoFile: (filename) ->
-    fs ?= require 'fs-plus'
-    path ?= require 'path'
-    # this logic is borken...can't always assume we can infer the path
-    # if the file exist locally, assume it's good
-    # the view shouldn't be fixing up the filename paths...;-)
-    if fs.existsSync(filename)
-      return filename
-
-    rootPath = atom.project.getPaths()[0]
-    files = fs.listTreeSync rootPath
-    for file in files
-      if file.replace(rootPath + path.sep, '') == filename
-        return file.slice(rootPath.length + 1)
-    return filename.replace '.cpp', '.ino'
-
   show: =>
     SettingsHelper ?= require '../utils/settings-helper'

@@ -53,11 +37,10 @@
     $$ ->
       @li class: 'two-lines', =>
         @div class: 'primary-line', item.text
-        @div class: 'secondary-line', self.fixInoFile(item.filename) +
-                                      ":#{item.line}:#{item.column}"
+        @div class: 'secondary-line',  "#{item.filename}:#{item.line}:#{item.column}"

   confirmed: (item) ->
-    filename = @fixInoFile item.filename
+    filename = item.filename

     # Open file with error in editor
     opening = atom.workspace.open filename, { searchAllPanes: true }


Adds more supported expression types to the expression equality library

--- math/expression_equality_spec.coffee
+++ math/expression_equality_spec.coffee
@@ -89,3 +89,41 @@
           @comps.addition.build()
         )).toEqual true

+
+  describe "blank elements", ->
+    it "accepts vs a blank element", ->
+      expect(
+        @isEqual(
+          @comps.blank.build(),
+          @comps.blank.build(),
+        )).toEqual true
+
+    it "rejects against numbers", ->
+      expect(
+        @isEqual(
+          @comps.blank.build(),
+          @comps.number.build(value: 1)
+        )).toEqual false
+    it "accepts against expressions that contain a single blank element", ->
+      throw "TODO fill this in!"
+
+
+  describe "exponentiation", ->
+    it "accepts exponents with same base and power", ->
+      a = @exp_builder('^': [11, 22])
+      b = @exp_builder('^': [11, 22])
+      expect(a).toBeAnEqualExpressionTo b
+
+    it "rejects exponents with differing bases", ->
+      new_exp = @exp_builder('^': [11, 32])
+      expected = @exp_builder('^': [12, 32])
+      expect(new_exp).not.toBeAnEqualExpressionTo(expected)
+
+    it "rejects exponents different powers",->
+      new_exp = @exp_builder('^': [10, 32])
+      expected = @exp_builder('^': [10, 22])
+      expect(new_exp).not.toBeAnEqualExpressionTo(expected)
+
+
+
+


AAAAAA

AAAAAA

--- modules/danbooru.coffee
+++ modules/danbooru.coffee
@@ -85,7 +85,6 @@
       return msg.reply "Usage: ```#{@prefix}setWaifu <safebooru_tag>```" if not waifu
       # Do a dummy search
       qs = {
-        limit: 1
         tags: 'solo ' + waifu
       }
       safebooru.get '/posts.json', { json: true, qs }


Minor spec refactor with de-structuring.

--- tests/fakes.coffee
+++ tests/fakes.coffee
@@ -2,6 +2,8 @@
   'phaser'
   'underscore'
 ], (Phaser, _) ->
+
+  {Point} = Phaser

   # Phaser is written with interwoven dependencies, but does not provide test
   # helpers or fake classes. This custom faking isn't ideal, but a last resort.
@@ -26,8 +28,8 @@
   configurePlatformsWithDefaults: (platforms) ->
     platforms.minLedgeSize = 3
     platforms.maxLedgeSize = 5
-    platforms.minLedgeSpacing = new Phaser.Point 4, 2
-    platforms.maxLedgeSpacing = new Phaser.Point 8, 4
+    platforms.minLedgeSpacing = new Point 4, 2
+    platforms.maxLedgeSpacing = new Point 8, 4
     platforms.ledgeThickness = 2
     platforms.tileWidth = platforms.tileHeight = 32

@@ -47,12 +49,12 @@
   createPlayerProps: (player) ->
     sprite:
       body:
-        drag: new Phaser.Point(), setSize: jasmine.createSpy 'setSize'
-        velocity: new Phaser.Point(), acceleration: new Phaser.Point()
         onFloor: -> no
+        drag: new Point(), setSize: jasmine.createSpy 'setSize'
+        velocity: new Point(), acceleration: new Point()
       game:
         time: { create: -> new FakeTimer() }
-      scale: new Phaser.Point()
+      scale: new Point()

     animations:
       play: jasmine.createSpy('play').and.callFake (name) ->
@@ -65,4 +67,4 @@
       _.mapObject { left: {}, right: {}, up: {}, down: {} }, (key) ->
         key.isUp = key.isDown = no; key

-    gravity: new Phaser.Point()
+    gravity: new Point()


add tooltip to active session

add tooltip to active session

--- client/account/lib/accountsessionlistitem.coffee
+++ client/account/lib/accountsessionlistitem.coffee
@@ -50,10 +50,16 @@

     lastAccess = lastLoginDate or lastAccess

+    @session = new kd.CustomHTMLView
+      tagName: 'p'
+      cssClass: "group-name#{activeSession}"
+      partial:"#{group}"
+      tooltip: { title : 'Active Session!', placement: 'left' }  if activeSession
+
     """

-
#{group}

+        {{> @session}}

Last access: #{timeago lastAccess}

       {div.delete-button{> @deleteButton }}


Disable bounce animation when overdrag is false

--- framer/LayerDraggable.coffee
+++ framer/LayerDraggable.coffee
@@ -375,7 +375,7 @@
 		updatePoint = {}

 		if @constraints
-			if @bounce
+			if @bounce and @overdrag
 				updatePoint[axis] = state.x
 			else
 				{minX, maxX, minY, maxY} = @_calculateConstraints(@_constraints)


Fix zero velocity animation bug

Fix zero velocity animation bug

--- framer/LayerDraggable.coffee
+++ framer/LayerDraggable.coffee
@@ -456,6 +456,7 @@
 	_startSimulation: ->

 		return unless @momentum or @bounce
+		return unless @isDragging

 		# If overdrag is disabled, we need to not have a bounce animation
 		# when the cursor is outside of the dragging bounds for an axis.
@@ -471,10 +472,6 @@

 		velocityX = velocity.x * @momentumVelocityMultiplier * @speedX * (1 / @_screenScale.x) * @layer.scaleX * @layer.scale
 		velocityY = velocity.y * @momentumVelocityMultiplier * @speedY * (1 / @_screenScale.y) * @layer.scaleY * @layer.scale
-
-		# Don't start a simulation if we're below velocity threshold
-		if Math.abs(velocityX) < @momentumOptions.tolerance and Math.abs(velocityY) < @momentumOptions.tolerance
-			return

 		@_setupSimulation()
 		@_isAnimating = true


Fix #402 - no progress bar for files with an unknown size

--- src/bin/cli.coffee
+++ src/bin/cli.coffee
@@ -46,15 +46,18 @@
             what = if info.way is 'up' then 'Uploading' else 'Downloading'
             filename = path.basename info.path
             format = "#{what} #{filename} [:bar] :percent :etas"
-            options =
-                total: info.size
-                width: 30
-            bar = new Progress format, options
-            app.events.on info.eventName, (data) ->
-                if data.finished
-                    app.events.removeAllListeners info.eventName
-                else
-                    bar.tick data.length
+            if info.size
+                options =
+                    total: info.size
+                    width: 30
+                bar = new Progress format, options
+                app.events.on info.eventName, (data) ->
+                    if data.finished
+                        app.events.removeAllListeners info.eventName
+                    else
+                        bar.tick data.length
+            else
+                log.log "#{what} #{filename} (unknown size)"
         app.synchronize mode, (err) ->
             process.exit 1 if err
     else


Added test for returning error when top-level field isn't a string


Don't wait for iexpress

Don't wait for iexpress

--- webpack/dist/sfx.coffee
+++ webpack/dist/sfx.coffee
@@ -100,7 +100,10 @@
     out.write "#{f}=\n"
   out.end()

-  spawn 'iexpress', ['/N', sed]
+  spawn 'iexpress', ['/N', sed],
+    detached: true
+    stdio: 'ignore'
   .on 'error', (e)-> throw e
+  .unref()

   console.log 'SFX created:', exe


Use "getSubViews" method instead of "subViews" property

--- client/ide/lib/workspace/idelayoutmanager.coffee
+++ client/ide/lib/workspace/idelayoutmanager.coffee
@@ -24,7 +24,7 @@

     workspaceView = @getDelegate().workspace.getView()
     baseSplitView = workspaceView.layout.getSplitViewByName 'BaseSplit'
-    splitViews    = baseSplitView.panels.last.subViews.first.subViews.first
+    splitViews    = baseSplitView.panels.last.getSubViews().first.getSubViews().first

     if splitViews instanceof IDEView
       @createParentSplitViews splitViews


better guidelines in bitcoinclassic header

Former-commit-id: e5050d0ce0f6b701126c3190d36c3af1c5749335 [formerly 8d8013a67ff18d47fc9f4c98bb37af1c94e6193f] [formerly b0a86f4e8d7fbc4b0a2570f021f746044c39792a [formerly b9f639071c6e06670dafa9e7b6df26bd20e48b6c]] [formerly cc12b92fc01cb8dcc7d903b168d9c0f6f70bbbac [formerly 0e48c56dcdc0e24dfbf3609627990d1696aba0b1] [formerly ae74873955997ef8753ca95f90759759d6fa0d10 [formerly ae74873955997ef8753ca95f90759759d6fa0d10 [formerly 9d20892cd883d28a9a6a185787b8ddcfd2e5b01e]]]]
Former-commit-id: cd25ca8424a8948704f26e043c8d86ce83ee2249 [formerly 90a0a7eec0d4b3d53fae253c2157a5f484fde8fb] [formerly d00a2ddaf990ba8a1ad243b1dc662d22f7f176d6 [formerly fae0706b6e2d961b0bb284dea1e877e5af46bcc8]]
Former-commit-id: 6ce6928909a215644f053196566dc22acbeb3312 [formerly 6cdf9039eb3a180eeacee8eb05178eb4ad1f2310]
Former-commit-id: bae5b980bc0728f57840d07820043c9fe773f7c1
Former-commit-id: 78b0ab31f4c9df35cec7278b25bfd4b9058a2e85

--- @client/customizations.coffee
+++ @client/customizations.coffee
@@ -1877,9 +1877,9 @@
         style:
           position: 'relative'
           backgroundColor: 'white'
-          height: 63
-          borderBottom: '1px solid #ddd'
-          boxShadow: '0 1px 2px rgba(0,0,0,.1)'
+          #height: 63
+          # borderBottom: '1px solid #ddd'
+          # boxShadow: '0 1px 2px rgba(0,0,0,.1)'

         onMouseEnter: => @local.hover=true;  save(@local)
         onMouseLeave: => @local.hover=false; save(@local)
@@ -1920,18 +1920,35 @@

                 src: asset('bitcoin/bitcoinclassic.png')

-            A
-              href: 'https://www.reddit.com/r/Bitcoin_Classic/comments/40u3ws/considerit_voting_guide/'
-              target: '_blank'
+            BR null
+            SPAN
               style:
-                textDecoration: 'underline'
-                color: '#8d8d8d'
-                marginLeft: 15
-                fontSize: 14
+                color: 'white'
+                marginLeft: 69
                 position: 'relative'
+                marginBottom: 10
                 top: -4
-
-              "Guide to participation"
+                backgroundColor: '#F69332'
+                padding: '3px 6px'
+                fontSize: 18
+
+
+              "Please discuss proposals on "
+              A
+                href: "http://invite.bitcoinclassic.com/"
+                target: '_blank'
+                style:
+                  textDecoration: 'underline'
+
+                "Slack"
+              " before posting here. "
+              A
+                href: 'https://www.reddit.com/r/Bitcoin_Classic/comments/40u3ws/considerit_voting_guide/'
+                target: '_blank'
+                style:
+                  textDecoration: 'underline'
+
+                "Other guidelines"

         ProfileMenu()


fix(search-playground): Search bar React conversion issue

--- internal_packages/search-playground/lib/search-bar.cjsx
+++ internal_packages/search-playground/lib/search-bar.cjsx
@@ -4,6 +4,7 @@
 {Menu, RetinaImg} = require 'ui-components'
 SearchSuggestionStore = require './search-suggestion-store'
 _ = require 'underscore-plus'
+

 class SearchBar extends React.Component
   @displayName = 'SearchBar'
@@ -78,8 +79,7 @@
     </div>

   _onFocusSearch: =>
-    return unless @isMounted()
-    @refs.searchInput.findDOMNode().focus()
+    React.findDOMNode(@refs.searchInput).focus()

   _containerClasses: =>
     classNames
@@ -125,7 +125,7 @@

   _clearAndBlur: =>
     @_onClearSearch()
-    @refs.searchInput?.findDOMNode().blur()
+    React.findDOMNode(@refs.searchInput)?.blur()

   _onFocus: =>
     @setState focused: true
@@ -136,8 +136,7 @@
     # handle the touch event, then dismiss the menu.
     setTimeout =>
       Actions.searchBlurred()
-      if @isMounted()
-        @setState focused: false
+      @setState(focused: false)
     , 150

   _doSearch: =>


For Node 0.4, specs should still use assert.ok instead of assert as a function

--- spec/browser_spec.coffee
+++ spec/browser_spec.coffee
@@ -47,7 +47,7 @@
             browser = new Browser
             browser.visit "http://localhost:3003/browser/scripted", @callback
         "should not include an error": ->
-          assert true
+          assert.ok true
         "should pass browser to callback": (_, browser, status, errors)->
           assert.instanceOf browser, Browser
         "should pass status code to callback": (_, browser, status, errors)->
@@ -63,7 +63,7 @@
             browser = new Browser
             browser.visit "http://localhost:3003/browser/missing", @callback
         "should not include an error": ->
-          assert true
+          assert.ok true
         "should pass browser to callback": (_, browser, status, errors)->
           assert.instanceOf browser, Browser
         "should pass status code to callback": (_, browser, status, errors)->


make a few more changes to y-axis tick intervals; clean up code

--- app/lib/canvas-graph.coffee
+++ app/lib/canvas-graph.coffee
@@ -224,28 +224,33 @@
         @ctx.fillText( (tick + @originalMin).toFixed(2), @toCanvasXCoord(tick), 0 + textSpacing+10 )

   drawYTickMarks: (yMin, yMax, nIntervals) ->
+
+    tickMinorLength = 5
+    tickMajorLength = 10
+    tickWidth = 1
+    tickColor = '#323232' #rgba(200,20,20,1)' #'#323232'
+    textColor = '#323232' #'rgba(200,20,20,1)' #'#323232'
+    textSpacing = 15
+
     # console.log 'yLimits: [',yMin,',',yMax,']'
     # generate intervals
     yTicks = []
-    nIntervals = 10
+    nIntervals = 20
+
+    majorTickInterval = 2
+    minorTickInterval = 1
+    textInterval = 2
+
     yStep = 1/nIntervals
     i = 0
     yVal = yMin
     while yVal <= yMax
       for j in [0...nIntervals]
         tick = yVal + j*yStep;
-        # console.log 'tick: ', tick, ' -> ', @toCanvasYCoord(tick)
         unless tick > yMax
           yTicks.push tick
       i++
       yVal++
-
-    tickMinorLength = 5
-    tickMajorLength = 10
-    tickWidth = 1
-    tickColor = '#323232' #rgba(200,20,20,1)' #'#323232'
-    textColor = '#323232' #'rgba(200,20,20,1)' #'#323232'
-    textSpacing = 15

     # REQUIRED FOR MEAN NORMALIZATION
     # yMean = @mean(@data.y)
@@ -271,86 +276,21 @@
       tickPos = @toCanvasYCoord(tick)     # transform to canvas coordinate
       tickPos = -tickPos + @canvas.height # flip y-axis

-      # draw ticks
+      # draw axis
+      @ctx.font = '10pt Arial'
+      @ctx.textAlign = 'center'
+      @ctx.fillStyle = textColor
       @ctx.beginPath()
       @ctx.moveTo( 0, tickPos )
-      if i % nIntervals is 0
+      if i % majorTickInterval is 0
         @ctx.lineTo( tickMajorLength, tickPos ) # major tick
+        @ctx.fillText( tick.toFixed(2), 0+textSpacing+10, tickPos+5 )
+
       else
         @ctx.lineTo( tickMinorLength, tickPos ) # minor tick
       @ctx.lineWidth = tickWidth
       @ctx.strokeStyle = tickColor
       @ctx.stroke()
-
-      # draw numbers
-      # if i % nIntervals is 0
-      @ctx.font = '10pt Arial'
-      @ctx.textAlign = 'center'
-      @ctx.fillStyle = textColor
-      # @ctx.fillText( tick.toFixed(2), 0+textSpacing+10, -(@toCanvasYCoord(tick)+5)+@canvas.height )
-      # flip about y-axis
-      # tick = tick/yMean # FOR MEAN NORMALIZATION (NOT CORRECT YET!)
-      @ctx.fillText( tick.toFixed(2), 0+textSpacing+10, tickPos+5 )
-
-    # # X-AXIS
-    # # display 'days' label
-    # @ctx.font = '10pt Arial'
-    # @ctx.textAlign = 'left'
-    # @ctx.fillStyle = textColor
-    # @ctx.fillText( 'DAYS', 10, @canvas.height - textSpacing )
-    # for i in [0...@dataLength]
-    #   if i % 1 is 0 and i isnt 0
-    #     # top
-    #     tick_x = ((+i - xMin) / (xMax - xMin)) * @canvas.width
-    #     @ctx.beginPath()
-    #     @ctx.moveTo( tick_x, 0 )
-    #     @ctx.lineTo( tick_x, tickMinorLength )
-    #     @ctx.lineWidth = tickWidth
-    #     @ctx.strokeStyle = tickColor
-    #     @ctx.stroke()
-
-    #     # bottom tickmarks
-    #     @ctx.beginPath()
-    #     @ctx.moveTo( tick_x, @canvas.height )
-    #     @ctx.lineTo( tick_x, @canvas.height - tickMinorLength )
-    #     @ctx.lineWidth = tickWidth
-    #     @ctx.strokeStyle = tickColor
-    #     @ctx.stroke()
-
-    #   if i % 2 is 0 and i isnt 0
-    #     # tick_x = ((+i - xMin) / (xMax - xMin)) * @canvas.width
-
-    #     # bottom lines
-    #     @ctx.beginPath()
-    #     @ctx.moveTo( tick_x, @canvas.height )
-    #     @ctx.lineTo( tick_x, @canvas.height-tickMajorLength )
-    #     @ctx.lineWidth = tickWidth
-    #     @ctx.strokeStyle = tickColor
-    #     @ctx.stroke()
-
-    #     #bottom numbers
-    #     @ctx.font = '10pt Arial'
-    #     @ctx.textAlign = 'center'
-    #     @ctx.fillStyle = textColor
-    #     @ctx.fillText( @toDataXCoord(tick_x).toFixed(), tick_x, @canvas.height - textSpacing )
-
-    #   if i % 4 is 0 and i isnt 0
-    #     tick_x = ((+i - xMin) / (xMax - xMin)) * @canvas.width
-
-    #     # top numbers
-    #     @ctx.font = '10pt Arial'
-    #     @ctx.textAlign = 'center'
-    #     @ctx.fillStyle = textColor
-    #     x_value = @toDataXCoord(tick_x)+Math.round(@originalMin)
-    #     @ctx.fillText( x_value, tick_x, tickMajorLength+textSpacing )
-
-    #     # top lines
-    #     @ctx.beginPath()
-    #     @ctx.moveTo( tick_x, 0 )
-    #     @ctx.lineTo( tick_x, tickMajorLength )
-    #     @ctx.lineWidth = tickWidth
-    #     @ctx.strokeStyle = tickColor
-    #     @ctx.stroke()

   zoomInTo: (wMin, wMax) ->
     [cMin, cMax] = [@xMin, @xMax]


Add Geordi integration and basic interventions support.

--- app/lib/intervention.coffee
+++ app/lib/intervention.coffee
@@ -27,7 +27,7 @@
           if res.length > 0
             nextIntervention = res[0]
             logInterventionDetected nextIntervention
-            console.log intervention
+            console.log nextIntervention
         error    : (xhr, status, err) ->
           Analytics.logError {
             userID: User.current?.zooniverse_id


:arrow_up: Upgrade helper specs to match latest module

--- spec/helpers-spec.coffee
+++ spec/helpers-spec.coffee
@@ -3,9 +3,9 @@
   beforeEach ->
     atom.notifications.clear()

-  describe '::error', ->
+  describe '::showError', ->
     it 'adds an error notification', ->
-      helpers.error(new Error())
+      helpers.showError(new Error())
       expect(atom.notifications.getNotifications().length).toBe(1)

   describe '::shouldTriggerLinter', ->


install-spec: Delete "configurable python" tests

No longer working with new `node-gyp`;
Deleting rather than re-writing.

--- spec/install-spec.coffee
+++ spec/install-spec.coffee
@@ -566,47 +566,3 @@
           if process.platform isnt 'win32'
             makefileContent = fs.readFileSync(path.join(testModuleDirectory, 'build', 'Makefile'), {encoding: 'utf-8'})
             expect(makefileContent).toMatch('node_modules/with\\ a\\ space/addon.gypi')
-
-    if process.platform isnt 'win32'
-      # Only applicable on Linux and macOS
-      describe "configurable Python binaries", ->
-        [originalPython, originalNpmConfigPython] = []
-
-        beforeEach ->
-          originalPython = process.env.PYTHON
-          originalNpmConfigPython = process.env.npm_config_python
-          delete process.env.PYTHON
-          delete process.env.npm_config_python
-
-        afterEach ->
-          process.env.PYTHON = originalPython
-          process.env.npm_config_python = originalNpmConfigPython
-
-        it 'respects ${PYTHON} if set', ->
-          process.env.PYTHON = path.join __dirname, 'fixtures', 'fake-python-1.sh'
-
-          callback = jasmine.createSpy('callback')
-          apm.run(['install', 'native-package'], callback)
-
-          waitsFor 'waiting for install to fail', 600000, ->
-            callback.callCount is 1
-
-          runs ->
-            errorText = callback.mostRecentCall.args[0]
-            expect(errorText).not.toBeNull()
-            expect(errorText).toMatch('fake-python-1 called')
-
-        it 'respects ${npm_config_python} if set', ->
-          process.env.npm_config_python = path.join __dirname, 'fixtures', 'fake-python-2.sh'
-          process.env.PYTHON = path.join __dirname, 'fixtures', 'fake-python-1.sh'
-
-          callback = jasmine.createSpy('callback')
-          apm.run(['install', 'native-package'], callback)
-
-          waitsFor 'waiting for install to fail', 600000, ->
-            callback.callCount is 1
-
-          runs ->
-            errorText = callback.mostRecentCall.args[0]
-            expect(errorText).not.toBeNull()
-            expect(errorText).toMatch('fake-python-2 called')


Add specs for SSL and anonymize IP param

--- spec/metrics-spec.coffee
+++ spec/metrics-spec.coffee
@@ -40,6 +40,28 @@
     runs ->
       [url] = Reporter.request.calls[0].args
       expect(url).toBeDefined()
+
+  it "reports over SSL", ->
+    waitsForPromise ->
+      atom.packages.activatePackage('metrics')
+
+    waitsFor ->
+      Reporter.request.callCount > 0
+
+    runs ->
+      [url] = Reporter.request.mostRecentCall.args
+      expect(url).toMatch('^https:\/\/ssl.google-analytics.com\/collect\?')
+
+  it "specifies anonymization", ->
+    waitsForPromise ->
+      atom.packages.activatePackage('metrics')
+
+    waitsFor ->
+      Reporter.request.callCount > 0
+
+    runs ->
+      [url] = Reporter.request.mostRecentCall.args
+      expect(url).toContain('&aip=1&')

   describe "reporting release channel", ->
     beforeEach ->


Use CWD as a default directory.

Use CWD as a default directory.

Use CWD as a default directory when watching / building projects.

--- src/command.coffee
+++ src/command.coffee
@@ -71,6 +71,7 @@
           help: "application path"
           metavar: "APP_PATH"
           full: "app_path"
+          default: "."
         buildPath:
           abbr: "o"
           help: "build path"
@@ -91,6 +92,7 @@
           help: "application path"
           metavar: "APP_PATH"
           full: "app_path"
+          default: "."
         buildPath:
           abbr: "o"
           help: "build path"


Teambuilder: Attempt to fix move selection bug

--- client/app/js/views/teambuilder_view.coffee
+++ client/app/js/views/teambuilder_view.coffee
@@ -36,6 +36,7 @@
     'keydown .selected_moves input': 'keydownMoves'
     'blur .selected_moves input': 'blurMoves'
     'click .table-moves tbody tr': 'clickMoveName'
+    'mousedown .table-moves': 'preventBlurMoves'
     'click .move-button': 'clickSelectedMove'

   initialize: (attributes) =>
@@ -269,8 +270,21 @@
     $moves.first().addClass('active')
     $table.removeClass('hidden')

+  # Prevents the blurMoves event from activating for the duration of
+  # the remaining javascript events. This allows the click event to not fire
+  # the blur event.
+  preventBlurMoves: (e) =>
+    @_preventBlur = true
+    _.defer =>
+      @_preventBlur = false
+
   blurMoves: (e) =>
     $input = $(e.currentTarget)
+    if @_preventBlur
+      $input.focus()
+      e.preventDefault()
+      return
+
     $selectedMove = @$selectedMove()
     moveName = $selectedMove.data('move-id')

@@ -293,6 +307,7 @@
     @insertMove($input, moveName)

   insertMove: ($input, moveName) =>
+    @preventBlurMoves()
     return  if !@buttonify($input, moveName)
     $moves = @getActivePokemonView().find('.selected_moves')
     $moves.find('input').first().focus()


fixme seems to be fixed

fixme seems to be fixed

--- spec/motions-spec.coffee
+++ spec/motions-spec.coffee
@@ -580,9 +580,7 @@
         expect(editor.getText()).toBe "  ab\n\n1234567890"
         expect(editor.getCursorScreenPosition()).toEqual [0, 3]

-  # FIXME: this doesn't work as we can't determine if this is a motion
-  # or part of a repeat prefix.
-  xdescribe "the 0 keybinding", ->
+  describe "the 0 keybinding", ->
     beforeEach ->
       editor.setText("  a\n")
       editor.setCursorScreenPosition([0, 2])


Fix test that was throwing a hidden failuire

--- client/test/src/views/bar_chart_view.coffee
+++ client/test/src/views/bar_chart_view.coffee
@@ -36,22 +36,25 @@
   indicator = Factory.indicator(
     indicatorDefinition:
       xAxis: 'hat'
-      xAxis: 'boat'
+      yAxis: 'boat'
   )
   visualisation = Factory.visualisation(
     indicator: indicator
   )

+  barChartRenderStub = sinon.stub(Backbone.Views.BarChartView::, 'render', ->)
+
   barChartStub = sinon.stub(nrtViz, 'barChart', (options) ->
     try
       assert.strictEqual options.xKey, indicator.get('indicatorDefinition').xAxis
       assert.strictEqual options.yKey, indicator.get('indicatorDefinition').yAxis
+
+      done()
     catch e
       done(e)
     finally
       barChartStub.restore()
-
-    done()
+      barChartRenderStub.restore()
   )

   view = new Backbone.Views.BarChartView(visualisation: visualisation)


Binding @on_resize call to view scope. (closes #34)

--- www/src/theoricus/mvc/view.coffee
+++ www/src/theoricus/mvc/view.coffee
@@ -71,8 +71,8 @@
       @in()

       if @on_resize?
-        $( window ).unbind 'resize', @on_resize
-        $( window ).bind   'resize', @on_resize
+        $( window ).unbind 'resize', => do @on_resize
+        $( window ).bind   'resize', => do @on_resize
         @on_resize()


change default text color gray

change default text color gray

--- src/primitives/types/text/label.coffee
+++ src/primitives/types/text/label.coffee
@@ -4,7 +4,7 @@
 class Label extends Primitive
   @traits = ['node', 'bind', 'object', 'visible', 'style', 'label', 'attach', 'geometry', 'position']
   @defaults =
-    color: '#000000'
+    color: '#808080'

   make: () ->
     super


mailchimp-subscribe: Removed encoding: it's causing errors now

--- src/scripts/mailchimp-subscribe.coffee
+++ src/scripts/mailchimp-subscribe.coffee
@@ -37,8 +37,7 @@

   api.listSubscribe
     id:            listId
-    # Hack until this PR lands: https://github.com/gomfunkel/node-mailchimp/pull/21
-    email_address: encodeURIComponent(emailAddress)
+    email_address: emailAddress
     double_optin:  false
   , (error, data) ->
     if error


Preserve arrays

Preserve arrays

--- Settings.coffee
+++ Settings.coffee
@@ -4,7 +4,7 @@

 merge = (settings, defaults) ->
 	for key, value of settings
-		if typeof(value) == "object"
+		if typeof(value) == "object" and value not instanceof Array
 			defaults[key] = merge(settings[key], defaults[key] or {})
 		else
 			defaults[key] = value


Fixed a bug where sometimes thang avatar views wouldn't render the portrait, because 'loading' wouldn't be set to false properly.

--- app/models/CocoModel.coffee
+++ app/models/CocoModel.coffee
@@ -16,7 +16,7 @@
       console.error("#{@} needs a className set.")
     @markToRevert()
     @addSchemaDefaults()
-    @once 'sync', @onLoaded, @
+    @on 'sync', @onLoaded, @
     @on 'error', @onError, @
     @saveBackup = _.debounce(@saveBackup, 500)


_.isKindOf now works with javascript primary types (Function, Array, Number, String. Object)

--- app/src/utils/object.coffee
+++ app/src/utils/object.coffee
@@ -6,6 +6,12 @@
   # @param [Function] The class to test
   # @return [Boolean] true if the object is a subtype of class otherwise false
   isKindOf: (object, clazz) ->
+    switch clazz
+      when String then return _.isString(object)
+      when Array then return _.isArray(object)
+      when Function then return _.isFunction(object)
+      when Number then return _.isNumber(object)
+      when Object then return _.isObject(object)
     while clazz?.constructor?
       return yes if object.constructor == clazz
       clazz = clazz.constructor.__super__


Saving progress

Saving progress

--- src/components/keyboard_shortcuts.coffee
+++ src/components/keyboard_shortcuts.coffee
@@ -7,6 +7,7 @@

 KeyboardShortcuts = React.createClass
   displayName: 'KeyboardShortcuts'
+  pointKeys: {5: 15, 6: 16, 7: 17, 8: 18, 9: 19, 0: 20, 1: 25}

   componentDidMount: ->
     key 'space', => @props.nextRound() and off
@@ -14,12 +15,27 @@
     key 'command+x', => @props.undoRound() and off
     key 'command+enter', => FinishGame.submitResults(@props.finishGameState) and off

-#    pointKeys = {5: 15, 6: 16, 7: 17, 8: 18, 9: 19, 0: 20, 1: 25}
-#    for num, points of pointKeys
-#      key "#{num}", => @props.score(points, 1) and off
-#      key "command+#{num}", => @props.score(points, 2) and off
-#      unless points is 25
-#        key "command+shift+#{num}", => @props.score(points, 3) and off
+    for num, points of @pointKeys
+      key "#{num}", @scoreKey
+      key "command+#{num}", @scoreKey
+      key("command+shift+#{num}", @scoreKey) unless points is 25
+
+  scoreKey: (e) ->
+    console.log e
+    console.log @props.scoreboard
+    if @pointKeys[e.key]
+      points = @pointKeys[e.key]
+      if @isTriple e
+        @props.score(points, 3)
+      else if @isDouble e
+        @props.score(points, 2)
+      else
+        @props.score(points, 2)
+      return off
+    on
+
+  isTriple: (e) -> e.metaKey and e.shiftKey
+  isDouble: (e) -> e.metaKey

   render: ->
     div {id: 'shortcuts'},


Add callback to creator.copy to allow chmodding bin/hubot

--- src/creator.coffee
+++ src/creator.coffee
@@ -26,10 +26,12 @@
   # to   - A String destination file to write to.
   #
   # Returns nothing.
-  copy: (from, to) ->
+  copy: (from, to, callback) ->
     Fs.readFile from, "utf8", (err, data) ->
       console.log "Copying #{Path.resolve(from)} -> #{Path.resolve(to)}"
       Fs.writeFileSync to, data, "utf8"
+
+      callback(err, to) if callback?

   # Copy the default scripts hubot ships with to the scripts folder
   # This allows people to easily remove scripts hubot defaults to if
@@ -75,7 +77,7 @@
     ]

     for bin in bins
-      @copy "#{@templateDir}/#{bin}", "#{@path}/#{bin}"
-      Fs.chmodSync "#{@path}/#{bin}", 0o755
+      @copy "#{@templateDir}/#{bin}", "#{@path}/#{bin}", (err, binPath) =>
+        Fs.chmodSync binPath, 0o755

 module.exports = Creator


no need to set el width

no need to set el width

--- components/artwork_columns/test/view.coffee
+++ components/artwork_columns/test/view.coffee
@@ -35,6 +35,7 @@
       new Artwork fabricate 'artwork'
       new Artwork fabricate 'artwork'
     ])
+
     @view = new ArtworkColumnsView
       el: $('body')
       collection: @artworks
@@ -57,9 +58,13 @@

   describe '#_columnWidth',  ->

+    beforeEach ->
+      sinon.stub($.fn, 'width').returns 1280
+
+    afterEach ->
+      $.fn.width.restore()
+
     it 'total width of columns should be less than container width', ->
-      @view.$el.width 1000
-
       totalWidth = (@view._columnWidth() * @view.numberOfColumns) + ((@view.numberOfColumns - 1) * @view.gutterWidth)
       totalWidth.should.be.below @view.$el.width()


test Model.set with to consecutive "set" calls

--- test/Bacon.JQuery.Bindings.Spec.coffee
+++ test/Bacon.JQuery.Bindings.Spec.coffee
@@ -16,7 +16,8 @@
     b = bjb.Model()
     values = collect(b)
     b.set("wat")
-    expect(values).to.deep.equal(["wat"])
+    b.set("asdf")
+    expect(values).to.deep.equal(["wat", "asdf"])

 describe "Model initial value", ->
   it "is sent", ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/emitter.coffee
+++ src/emitter.coffee
@@ -4,3 +4,4 @@

   self.include Emitterable

+  return self


Fixing mouse selection for Firefox

Fixing mouse selection for Firefox

--- src/js/Main.coffee
+++ src/js/Main.coffee
@@ -12,19 +12,22 @@
     @renderer.drawMap()
     console.timeEnd "rendering" if DEBUG

+    # TODO: Fails to reset the cursor if mousemove doesn go over
+    #       the canvas, move this to the body
     $('#main-canvas').bind 'mousemove', (event) =>
-      blockAtMouse = @renderer.blockAtScreenCoordinates event.layerX, event.layerY
-      if blockAtMouse
-        if $.browser.webkit
-          cursor = "-webkit-grab"
-        else if $.browser.mozilla
-          cursor = "-moz-grab"
-        $('body').css "cursor", cursor
+      x = event.offsetX || event.layerX - $(event.target).position().left
+      y = event.offsetY || event.layerY - $(event.target).position().top
+      if @renderer.blockAtScreenCoordinates x, y
+        cursor = if $.browser.webkit then '-webkit-grab' else \
+                 if $.browser.mozilla then '-moz-grab'
       else
-        $('body').css "cursor", "auto"
+        cursor = 'auto'
+      $('body').css 'cursor', cursor

     $('#main-canvas').bind 'click', (event) =>
-      @map.selectBlock @renderer.blockAtScreenCoordinates event.layerX, event.layerY
+      x = event.offsetX || event.layerX - $(event.target).position().left
+      y = event.offsetY || event.layerY - $(event.target).position().top
+      @map.selectBlock @renderer.blockAtScreenCoordinates x, y

     renderingLoop = =>
       @renderer.drawMap()


Clean up role as well

Clean up role as well

--- src/library.coffee
+++ src/library.coffee
@@ -110,6 +110,7 @@
   return component unless component?.definition
   delete component.definition.extra
   delete component.definition.id
+  delete component.definition.role
   for port in component.definition.inports
     delete port.queue
   for port in component.definition.outports


Metered changing max attribute

Metered changing max attribute

--- src/metered.coffee
+++ src/metered.coffee
@@ -21,7 +21,7 @@
     someOtherObject.meter 'turbo'
     # => Sets up a turbo meter that will be drawn during the someOtherObject overlay event.
     # Since neither turbo or turboMax were provided, they are both set to 100.
-
+

 Metered module
 @name Metered


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -96,7 +96,7 @@
           width: 1.5

   ###*
-  Configures a meter to be
+  Configures a meter to be drawn
   The position of this game object. By default it is the top left point.
   Redefining the center method will change the relative position.


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -26,7 +26,8 @@
 # Since maxHealth wasn't provided, it is set to the value of I.health (500)

 someOtherObject.meter 'turbo'
-# =>
+# => Sets up a health meter that will be drawn during the enemy overlay event.
+# Since maxHealth wasn't provided, it is set to the value of I.health (500)

 # now player has all the methods provided by this module


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -125,7 +125,7 @@
   @param {String} font Size and style of the meter's font
   @param {Number} height Height of the meter
   @param {Object} position An x, y object representing the position of the meter
-    radius - Border radius of the meter
+  @param {String} radius - Border radius of the meter
     showName - Boolean to toggle whether or not to show the attribute associated with the meter
     text - A String to display over the meter. Overrides default name attribute
     width - How wide the meter is


vtrace, not strace

vtrace, not strace

--- src/methods.coffee
+++ src/methods.coffee
@@ -221,14 +221,14 @@
     op = code[cf.pc]

     loop
-      unless RELEASE? or logging.log_level < logging.STRACE
+      unless RELEASE? or logging.log_level < logging.VTRACE
         pc = cf.pc
         throw "#{@name}:#{pc} => (null)" unless op
         annotation = op.annotate(pc, @cls.constant_pool)

       break if op.execute(rs) is false

-      unless RELEASE? or logging.log_level < logging.STRACE
+      unless RELEASE? or logging.log_level < logging.VTRACE
         vtrace "#{@cls.get_type()}::#{@name}:#{pc} => #{op.name}" + annotation
         depth = rs.meta_stack().length()
         vtrace "D: #{depth}, S: [#{debug_vars cf.stack}], L: [#{debug_vars cf.locals}], T: #{thread_name(rs, rs.curr_thread) if rs.curr_thread.get_field? }"


runtime: Also stop coordinator

runtime: Also stop coordinator

--- src/runtime.coffee
+++ src/runtime.coffee
@@ -119,7 +119,11 @@
           onLoaded null

   stop: (callback) ->
-    @server.close callback
+    @coordinator.stop (stopErr) =>
+      @server.close (closeErr) ->
+        return callback stopErr if stopErr
+        return callback closeErr if closeErr
+        return callback null

   address: () ->
     scheme = 'ws://'


Fix unintended focused spec

Fix unintended focused spec

--- spec/builder-spec.coffee
+++ spec/builder-spec.coffee
@@ -2,7 +2,7 @@
 path = require 'path'
 Builder = require '../lib/builder'

-fdescribe "Builder", ->
+describe "Builder", ->
   [builder] = []

   beforeEach ->


added a lot more command/event listeners

--- lib/autohide-tree-view.coffee
+++ lib/autohide-tree-view.coffee
@@ -24,14 +24,18 @@

   activate: (state) ->
     @subs = new SubAtom()
+    # initialize this package when the tree-view package is activated
     @subs.add atom.packages.onDidActivatePackage (pkg) =>
       @initialize state, pkg if pkg.path.match(/\/tree-view\/?$/i)

   deactivate: ->
+    # cleanup the tree view element
     @disable() if treeViewEl?
+    # dispose subscriptions
     @subs.dispose()

   serialize: ->
+    # remember if enabled
     {@enabled}

   initialize: (state, treeViewPkg) ->
@@ -54,6 +58,7 @@
     @subs.add 'atom-workspace', 'mouseleave', '.tree-view-resizer.autohide.autohide-hover-events', =>
       @hide()

+    # register commands for this package
     @subs.add atom.commands.add 'atom-workspace',
       'autohide-tree-view:toggle-enabled': => @toggleEnabled()
       'autohide-tree-view:enable': => @enable()
@@ -66,28 +71,43 @@
     @subs.add atom.packages.onDidDeactivatePackage (pkg) ->
       treeView = treeViewEl = null if pkg.path.match /\/tree-view\/?/i

-    # following events should be fired AFTER tree-view is done handling them
+    # hide when opening a file
+    # show when expanding a directory
     @subs.add treeViewEl, 'click', '.entry', (event) =>
-      # console.log event.target, event.currentTarget
-      if event.currentTarget.classList.contains 'directory'
-        @show true
-      else
-        @hide true
+      @openEntry event
+
+    # listen to commands of the tree view
     @subs.add treeViewEl,
+      # adjust tree view size to the width of the actual list
+      # when expanding a directory
       'tree-view:expand-directory': => @show true
       'tree-view:recursive-expand-directory': => @show true
       'tree-view:collapse-directory': => @show true
       'tree-view:recursive-collapse-directory': => @show true
-      'tree-view:open-selected-entry': => @hide true
-    @subs.add atom.config.observe 'tree-view:showOnRightSide', =>
-      @applyHiddenWidth()
+      # hideshow on tree view open entry commands
+      'tree-view:open-selected-entry': (event) => @openEntry event
+      'tree-view:open-selected-entry-right': (event) => @openEntry event
+      'tree-view:open-selected-entry-left': (event) => @openEntry event
+      'tree-view:open-selected-entry-up': (event) => @openEntry event
+      'tree-view:open-selected-entry-down': (event) => @openEntry event
+      'tree-view:open-selected-entry-in-pane-1': (event) => @openEntry event
+      'tree-view:open-selected-entry-in-pane-2': (event) => @openEntry event
+      'tree-view:open-selected-entry-in-pane-3': (event) => @openEntry event
+      'tree-view:open-selected-entry-in-pane-4': (event) => @openEntry event
+      'tree-view:open-selected-entry-in-pane-5': (event) => @openEntry event
+      'tree-view:open-selected-entry-in-pane-6': (event) => @openEntry event
+      'tree-view:open-selected-entry-in-pane-7': (event) => @openEntry event
+      'tree-view:open-selected-entry-in-pane-8': (event) => @openEntry event
+      'tree-view:open-selected-entry-in-pane-9': (event) => @openEntry event

+  # enable/disable autohide behavior
   toggleEnabled: ->
     if @enabled
       @disable()
     else
       @enable()

+  # enable autohide behavior
   enable: ->
     treeViewEl.classList.add 'autohide'
     @applyHiddenWidth()
@@ -95,6 +115,7 @@
     @hide true
     @enabled = true

+  # disable autohide behavior
   disable: ->
     treeViewEl.classList.remove 'autohide'
     treeViewEl.classList.remove 'autohide-hover-events'
@@ -105,12 +126,14 @@
     treeViewEl.style.width = treeViewEl.querySelector('.tree-view').clientWidth
     @enabled = false

+  # show/hide the tree view
   toggleVisible: ->
     if treeViewEl.classList.contains 'unfolded'
       @hide true
     else
       @show true, true

+  # show the tree view
   show: (noDelay, disableHoverEvents) ->
     width = treeViewEl.querySelector('.tree-view').clientWidth
     noDelay = true if width > treeViewEl.clientWidth > atom.config.get 'autohide-tree-view.hiddenWidth'
@@ -121,6 +144,7 @@
     treeView.focus()
     @disableHoverEvents() if disableHoverEvents

+  # hide the tree view
   hide: (noDelay) ->
     width = atom.config.get 'autohide-tree-view.hiddenWidth'
     transitionDelay = if noDelay then 0 else atom.config.get 'autohide-tree-view.hideDelay'
@@ -130,13 +154,22 @@
     treeView.unfocus()
     @enableHoverEvents()

+  openEntry: (event) ->
+    if treeView.selectedEntry().classList.contains 'directory'
+      @show true
+    else if event.type isnt 'click'
+      @hide true
+
+  # apply the hiddenWidth setting
   applyHiddenWidth: (width = atom.config.get 'autohide-tree-view.hiddenWidth') ->
     treeViewEl.style.setProperty 'width', "#{width}px"
     treeViewEl.parentNode.style.setProperty 'width', "#{width}px", 'important'

+  # enable the hover events on the tree view
   enableHoverEvents: ->
     treeViewEl.classList.add 'autohide-hover-events'

+  # disable the hover events on the tree view
   disableHoverEvents: ->
     treeViewEl.classList.remove 'autohide-hover-events'