collaborative-workspace: do not disconnect on join session event

--- client/landing/CollaborativeWorkspace/collaborativeworkspace.coffee
+++ client/landing/CollaborativeWorkspace/collaborativeworkspace.coffee
@@ -184,7 +184,6 @@
     options                = @getOptions()
     options.sessionKey     = newOptions.sessionKey.trim()
     options.joinedASession = yes
-    @forceDisconnect()
     @destroy()

     @addSubView new CollaborativeWorkspace options


Fix logging.

Fix logging.

--- services/web/app/coffee/Features/User/UserSessionsManager.coffee
+++ services/web/app/coffee/Features/User/UserSessionsManager.coffee
@@ -21,7 +21,7 @@
 			.expire(sessionSetKey, "#{Settings.cookieSessionLength}")
 			.exec (err, response) ->
 				if err
-					logger.err {err, user_id: user._id, sessionId}, "error while adding session key to UserSessions set"
+					logger.err {err, user_id: user._id, sessionSetKey}, "error while adding session key to UserSessions set"
 					return callback(err)
 				callback()

@@ -37,7 +37,7 @@
 			.expire(sessionSetKey, "#{Settings.cookieSessionLength}")
 			.exec (err, response) ->
 				if err
-					logger.err {err, user_id: user._id, sessionId}, "error while removing session key from UserSessions set"
+					logger.err {err, user_id: user._id, sessionSetKey}, "error while removing session key from UserSessions set"
 					return callback(err)
 				callback()


catch rejected promises in pdfviewer

catch rejected promises in pdfviewer

--- services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee
+++ services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee
@@ -309,7 +309,6 @@
 								scope.loadSuccess = true
 						.catch (error) ->
 							scope.$emit 'pdf:error', error
-							return $q.reject(error)

 				elementTimer = null
 				spinnerTimer = null
@@ -373,9 +372,11 @@
 						scope.$emit 'pdf:error:display'
 						return
 					if scope.loadSuccess
-						ctrl.load()
-						# trigger a redraw
-						scope.scale = angular.copy (scope.scale)
+						ctrl.load().then () ->
+							# trigger a redraw
+							scope.scale = angular.copy (scope.scale)
+						.catch (error) ->
+							scope.$emit 'pdf:error:display'
 					else
 						scope.$emit 'pdf:error:display'
 						return
@@ -413,9 +414,11 @@
 					return unless newVal?
 					scope.loadCount = 0; # new pdf, so reset load count
 					scope.loadSuccess = false
-					ctrl.load()
-					# trigger a redraw
-					scope.scale = angular.copy (scope.scale)
+					ctrl.load().then () ->
+						# trigger a redraw
+						scope.scale = angular.copy (scope.scale)
+					.catch (error) ->
+						scope.$emit 'pdf:error', error

 				scope.$watch 'scale', (newVal, oldVal) ->
 					# no need to set scale when initialising, done in pdfSrc


renamed testSubject to stream

renamed testSubject to stream

--- test/transaction-stream-test.coffee
+++ test/transaction-stream-test.coffee
@@ -34,7 +34,7 @@
   it 'subscribes to account and streams it', (done) ->
     world.given.fakeWebSocketConstructor()

-    testSubject = transactionStream(world.fakeWebSocketConstructor, 'gDSSa75HPagWcvQmwH7D51dT5DPmvsKL4q')
+    stream = transactionStream(world.fakeWebSocketConstructor, 'gDSSa75HPagWcvQmwH7D51dT5DPmvsKL4q')

     assert(world.fakeWebSocketConstructor.calledWithNew())
     assert(world.fakeWebSocketConstructor.calledWith('ws://live.stellar.org:9001'))
@@ -45,14 +45,14 @@

     clock.tick 100

-    testSubject.on 'error', -> assert.fail('should not call error')
+    stream.on 'error', -> assert.fail('should not call error')

     world.fakeWebSocketInstance.send.yield null

     assert(world.fakeWebSocketInstance.send.calledWith(
       JSON.stringify({ "command" : "subscribe",   "accounts" : [ "gDSSa75HPagWcvQmwH7D51dT5DPmvsKL4q" ] })))

-    testSubject.on 'data', (data) ->
+    stream.on 'data', (data) ->
       assert.deepEqual data,
         from: "gDSSa75HPagWcvQmwH7D51dT5DPmvsKL4q"
         to: "gM8ZuCaGB7GkCiLz7rW941boyVT2vW1ppT"
@@ -75,13 +75,13 @@
   it 'forwards errors from on error', (done) ->
     world.given.fakeWebSocketConstructor()

-    testSubject = transactionStream(world.fakeWebSocketConstructor, 'gDSSa75HPagWcvQmwH7D51dT5DPmvsKL4q')
+    stream = transactionStream(world.fakeWebSocketConstructor, 'gDSSa75HPagWcvQmwH7D51dT5DPmvsKL4q')

     clock.tick 50

     fakeError = new Error()

-    testSubject.on 'error', (error) ->
+    stream.on 'error', (error) ->
       assert.equal fakeError, error
       done()

@@ -91,14 +91,14 @@

     world.given.fakeWebSocketConstructor()

-    testSubject = transactionStream(world.fakeWebSocketConstructor, 'gDSSa75HPagWcvQmwH7D51dT5DPmvsKL4q')
+    stream = transactionStream(world.fakeWebSocketConstructor, 'gDSSa75HPagWcvQmwH7D51dT5DPmvsKL4q')

     clock.tick 50

     world.fakeWebSocketInstance.fakeEmit 'open'

     fakeError = new Error()
-    testSubject.on 'error', (error) ->
+    stream.on 'error', (error) ->
       assert.equal fakeError, error
       done()


Updated template.coffee

Updated template.coffee

--- template.coffee
+++ template.coffee
@@ -50,8 +50,6 @@

     props.keywords = []
     props.preferGlobal = true
-    props.browserify = {}
-    props.browserify.transform = ['coffeeify','hbsfy']
     props.devDependencies =
       "browser-sync": "^2.7.1"
       "browserify": "^10.2.0"
@@ -76,7 +74,6 @@
     # Files to copy (and process).
     files = init.filesToCopy(props)

-
     # Add properly-named license files.
     init.addLicenseFiles(files, props.licenses)

@@ -85,8 +82,11 @@

     # Generate package.json file.
     init.writePackageJSON 'package.json',  props, (pkg, props) ->
+      pkg['browserify'] =
+        transform : ['coffeeify','hbsfy']
+
       pkg['scripts'] =
-        test: 'gulp test'
+        test : 'gulp test'
       pkg

     # All done!


make tests safer

make tests safer

--- test/get.coffee
+++ test/get.coffee
@@ -26,7 +26,7 @@
         uri = 'arhgglserhslfhs'
         options = uri: uri
         quest options, (err, resp, body) ->
-          assert.equal err.code, "ENOTFOUND"
+          assert.equal err?.code, "ENOTFOUND"
           done()

       it 'supports no protocol', (done) ->
@@ -36,8 +36,8 @@
           json: true
         quest options, (err, resp, body) ->
           assert not err, "Has error #{err}"
-          assert.equal resp.statusCode, 200, "Status code should be 200, is #{resp.statusCode}"
-          assert.equal body.headers.Host, 'httpbin.org'
+          assert.equal resp?.statusCode, 200, "Status code should be 200, is #{resp?.statusCode}"
+          assert.equal body?.headers?.Host, 'httpbin.org'
           done safe_err err

       it 'supports simple gets', (done) ->
@@ -46,8 +46,8 @@
           uri: "#{protocol}://httpbin.org/get"
         quest options, (err, resp, body) ->
           assert not err, "Has error #{err}"
-          assert.equal resp.statusCode, 200, "Status code should be 200, is #{resp.statusCode}"
-          assert.equal JSON.parse(body).headers.Host, 'httpbin.org'
+          assert.equal resp?.statusCode, 200, "Status code should be 200, is #{resp?.statusCode}"
+          assert.equal JSON.parse(body)?.headers?.Host, 'httpbin.org'
           done safe_err err

       it 'supports interpreting responses as json', (done) ->
@@ -57,8 +57,8 @@
           json: true
         quest options, (err, resp, body) ->
           assert not err, "Has error #{err}"
-          assert.equal resp.statusCode, 200, "Status code should be 200, is #{resp.statusCode}"
-          assert.equal body.headers.Host, 'httpbin.org'
+          assert.equal resp?.statusCode, 200, "Status code should be 200, is #{resp?.statusCode}"
+          assert.equal body?.headers?.Host, 'httpbin.org'
           done safe_err err

       it 'has a default user-agent', (done) ->
@@ -69,8 +69,8 @@
           json: true
         quest options, (err, resp, body) ->
           assert not err, "Has error #{err}"
-          assert.equal resp.statusCode, 200, "Status code should be 200, is #{resp.statusCode}"
-          assert.equal body['user-agent'], default_user_agent
+          assert.equal resp?.statusCode, 200, "Status code should be 200, is #{resp?.statusCode}"
+          assert.equal body?['user-agent'], default_user_agent
           done safe_err err

       it 'allows you to modify the headers', (done) ->
@@ -83,8 +83,8 @@
             'user-agent': other_user_agent
         quest options, (err, resp, body) ->
           assert not err, "Has error #{err}"
-          assert.equal resp.statusCode, 200, "Status code should be 200, is #{resp.statusCode}"
-          assert.equal body['user-agent'], other_user_agent
+          assert.equal resp?.statusCode, 200, "Status code should be 200, is #{resp?.statusCode}"
+          assert.equal body?['user-agent'], other_user_agent
           done safe_err err

       it 'allows you to set a querystring parameter', (done) ->
@@ -95,8 +95,8 @@
             my_param: 'trolling'
         quest options, (err, resp, body) ->
           assert not err, "Has error #{err}"
-          assert.equal resp.statusCode, 200, "Status code should be 200, is #{resp.statusCode}"
-          assert.equal resp.headers.my_param, 'trolling', "Parameter should be trolling, is #{resp.headers.my_param}"
+          assert.equal resp?.statusCode, 200, "Status code should be 200, is #{resp?.statusCode}"
+          assert.equal resp?.headers?.my_param, 'trolling', "Parameter should be trolling, is #{resp?.headers?.my_param}"
           done safe_err err

       it "doesn't follow redirects when disabled", (done) ->
@@ -106,8 +106,8 @@
           followRedirects: false
         quest options, (err, resp, body) ->
           assert not err, "Has error #{err}"
-          assert.equal resp.statusCode, 302, "Status code should be 302, is #{resp.statusCode}"
-          assert.equal resp.headers.location, 'http://httpbin.org/redirect/2'
+          assert.equal resp?.statusCode, 302, "Status code should be 302, is #{resp?.statusCode}"
+          assert.equal resp?.headers?.location, 'http://httpbin.org/redirect/2'
           done safe_err err

       it 'follows redirects', (done) ->
@@ -117,8 +117,8 @@
           json: true
         quest options, (err, resp, body) ->
           assert not err, "Has error #{err}"
-          assert.equal resp.statusCode, 200, "Status code should be 200, is #{resp.statusCode}"
-          assert.equal body.url, "http://httpbin.org/get"
+          assert.equal resp?.statusCode, 200, "Status code should be 200, is #{resp?.statusCode}"
+          assert.equal body?.url, "http://httpbin.org/get"
           done safe_err err

       it "doesn't follow relative redirects when disabled", (done) ->
@@ -128,9 +128,9 @@
           followRedirects: false
         quest options, (err, resp, body) ->
           assert not err, "Has error #{err}"
-          assert.equal resp.statusCode, 302, "Status code should be 302, is #{resp.statusCode}"
+          assert.equal resp?.statusCode, 302, "Status code should be 302, is #{resp?.statusCode}"
           # As far as I can tell this isn't actually a relative redirect...
-          assert.equal resp.headers.location, 'http://httpbin.org/relative-redirect/2'
+          assert.equal resp?.headers?.location, 'http://httpbin.org/relative-redirect/2'
           done safe_err err

       it 'follows relative redirects', (done) ->
@@ -140,8 +140,8 @@
           json: true
         quest options, (err, resp, body) ->
           assert not err, "Has error #{err}"
-          assert.equal resp.statusCode, 200, "Status code should be 200, is #{resp.statusCode}"
-          assert.equal body.url, "http://httpbin.org/get"
+          assert.equal resp?.statusCode, 200, "Status code should be 200, is #{resp?.statusCode}"
+          assert.equal body?.url, "http://httpbin.org/get"
           done safe_err err

       it 'has a maximum number of redirects', (done) ->
@@ -165,9 +165,9 @@
           json: true
         quest options, (err, resp, body) ->
           assert not err, "Has error #{err}"
-          assert.equal resp.statusCode, 200, "Status code should be 200, is #{resp.statusCode}"
-          assert.equal _(body.cookies).keys().length, 1
-          assert.equal body.cookies.my_param, 'trolling'
+          assert.equal resp?.statusCode, 200, "Status code should be 200, is #{resp?.statusCode}"
+          assert.equal _(body?.cookies)?.keys()?.length, 1
+          assert.equal body?.cookies?.my_param, 'trolling'
           done safe_err err

       it 'stores cookies', (done) ->
@@ -185,13 +185,13 @@
               json: true
             quest options, cb_wf
           (resp, body, cb_wf) ->
-            assert.equal resp.statusCode, 200, "Status code should be 200, is #{resp.statusCode}"
+            assert.equal resp?.statusCode, 200, "Status code should be 200, is #{resp?.statusCode}"
             cookies = j.get uri
             assert.equal cookies.length, 2
-            assert.equal cookies[0].name, 'my_param'
-            assert.equal cookies[0].value, 'trolling'
-            assert.equal cookies[1].name, 'my_param2'
-            assert.equal cookies[1].value, 'trolling2'
+            assert.equal cookies[0]?.name, 'my_param'
+            assert.equal cookies[0]?.value, 'trolling'
+            assert.equal cookies[1]?.name, 'my_param2'
+            assert.equal cookies[1]?.value, 'trolling2'

             options =
               uri: "#{protocol}://httpbin.org/cookies"
@@ -199,9 +199,9 @@
               json: true
             quest options, cb_wf
           (resp, body, cb_wf) ->
-            assert.equal resp.statusCode, 200, "Status code should be 200, is #{resp.statusCode}"
-            assert.equal _(body.cookies).keys().length, 2
-            assert.equal body.cookies.my_param, 'trolling'
-            assert.equal body.cookies.my_param2, 'trolling2'
+            assert.equal resp?.statusCode, 200, "Status code should be 200, is #{resp?.statusCode}"
+            assert.equal _(body?.cookies)?.keys().length, 2
+            assert.equal body?.cookies?.my_param, 'trolling'
+            assert.equal body?.cookies?.my_param2, 'trolling2'
             cb_wf()
         ], (err) -> done safe_err err


better test error

better test error

--- test/external/druidExternalIntrospection.mocha.coffee
+++ test/external/druidExternalIntrospection.mocha.coffee
@@ -118,7 +118,7 @@

   requesterDruid_0_8_0 = ({query}) ->
     if query.queryType is 'segmentMetadata'
-      return Q.reject(new Error('segmentMetadata failed'))
+      return Q.reject(new Error('Timeout'))

     expect(query).to.deep.equal({
       "dataSource": "wikipedia"


Clear the search scope on ctrl/cmd/alt + backspace

--- assets/javascripts/views/search/search_scope.coffee
+++ assets/javascripts/views/search/search_scope.coffee
@@ -88,13 +88,12 @@
     return

   onKeydown: (event) =>
-    return if event.ctrlKey or event.metaKey or event.altKey or event.shiftKey
-
     if event.which is 8 # backspace
       if @doc and not @input.value
         $.stopEvent(event)
         @reset()
     else if not @doc and @input.value
+      return if event.ctrlKey or event.metaKey or event.altKey or event.shiftKey
       if event.which is 9 or # tab
          event.which is 32 and (app.isMobile() or $.isTouchScreen()) # space
         @search @input.value[0...@input.selectionStart]


Listen to changes to currentPage.downloads

--- src/scripts/modules/media/footer/downloads/downloads.coffee
+++ src/scripts/modules/media/footer/downloads/downloads.coffee
@@ -8,4 +8,4 @@

     initialize: () ->
       super()
-      @listenTo(@model, 'changePage changePage:content', @render)
+      @listenTo(@model, 'change:currentPage.downloads', @render)


Enable "Downloading Update" context menu entry

Previously 'update-downloaded' would get emitted right after 'update-available' which would suppress the "Downloading Update" menu entry

--- src/browser/auto-updater-win32.coffee
+++ src/browser/auto-updater-win32.coffee
@@ -14,6 +14,8 @@
       require('auto-updater').quitAndInstall()

   downloadUpdate: (callback) ->
+    @emit 'update-available'
+
     SquirrelUpdate.spawn ['--download', @updateUrl], (error, stdout) ->
       return callback(error) if error?

@@ -56,7 +58,6 @@
           @emit 'update-not-available'
           return

-        @emit 'update-available'
         @emit 'update-downloaded', {}, update.releaseNotes, update.version, new Date(), 'https://atom.io', => @quitAndInstall()

 module.exports = new AutoUpdater()


Use execFile from child_process

Use execFile from child_process

This will make it easier to extract to Atom Shell since BufferedProcess
is internal to Atom.

--- src/browser/auto-updater-win32.coffee
+++ src/browser/auto-updater-win32.coffee
@@ -4,7 +4,7 @@
 shellAutoUpdater = require 'auto-updater'

 {EventEmitter} = require 'events'
-{BufferedProcess} = require 'atom'
+ChildProcess = require 'child_process'

 module.exports =
 class AutoUpdater
@@ -20,72 +20,50 @@
       console.log 'Running developer or Chocolatey version of Atom, skipping'
       return

-    updateOutput = ""
-    ps = new BufferedProcess
-      command: updateDotExe,
-      args: ['--update', @updateUrl]
-      stdout: (o) -> updateOutput += o
-      exit: (exitCode) ->
-        unless exitCode is 0
-          console.log 'Failed to update: ' + exitCode + ' - ' + updateOutput
-          return
+    args = ['--update', @updateUrl]
+    ChildProcess.execFile updateDotExe, args, (error) ->
+      return if error?

-        dontcare = new BufferedProcess
-          command: updateDotExe,
-          args: ['--processStart', 'atom.exe']
-
+      args = ['--processStart', 'atom.exe']
+      ChildProcess.execFile updateDotExe, args, ->
         shellAutoUpdater.quitAndInstall()

   checkForUpdates: ->
-    throw new Error("Update URL is not set") unless @updateUrl
+    throw new Error('Update URL is not set') unless @updateUrl

     emit 'checking-for-update'

     updateDotExe = path.join(path.dirname(process.execPath), '..', 'update.exe')
+
     unless fs.existsSync(updateDotExe)
       console.log 'Running developer or Chocolatey version of Atom, skipping'
       emit 'update-not-available'
       return

     args = ['--update', @updateUrl]
-    updateOutput = ""
+    ChildProcess.execFile updateDotExe, args, (error, stdout) =>
+      if error?
+        console.log "Failed to update: #{error.code} - #{stdout}"
+        emit 'update-not-available'
+        return

-    ps = new BufferedProcess
-      command: updateDotExe,
-      args,
-      stdout: (output) -> updateOutput += output
-      exit: (exitCode) ->
-        unless exitCode is 0
-          console.log "Failed to update: #{exitCode} - #{updateOutput}"
-          emit 'update-not-available'
-          return
+      try
+        # Last line of output is the JSON details about the release
+        [json] = stdout.split('\n').reverse()
+        latestRelease = JSON.parse(json)?.releasesToApply?.pop?()
+      catch error
+        console.log "Update output isn't valid: #{stdout}"
+        emit 'update-not-available'
+        return

-        updateInfo = null
-        try
-          # NB: Update.exe spits out the progress as ints until it completes,
-          # then the JSON is the last line of the output. We don't support progress
-          # so just drop the last lines
-          json = updateOutput.split("\n").reverse()[0]
-
-          updateInfo = JSON.parse json
-        catch error
-          console.log "Update output isn't valid: #{updateOutput}"
-          emit 'update-not-available'
-          return
-
-        unless updateInfo and updateInfo.releasesToApply.length > 0
-          console.log "You're on the latest version!"
-          emit 'update-not-available'
-          return
-
-        latest = updateInfo.releasesToApply[updateInfo.ReleasesToApply.length-1]
-
-        # We don't have separate "check for update" and "download" in Squirrel,
-        # we always just download
+      if latestRelease?
         emit 'update-available'
         emit 'update-downloaded',
-          releaseNotes: latest.releaseNotes
-          releaseName: "Atom #{latest.version}"
-          releaseDate: ""   # NB: Squirrel doesn't provide this :(
-          updateUrl: "https://atom.io"
-          quitAndUpdate: @quitAndInstall
+          releaseNotes: latestRelease.releaseNotes
+          releaseName: "Atom #{latestRelease.version}"
+          releaseDate: ''
+          updateUrl: 'https://atom.io'
+          quitAndUpdate: => @quitAndInstall
+      else
+        console.log "You're on the latest version!"
+        emit 'update-not-available'


fixed return type

fixed return type

--- src/main/coffeescript/view/MainView.coffee
+++ src/main/coffeescript/view/MainView.coffee
@@ -62,7 +62,6 @@
       resource.id = id
       resources[id] = resource
       @addResource resource, @model.auths
-    @

     $('.propWrap').hover(
       ->
@@ -70,6 +69,7 @@
       ,->
         $('.optionsWrapper', $(this)).hide()
     )
+    @

   addResource: (resource, auths) ->
     # Render a resource and add it to resources li


Remove unused variable

Remove unused variable

--- src/main/assets/javascripts/simple.coffee
+++ src/main/assets/javascripts/simple.coffee
@@ -1,5 +1,5 @@
 generateData = ->
-  data = [
+  [
     {
       "title":"Some Title",
       "description":"Some description",


webapp/lib: Number.isNaN polyfill -- issue #1853

--- src/webapp-lib.coffee
+++ src/webapp-lib.coffee
@@ -9,6 +9,10 @@
 # TODO switch to npm packaging

 require("script!primus/primus-engine.min.js")
+
+# polyfill Number.isNaN for IE -- see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN#Polyfill
+Number.isNaN = Number.isNaN || (value) ->
+    typeof value == "number" and isNaN(value)

 # polyfill for internet explorer's lack of knowing String.prototype.startswith
 String::startsWith ?= (searchString, position) ->


Removing jQuery

Removing jQuery

--- test/dummy/app/assets/javascripts/views/shared/flash.coffee
+++ test/dummy/app/assets/javascripts/views/shared/flash.coffee
@@ -11,21 +11,23 @@
   setWarning: (text) -> @warning = text

   render: ->
-    node = $('.flash')
-    node.removeClass('notice').removeClass('alert').removeClass('warning')
+    node = document.querySelector('.flash')
+    node.classList.remove('notice')
+    node.classList.remove('alert')
+    node.classList.remove('warning')
     if @notice?
-      node.addClass 'notice'
-      node.find('p').text @notice
+      node.classList.add('notice')
+      document.querySelector('.flash p').textContent = @notice
     else if @alert?
-      node.addClass 'alert'
-      node.find('p').text @alert
+      node.classList.add('alert')
+      document.querySelector('.flash p').textContent = @alert
     else if @warning?
-      node.addClass 'warning'
-      node.find('p').text @warning
-    node.slideDown 'normal'
+      node.classList.add('warning')
+      document.querySelector('.flash p').textContent = @warning
+    node.classList.remove('none') # slideDown initially
     this.hideAfterTime() if @hide

   hideAfterTime: (time = 4000) ->
     setTimeout ->
-      $('.flash').slideUp 'normal'
+      document.querySelector('.flash').classList.add('none') # slideUp initially
     , time


Better coffeescript

Better coffeescript

--- app/assets/javascripts/admin/views/registrations/edit.js.coffee
+++ app/assets/javascripts/admin/views/registrations/edit.js.coffee
@@ -26,39 +26,39 @@

   buildEventKey: ->
     eventKey = new Object()
-    jQuery.each $('.event-keys .row'), (index, value) ->
-      name = $(value).find('input#name').first().val()
-      path = $(value).find('input#path').first().val()
+    $.each @$('.event-keys .row'), (index, value) =>
+      name = @$(value).find('input#name').first().val()
+      path = @$(value).find('input#path').first().val()
       if path && name
         eventKey[name] = path
     eventKeyJSON = JSON.stringify(eventKey)
-    $('.event-keys').append("<input id='registration-event-key' name='event-key' type='hidden' value='#{eventKeyJSON}' />")
+    @$('.event-keys').append("<input id='registration-event-key' name='event-key' type='hidden' value='#{eventKeyJSON}' />")
     @model.set(event_key: @$('input[name=event-key]').val())

   buildEventDetails: ->
     eventDetails = new Object()
-    jQuery.each $('.event-details .row'), (index, value) ->
-      name = $(value).find('input#name').first().val()
-      path = $(value).find('input#path').first().val()
+    $.each @$('.event-details .row'), (index, value) =>
+      name = @$(value).find('input#name').first().val()
+      path = @$(value).find('input#path').first().val()
       if path && name
         eventDetails[name] = path
     eventDetailsJSON = JSON.stringify(eventDetails)
-    $('.event-details').append("<input id='registration-event-details' name='event-details' type='hidden' value='#{eventDetailsJSON}' />")
+    @$('.event-details').append("<input id='registration-event-details' name='event-details' type='hidden' value='#{eventDetailsJSON}' />")
     @model.set(event_details: @$('input[name=event-details]').val())

   prepareClickHandlers: ->
-    $(@$el).on 'click', '.add-event-fields', (event) ->
+    @$el.on 'click', '.add-event-fields', (event) ->
       event.preventDefault()
       template = JST['admin/templates/registrations/event_fields']
       $(template()).insertAfter($(@).context)
-    $(@$el).on 'click', '.remove-fields', (event) ->
+    @$el.on 'click', '.remove-fields', (event) ->
       event.preventDefault()
       $(@).closest('.row').remove()

   validateEventKey: ->
-    @$('.event-keys').on 'change', (event) ->
+    @$('.event-keys').on 'change', (event) =>
       console.log "Changed"
-      inputs = $(@).find('input#name')
+      inputs = @$el.find('input#name')
       input_values = _.map inputs, (input) ->
         return $(input).val()
       input_values = _.reject input_values, (value) ->
@@ -66,8 +66,8 @@
       unique_input_values = _.uniq input_values
       if unique_input_values.length != input_values.length
         $('#save')[0].disabled = true
-        $(@).find('strong').after('
Names must be unique
')
+        @$el.find('strong').after('
Names must be unique
')
       else
         $('#save')[0].disabled = false
-        $(@).find('p.text-error').remove()
+        @$el.find('p.text-error').remove()
 )


Removed unnecessary dependency injections.

--- app/assets/javascripts/ng-services/ng-FeedsFoldersSvc.js.coffee
+++ app/assets/javascripts/ng-services/ng-FeedsFoldersSvc.js.coffee
@@ -3,10 +3,8 @@
 ########################################################

 angular.module('feedbunch').service 'feedsFoldersSvc',
-['$rootScope', '$timeout', 'entriesPaginationSvc', 'feedsPaginationSvc', 'cleanupSvc',
-'animationsSvc', 'highlightedSidebarLinkSvc', 'loadFeedsSvc', 'loadFoldersSvc',
-($rootScope, $timeout, entriesPaginationSvc, feedsPaginationSvc, cleanupSvc,
-animationsSvc, highlightedSidebarLinkSvc, loadFeedsSvc, loadFoldersSvc)->
+['$rootScope', '$timeout', 'feedsPaginationSvc', 'loadFeedsSvc', 'loadFoldersSvc',
+($rootScope, $timeout, feedsPaginationSvc, loadFeedsSvc, loadFoldersSvc)->

   #--------------------------------------------
   # PRIVATE FUNCTION: Load feeds and folders every minute.


refactor confirm-account-page.coffee

refactor confirm-account-page.coffee

--- app/components/confirm-account-page/confirm-account-page.coffee
+++ app/components/confirm-account-page/confirm-account-page.coffee
@@ -4,12 +4,12 @@
   controller: ($scope, $location, $stateParams, Records, ipCookie, Toast) ->

     $scope.userConfirmingAccount = false
+    $scope.confirmationToken = $stateParams.confirmation_token

-    ipCookie.remove('currentGroupId')
-    ipCookie.remove('currentUserId')
-    ipCookie.remove('initialRequestPath')
-
-    $scope.confirmationToken = $stateParams.confirmation_token
+    $scope.redirectToLogin = () ->
+      $location.search('confirmation_token', null)
+      ipCookie.remove('currentUserId')
+      $location.path('/')

     $scope.confirmAccount = (formData) ->
       params =
@@ -19,9 +19,7 @@
       Records.users.confirmAccount(params)
         .then ->
           Toast.show('Your account is set up! Please log in to continue.')
-          $location.search('confirmation_token', null)
-          $location.path('/')
+          $scope.redirectToLogin()
         .catch ->
           Toast.show('This token has expired. Please log in to continue')
-          $location.search('confirmation_token', null)
-          $location.path('/')+          $scope.redirectToLogin()


social: remove getNextApiUrl function and chane proxy url composition

--- workers/social/lib/social/models/socialapi/requests.coffee
+++ workers/social/lib/social/models/socialapi/requests.coffee
@@ -2,13 +2,11 @@
 KONFIG = require('koding-config-manager').load("main.#{argv.c}")

 request        = require 'request'
-_ = require "underscore"
-
-getNextApiURL = (proxyUrl, callback)->
-
-  return callback null, KONFIG.socialapi.proxyUrl  unless proxyUrl
-
-  return callback null, "#{KONFIG.socialapi.customDomain.local}#{proxyUrl}"
+_               = require "underscore"
+
+socialProxyUrl  = "/api/social"
+webhookProxyUrl = "/api/integration"
+localDomain     = KONFIG.socialapi.customDomain.local

 wrapCallback = (callback)->
   (err, response, body) ->
@@ -25,33 +23,33 @@
 createAccount = ({id, nickname}, callback)->
   if not id or not nickname
     return callback {message:"Request is not valid for creating account"}
-  url = "/account"
+  url = "#{socialProxyUrl}/account"
   post url, {oldId: id, nick: nickname}, callback

 updateAccount = (data, callback)->
   {id, nick} = data
   if not id or not nick
     return callback {message:"Request is not valid for updating account"}
-  url = "/account/#{id}"
+  url = "#{socialProxyUrl}/account/#{id}"
   post url, data , callback

 createChannel = (data, callback)->
   unless data.name or data.creatorId
     return callback { message: "Request is not valid for creating channel"}
-  url = "/channel"
+  url = "#{socialProxyUrl}/channel"
   post url, data, callback

 fetchChannelActivities = (data, callback)->
   if not data.channelId or not data.accountId
     return callback { message: "Request is not valid for fetching activities"}
-  url = "/channel/#{data.channelId}/history"
+  url = "#{socialProxyUrl}/channel/#{data.channelId}/history"
   get url, data, callback

 fetchActivityCount = (data, callback)->
   if not data.channelId
     return callback {message: "Request is not valid for fetching activity count"}

-  url = "/channel/#{data.channelId}/history/count"
+  url = "#{socialProxyUrl}/channel/#{data.channelId}/history/count"
   get url, data, callback

 fetchGroupChannels = (data, callback)->
@@ -61,41 +59,41 @@
   # topic fetch is crashing so we forced for a limit here
   data.limit = 15

-  url = "/channel"
+  url = "#{socialProxyUrl}/channel"
   get url, data, callback

 fetchMessage = (data, callback)->
   if not data.id
     return callback { message: "Message id is not set"}

-  url = "/message/#{data.id}"
+  url = "#{socialProxyUrl}/message/#{data.id}"
   get url, data, callback

 postToChannel = (data, callback)->
   if not data.channelId or not data.accountId or not data.body
     return callback { message: "Request is not valid for posting message"}

-  url = "/channel/#{data.channelId}/message"
+  url = "#{socialProxyUrl}/channel/#{data.channelId}/message"
   post url, data, callback

 editMessage = (data, callback)->
   if not data.body or not data.id
     return callback { message: "Request is not valid for editing a message"}

-  url = "/message/#{data.id}"
+  url = "#{socialProxyUrl}/message/#{data.id}"
   post url, data, callback

 deleteMessage = (data, callback)->
   unless data.id
     return callback { message: "Request is not valid for deleting message"}
-  url =  "/message/#{data.id}"
+  url =  "#{socialProxyUrl}/message/#{data.id}"
   deleteReq url, data, callback

 likeMessage = (data, callback)->
   unless data.id
     return callback { message: "Request is not valid for liking a message"}

-  url = "/message/#{data.id}/interaction/like/add"
+  url = "#{socialProxyUrl}/message/#{data.id}/interaction/like/add"
   delete data.id
   post url, data, callback

@@ -103,7 +101,7 @@
   unless data.id
     return callback { message: "Request is not valid for unliking a message"}

-  url = "/message/#{data.id}/interaction/like/delete"
+  url = "#{socialProxyUrl}/message/#{data.id}/interaction/like/delete"
   delete data.id
   post url, data, callback

@@ -111,7 +109,7 @@
   unless data.id
     return callback { message: "Request is not valid for listing actors" }

-  url = "/message/#{data.id}/interaction/like"
+  url = "#{socialProxyUrl}/message/#{data.id}/interaction/like"
   delete data.id
   get url, data, callback

@@ -119,80 +117,80 @@
   if not data.accountId or not data.body or not data.messageId
     return callback { message: "Request is not valid for adding a reply"}

-  url = "/message/#{data.messageId}/reply"
+  url = "#{socialProxyUrl}/message/#{data.messageId}/reply"
   post url, data, callback

 listReplies = (data, callback)->
   unless data.messageId
     return callback { message: "Request is not valid for adding a reply"}

-  url = "/message/#{data.messageId}/reply"
+  url = "#{socialProxyUrl}/message/#{data.messageId}/reply"
   get url, data, callback

 fetchPopularTopics = (data, callback)->
   if not data.groupName or not data.type
     return callback {message: "Request is not valid for listing popular topics"}

-  url = "/popular/topics/#{data.type}"
+  url = "#{socialProxyUrl}/popular/topics/#{data.type}"
   get url, data, callback

 fetchPopularPosts = (data, callback)->
   if not data.groupName or not data.channelName
     return callback {message: "Request is not valid for listing popular topics"}

-  url = "/popular/posts/#{data.channelName}"
+  url = "#{socialProxyUrl}/popular/posts/#{data.channelName}"
   get url, data, callback

 fetchPinnedMessages = (data, callback)->
-  url = "/activity/pin/list"
+  url = "#{socialProxyUrl}/activity/pin/list"
   get url, data, callback

 pinMessage = (data, callback)->
   if not data.accountId or not data.messageId or not data.groupName
     return callback { message: "Request is not valid"}

-  url = "/activity/pin/add"
+  url = "#{socialProxyUrl}/activity/pin/add"
   post url, data, callback

 unpinMessage = (data, callback)->
   if not data.accountId or not data.messageId or not data.groupName
     return callback { message: "Request is not valid"}

-  url = "/activity/pin/remove"
+  url = "#{socialProxyUrl}/activity/pin/remove"
   post url, data, callback

 glancePinnedPost = (data, callback)->
   if not data.accountId or not data.messageId or not data.groupName
     return callback { message: "Request is not valid"}

-  url = "/activity/pin/glance"
+  url = "#{socialProxyUrl}/activity/pin/glance"
   post url, data, callback

 glanceNotifications = (data, callback)->
   if not data.accountId
     return callback { message: "Request is not valid"}

-  url = "/notification/glance"
+  url = "#{socialProxyUrl}/notification/glance"
   post url, data, callback

 listNotifications = (data, callback)->
   if not data.accountId # or not data.groupName
     return callback {message: "Request is not valid"}

-  url = "/notification/#{data.accountId}"
+  url = "#{socialProxyUrl}/notification/#{data.accountId}"
   get url, data, callback

 listParticipants = (data, callback)->
   return callback { message: "Request is not valid" } unless data.channelId
-  url = "/channel/#{data.channelId}/participants"
+  url = "#{socialProxyUrl}/channel/#{data.channelId}/participants"
   get url, data, callback

 addParticipants = (data, callback)->
-  url = "/channel/#{data.channelId}/participants/add"
+  url = "#{socialProxyUrl}/channel/#{data.channelId}/participants/add"
   doChannelParticipantOperation data, url, callback

 removeParticipants = (data, callback)->
-  url = "/channel/#{data.channelId}/participants/remove"
+  url = "#{socialProxyUrl}/channel/#{data.channelId}/participants/remove"

   {channelId, accountId} = data
   # fetch channel details
@@ -246,49 +244,49 @@
   unless data.channelId and data.accountId
     return callback {message: "Request is not valid"}

-  url = "/channel/#{data.channelId}/participant/#{data.accountId}/presence"
+  url = "#{socialProxyUrl}/channel/#{data.channelId}/participant/#{data.accountId}/presence"
   post url, data, callback

 fetchFollowedChannels = (data, callback)->
   if not data.accountId or not data.groupName
     return callback { message: "Request is not valid"}

-  url = "/account/#{data.accountId}/channels"
+  url = "#{socialProxyUrl}/account/#{data.accountId}/channels"
   get url, data, callback

 fetchFollowedChannelCount = (data, callback)->
   if not data.accountId or not data.groupName
     return callback { message: "Request is not valid"}

-  url = "/account/#{data.accountId}/channels/count"
+  url = "#{socialProxyUrl}/account/#{data.accountId}/channels/count"
   get url, data, callback

 initPrivateMessage = (data, callback)->
   if not data.body or not data.recipients or data.recipients.length < 1
     return callback { message: "Request is not valid"}

-  url = "/privatechannel/init"
+  url = "#{socialProxyUrl}/privatechannel/init"
   post url, data, callback

 sendPrivateMessage = (data, callback)->
   if not data.body or not data.channelId
     return callback { message: "Request is not valid"}

-  url = "/privatechannel/send"
+  url = "#{socialProxyUrl}/privatechannel/send"
   post url, data, callback

 fetchPrivateMessages = (data, callback)->
-  url = "/privatechannel/list"
+  url = "#{socialProxyUrl}/privatechannel/list"
   get url, data, callback

 fetchPrivateMessageCount = (data, callback)->
-  url = "/privatechannel/count"
+  url = "#{socialProxyUrl}/privatechannel/count"
   get url, data, callback

 searchChats = (data, callback)->
   if not data.name
     return callback { message: "Name should be set for chat search"}
-  url = "/privatechannel/search"
+  url = "#{socialProxyUrl}/privatechannel/search"
   get url, data, callback

 followUser = (data, callback)->
@@ -313,70 +311,70 @@
   unless data.admins?.length and data.actorId and data.name
     return callback {message: "Request is not valid"}

-  url = "/notification/group"
+  url = "#{socialProxyUrl}/notification/group"
   post url, data, callback

 searchTopics = (data, callback)->
   if not data.name
     return callback { message: "Name should be set for topic search"}
-  url = "/channel/search"
+  url = "#{socialProxyUrl}/channel/search"
   get url, data, callback

 fetchProfileFeed = (data, callback)->
   if not data.targetId
     return callback { message: "targetId should be set"}
-  url = "/account/#{data.targetId}/posts"
+  url = "#{socialProxyUrl}/account/#{data.targetId}/posts"
   get url, data, callback

 fetchProfileFeedCount = (data, callback)->
   if not data.targetId
     return callback { message: "targetId should be set"}
-  url = "/account/#{data.targetId}/posts/count"
+  url = "#{socialProxyUrl}/account/#{data.targetId}/posts/count"
   get url, data, callback

 messageById = (data, callback)->
   if not data.id
     return callback { message: "id should be set"}
-  url = "/message/#{data.id}"
+  url = "#{socialProxyUrl}/message/#{data.id}"
   get url, data, callback

 messageBySlug = (data, callback)->
   if not data.slug
     return callback { message: "slug should be set"}
-  url = "/message/slug/#{data.slug}"
+  url = "#{socialProxyUrl}/message/slug/#{data.slug}"
   get url, data, callback

 channelById = (data, callback)->
   if not data.id
     return callback { message: "id should be set"}
-  url = "/channel/#{data.id}"
+  url = "#{socialProxyUrl}/channel/#{data.id}"
   get url, data, callback

 channelByName = (data, callback)->
   if not data.name
     return callback { message: "name should be set"}
-  url = "/channel/name/#{data.name}"
+  url = "#{socialProxyUrl}/channel/name/#{data.name}"
   get url, data, callback

 checkChannelParticipation = (data, callback)->
   if not data.name or not data.type
     return callback { message: "request is not valid" }

-  url = "/channel/checkparticipation"
+  url = "#{socialProxyUrl}/channel/checkparticipation"
   get url, data, callback

 markAsTroll = (data, callback)->
   unless data.accountId
     return callback {message: "Request is not valid"}

-  url = "/trollmode/#{data.accountId}"
+  url = "#{socialProxyUrl}/trollmode/#{data.accountId}"
   post url, data, callback

 unmarkAsTroll = (data, callback)->
   unless data.accountId
     return callback {message: "Request is not valid"}

-  url = "/trollmode/#{data.accountId}"
+  url = "#{socialProxyUrl}/trollmode/#{data.accountId}"
   deleteReq url, data, callback

 getSiteMap = (data, callback)->
@@ -384,86 +382,75 @@
   getXml url, {}, callback

 updateChannel = (data, callback) ->
-  url = "/channel/#{data.id}/update"
+  url = "#{socialProxyUrl}/channel/#{data.id}/update"
   post url, data, callback

 createChannel = (data, callback) ->
-  url = "/channel"
+  url = "#{socialProxyUrl}/channel"
   post url, data, callback

 deleteChannel = (data, callback) ->
-  url = "/channel/#{data.channelId}/delete"
+  url = "#{socialProxyUrl}/channel/#{data.channelId}/delete"
   post url, data, callback

 checkOwnership = (data, callback) ->
-  url = "/account/#{data.accountId}/owns"
+  url = "#{socialProxyUrl}/account/#{data.accountId}/owns"
   get url, data, callback

 expireSubscription = (accountId, callback) ->
-  url = "/payments/customers/#{accountId}/expire"
+  url = "#{socialProxyUrl}/payments/customers/#{accountId}/expire"
   post url, {}, callback

 fetchBotChannel = (data, callback) ->
-  url = "/botchannel"
-  data.proxyUrl = "/api/integration"
+  url = "#{webhookProxyUrl}/botchannel"
   get url, data, callback

 post = (url, data, callback)->
-  getNextApiURL data.proxyUrl, (err, apiurl)->
-    return callback err if err
-    reqOptions =
-      url    : "#{apiurl}#{url}"
-      json   : true
-      method : 'POST'
-
-    {reqOptions, data} = setCookieIfRequired reqOptions, data
-    {reqOptions, data} = setHeaderIfRequired reqOptions, data
-
-    reqOptions.body = data
-
-    request reqOptions, wrapCallback callback
+  reqOptions =
+    url    : "#{localDomain}#{url}"
+    json   : true
+    method : 'POST'
+
+  {reqOptions, data} = setCookieIfRequired reqOptions, data
+  {reqOptions, data} = setHeaderIfRequired reqOptions, data
+
+  reqOptions.body = data
+
+  request reqOptions, wrapCallback callback

 deleteReq = (url, data, callback)->
   [data, callback] = [callback, null] unless callback

-  getNextApiURL data.proxyUrl, (err, apiurl)->
-    return callback err if err
-
-    reqOptions =
-      url    : "#{apiurl}#{url}"
-      json   : true
-      method : 'DELETE'
-
-    {reqOptions, data} = setCookieIfRequired reqOptions, data
-
-    request reqOptions, wrapCallback callback
+  reqOptions =
+    url    : "#{localDomain}#{url}"
+    json   : true
+    method : 'DELETE'
+
+  {reqOptions, data} = setCookieIfRequired reqOptions, data
+
+  request reqOptions, wrapCallback callback

 getXml = (url, data, callback)->
-  getNextApiURL data.proxyUrl, (err, apiurl)->
-    return callback err if err
-    reqOptions =
-      url    : "#{apiurl}#{url}"
-      method : 'GET'
-
-    {reqOptions, data} = setCookieIfRequired reqOptions, data
-
-    request reqOptions, wrapCallback callback
+  reqOptions =
+    url    : "#{localDomain}#{url}"
+    method : 'GET'
+
+  {reqOptions, data} = setCookieIfRequired reqOptions, data
+
+  request reqOptions, wrapCallback callback

 get = (url, data, callback)->
-
-  getNextApiURL data.proxyUrl, (err, apiurl)->
-    return callback err if err
-    reqOptions =
-      url    : "#{apiurl}#{url}"
-      json   : true
-      method : 'GET'
-
-    {reqOptions, data} = setCookieIfRequired reqOptions, data
-
-    # finally set query string
-    reqOptions.qs = data
-
-    request reqOptions, wrapCallback callback
+  reqOptions =
+    url    : "#{localDomain}#{url}"
+    json   : true
+    method : 'GET'
+
+  {reqOptions, data} = setCookieIfRequired reqOptions, data
+
+  # finally set query string
+  reqOptions.qs = data
+
+  request reqOptions, wrapCallback callback

 setCookieIfRequired = (reqOptions, data)->
   # inject clientId cookie if exists


Improvement in VM memory change.

Improvement in VM memory change.

--- src/api/vm.coffee
+++ src/api/vm.coffee
@@ -206,7 +206,13 @@
         ['VCPUs_max', 'VCPUs_at_startup']
       else
         'VCPUs_number_live'
-    memory: 'memory_static_max'
+    memory:
+      if params.memory > VM.memory.size
+        # Increase the memory.
+        ['memory_static_max', 'memory_dynamic_max']
+      else
+        # Decrease the memory.
+        ['memory_memory_max', 'memory_static_max']
     'name_label'
     'name_description'
   }


Fix BellefitGenerate3DCartOrdersByFreshdeskUserIdCollection

--- test/lib/WorkflowExecutionHistoryGeneratorSpec.coffee
+++ test/lib/WorkflowExecutionHistoryGeneratorSpec.coffee
@@ -72,7 +72,6 @@
       ]
       histories = generator.histories()
       histories.length.should.be.equal(2)
-      console.log histories[1].events
       histories[0].events.length.should.be.equal(1 + 2)
       histories[1].events.length.should.be.equal(1 + 2 + 1 + 2 + 1 + 2)
       histories[1].events[4].eventType.should.be.equal("ActivityTaskScheduled")


Tested the self signed https agent logic. No http headers are sent if a bad cert is detected and an error is raised.

--- lib/self_signed_https_agent.coffee
+++ lib/self_signed_https_agent.coffee
@@ -7,8 +7,6 @@
 # This HTTPS Agent allows us to verify a server's self-signed cert before
 # accepting the connection via a "cert" event that is emitted when the cert
 # is received.
-#
-# This requires a pentest
 module.exports = class SelfSignedHttpsAgent extends https.Agent

   constructor: (options = {}) ->


Don't re-attach events

Don't re-attach events

--- lib/simple-select-list-view.coffee
+++ lib/simple-select-list-view.coffee
@@ -6,6 +6,7 @@
   Enter: 13

 class SimpleSelectListView extends SelectListView
+  eventsAttached: false
   @content: ->
     @div class: "select-list", =>
       @input class: "fake-input", outlet: "fakeInput"
@@ -21,19 +22,22 @@
   setActive: ->
     @fakeInput.focus()

-    # Makes sure that `autosave` does not try to run `getModel` when
-    # losing focus. Weird stuff going on here.
-    @fakeInput.focusout -> false
+    unless @eventsAttached
+      @eventsAttached = true

-    @fakeInput.keydown (e) =>
-      switch e.keyCode
-        when Keys.Enter
-          @confirmSelection()
-        when Keys.Escape
-          @cancel()
+      # Makes sure that `autosave` does not try to run `getModel` when
+      # losing focus. Weird stuff going on here.
+      @fakeInput.focusout -> false

-      if e.keyCode in _.values(Keys)
-        return false
+      @fakeInput.keydown (e) =>
+        switch e.keyCode
+          when Keys.Enter
+            @confirmSelection()
+          when Keys.Escape
+            @cancel()
+
+        if e.keyCode in _.values(Keys)
+          return false

   initialize: ->
     @on "core:move-up", (e) =>


change a default to be more explicit/restrictive; doesn't actually make a difference in practice since the other groups aren't used

--- src/smc-hub/postgres-server-queries.coffee
+++ src/smc-hub/postgres-server-queries.coffee
@@ -2217,7 +2217,7 @@
         opts = defaults opts,
             project_id  : required
             account_id  : undefined
-            groups      : misc.PROJECT_GROUPS
+            groups      : ['owner', 'collaborator']
             cache       : false  # if true cache result for a few seconds
             cb          : required  # cb(err, true if in group)
         if not opts.account_id?


Update atom config

Update atom config

--- dotfiles/.atom/config.cson
+++ dotfiles/.atom/config.cson
@@ -1,26 +1,34 @@
 "*":
-  "exception-reporting":
-    userId: "cd5734c5-c324-bffc-9bf7-c2f3615272de"
-  welcome:
-    showOnStartup: false
+  "atom-beautify":
+    general:
+      _analyticsUserId: "50b04dc5-cac8-4ff3-8f5e-995eab8fc4be"
+    php:
+      cs_fixer_path: "/usr/local/bin/php-cs-fixer"
   "autocomplete-plus": {}
   core:
+    disabledPackages: [
+      "linter-eslint"
+      "linter-rust"
+    ]
     themes: [
       "one-dark-ui"
-      "zenburn"
+      "atom-dark-syntax"
     ]
     disabledPackages: [
       "linter-eslint"
     ]
   editor:
+    autoIndentOnPaste: false
+    fontSize: 15
     invisibles: {}
     showIndentGuide: true
-    autoIndentOnPaste: false
-    fontSize: 17
   emmet: {}
-  "atom-beautify":
-    _analyticsUserId: "50b04dc5-cac8-4ff3-8f5e-995eab8fc4be"
-    php_cs_fixer_path: "/usr/local/bin/php-cs-fixer"
+  "exception-reporting":
+    userId: "cd5734c5-c324-bffc-9bf7-c2f3615272de"
+  "linter-htmlhint": {}
+  "linter-rust":
+    cargoCommand: "check"
   minimap: {}
-  "linter-htmlhint": {}
   "one-dark-ui": {}
+  welcome:
+    showOnStartup: false


Inclui sales channel na URL do botão de comprar

--- src/coffee/portal-sku-selector.coffee
+++ src/coffee/portal-sku-selector.coffee
@@ -11,6 +11,7 @@
 	constructor: (productData) ->
 		@productId = productData.productId
 		@name = productData.name
+		@salesChannel = productData.salesChannel
 		@skus = productData.skus

 		i = 0
@@ -228,13 +229,13 @@
 		@select.warnUnavailable().filter(':visible').hide()

 	showBuyButton: (sku) =>
-		@select.buyButton().attr('href', $.skuSelector.getAddUrlForSku(sku.sku, sku.sellerId)).show()
+		@select.buyButton().attr('href', $.skuSelector.getAddUrlForSku(sku.sku, sku.sellerId, 1, @data.salesChannel)).show()

 	showConfirmButton: (sku) =>
 		dimensionsText = $.map(sku.dimensions, (k, v) -> k).join(', ')

 		@select.confirmButton()
-		.attr('href', $.skuSelector.getAddUrlForSku(sku.sku, sku.sellerId))
+		.attr('href', $.skuSelector.getAddUrlForSku(sku.sku, sku.sellerId, 1, @data.salesChannel))
 		.show()
 		.find('.skuselector-confirm-dimensions').text(dimensionsText)

@@ -392,8 +393,8 @@
 $.skuSelector.getSkusForProduct = (productId) ->
 	$.get '/api/catalog_system/pub/products/variations/' + productId

-$.skuSelector.getAddUrlForSku = (sku, seller = 1, qty = 1, redirect = true) ->
-	"/checkout/cart/add?qty=#{qty}&seller=#{seller}&sku=#{sku}&redirect=#{redirect}"
+$.skuSelector.getAddUrlForSku = (sku, seller = 1, qty = 1, salesChannel = 1, redirect = true) ->
+	"/checkout/cart/add?qty=#{qty}&seller=#{seller}&sku=#{sku}&sc=#{salesChannel}&redirect=#{redirect}"

 #


Cosmetic changes in code style.

Cosmetic changes in code style.

--- src/brunch.coffee
+++ src/brunch.coffee
@@ -28,7 +28,7 @@
     for prop in ignored when prop of options
       delete options[prop]
     @options = options
-    @options.buildPath ?= path.join options.appPath, 'build/'
+    @options.buildPath ?= path.join options.appPath, 'build', ''
     @options.compilers = (new compiler @options for name, compiler of compilers)
     @watcher = new helpers.Watcher

@@ -37,7 +37,7 @@

   new: (callback) ->
     callback = @_makeCallback callback
-    templatePath = path.join module.id, '/../../template/base'
+    templatePath = path.join __dirname, '..', 'template', 'base'
     path.exists @options.appPath, (exists) =>
       if exists
         helpers.logError "[Brunch]: can\'t create project:
@@ -95,7 +95,8 @@
         className = helpers.formatClassName @options.name
         genName = helpers.capitalize @options.generator
         "class exports.#{className} extends Backbone.#{genName}\n"
-      else ''
+      else
+        ''

     fs.writeFile filePath, data, (error) ->
       return helpers.logError error if error?


Pass options to prelude() properly.

Pass options to prelude() properly.

--- src/bundle.coffee
+++ src/bundle.coffee
@@ -178,7 +178,6 @@
   # Wraps a required module in a define statement.
   wrap = (file, opts={}) ->
     # Map of require calls to file hashes
-
     map = {}
     for req, filename of file.resolved
       map[req] = cache[filename].hash
@@ -213,6 +212,9 @@
     if opts.prelude is false
       return cb null, ''

+    if typeof opts.prelude isnt 'string'
+      opts.prelude = null
+
     path = opts.prelude ? join __dirname, if opts.minify then 'prelude-minify' else 'prelude'
     resolve path, (err, filename) ->
       fs.readFile filename, 'utf8', (err, data) ->


video: add video action link to settings menu

--- client/ide/lib/views/chat/idechatmessagepane.coffee
+++ client/ide/lib/views/chat/idechatmessagepane.coffee
@@ -30,7 +30,6 @@

     @input.input.on 'focus', @lazyBound 'handleFocus', yes

-
     @once 'NewParticipantButtonClicked', => @onboarding?.destroy()

@@ -51,9 +50,8 @@
     @glance()

-  handleVideoActive: (publisher) ->
-
-    @videoActive = yes
+  handleVideoActive: -> @videoActive = yes
+  handleVideoEnded: -> @videoActive = no

   glance: ->
@@ -140,6 +138,10 @@

   requestJoinVideo: -> @emit 'ChatVideoRequested'
+  requestLeaveVideo: -> @emit 'ChatVideoLeaveRequested'
+
+  requestStartVideo: -> @emit 'ChatVideoStartRequested'
+  requestEndVideo: -> @emit 'ChatVideoEndRequested'

   createMenu: ->
@@ -159,11 +161,17 @@
   settingsMenu: ->

     menu =
-      'Search'          : { cssClass : 'disabled', callback: kd.noop }
-      'Minimize'        : { callback : @getDelegate().bound 'end' }
-      'Join Video Chat' : { callback : @bound 'requestJoinVideo' }
-      'Learn More'      : { separator: yes, callback : -> kd.utils.createExternalLink 'http://learn.koding.com/collaboration' }
-      # 'Settings'      : { callback : @getDelegate().bound 'showSettingsPane' }
+      'Search'     : { cssClass : 'disabled', callback: kd.noop }
+      'Minimize'   : { callback : @getDelegate().bound 'end' }
+      'Learn More' : { separator: yes, callback : -> kd.utils.createExternalLink 'http://learn.koding.com/collaboration' }
+      # 'Settings' : { callback : @getDelegate().bound 'showSettingsPane' }
+
+    # wtf? this somehow means that we are host. ~Umut
+    unless @isInSession
+      seperator = yes
+      if @videoActive
+      then menu['End Video Chat'] = { seperator, callback: @bound 'requestEndVideo' }
+      else menu['Start Video Chat']  = { seperator, callback: @bound 'requestStartVideo' }

     if @isInSession
     then menu['Leave Session'] = { callback : => @parent.settingsPane.leaveSession() }


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera.coffee
+++ src/camera.coffee
@@ -35,7 +35,7 @@
       width: 2 * deadzone.x
       height: 2 * deadzone.y

-    if
+    if objectCe
     I.scroll = Point(
       I.scroll.x.clamp(centerRect.left, centerRect.right)
       I.scroll.y.clamp(centerRect.top, centerRect.bottom)


Use regular expression for string matching

--- views/env.coffee
+++ views/env.coffee
@@ -149,9 +149,9 @@
   $('#custom-css')?.setAttribute 'href', "file://#{EXROOT}/hack/custom.css"

 # Custom theme
-window.loadTheme = (theme) ->
-  window.theme = theme
-  window.isDarkTheme = theme.indexOf('dark') != -1 or theme.indexOf('black') != -1 or theme == 'slate' or theme in ['slate', 'superhero', 'papercyan']
+window.loadTheme = (th) ->
+  window.theme = th
+  window.isDarkTheme = /(dark|black|slate|superhero|papercyan)/i.test th
   if theme == '__default__'
     $('#bootstrap-css')?.setAttribute 'href', "file://#{ROOT}/components/bootstrap/dist/css/bootstrap.css"
   else


Reversed.

Reversed.

--- webapp/public/pbsfinder/javascripts/jobs/table_header.coffee
+++ webapp/public/pbsfinder/javascripts/jobs/table_header.coffee
@@ -1,7 +1,6 @@
 $(document).ready ->
   t = $('#protein-table')
-  t.floatThead()
-  #t.floatThead({
-    #scrollContainer: (t) ->
-      #return t.closest('.table-container')
-  #})
+  t.floatThead({
+    scrollContainer: (t) ->
+      return t.closest('.table-container')
+  })


typo in test

typo in test

--- test/OfflineIntegration.coffee
+++ test/OfflineIntegration.coffee
@@ -12,7 +12,7 @@
   request "http://localhost:3590/#{manifest_path}", (err, res, body) ->
     throw err if err
     test.strictEqual body.search("NETWORK:"), -1
-    test.strictEqual body.search("FALLBACKS:"), -1
+    test.strictEqual body.search("FALLBACK:"), -1
     console.log body
     test.done()
     app.close()


Tweaks

Tweaks

--- test/spec/ecosystem/backbone-relational.tests.coffee
+++ test/spec/ecosystem/backbone-relational.tests.coffee
@@ -967,7 +967,7 @@
   #   done()

   # https://github.com/kmalakoff/knockback/issues/122
-  it '13. Issue 122', (done) ->
+  it '14. Issue 122', (done) ->
     kb.statistics = new kb.Statistics() # turn on stats

     Model2 = Backbone.RelationalModel.extend({})
@@ -992,7 +992,7 @@
     done()

   # https://github.com/kmalakoff/knockback/issues/126
-  it '13. Issue 126', (done) ->
+  it '15. Issue 126', (done) ->
     kb.statistics = new kb.Statistics() # turn on stats

     root.Item = Item = Backbone.RelationalModel.extend({relations: [{type: Backbone.HasOne, key: 'related', relatedModel: 'OtherModel', includeInJSON: 'id'}]})
@@ -1012,4 +1012,5 @@
     ###########################
     done()

+
   it 'CLEANUP', -> kb.configure({orm: 'default'})


Also stop animations on close.

Also stop animations on close.

--- core/app/backbone/factlink/cross_fade_region.coffee
+++ core/app/backbone/factlink/cross_fade_region.coffee
@@ -3,6 +3,8 @@
 class Backbone.Factlink.CrossFadeRegion extends Backbone.Marionette.Region

   defaultFadeTime = 560
+
+  initialize: -> @on 'close', -> @$el?.stop()

   crossFade: (newView) ->
     if @currentView


Don't require keys for parts of an activity

--- core/app/backbone/views/feed_activities_view.coffee
+++ core/app/backbone/views/feed_activities_view.coffee
@@ -83,7 +83,7 @@
               user.get('name')
             ' '

-            this.props.activity_header_action
+            this.props.activity_header_action...

         _div ["feed-activity-content"],
            this.props.children


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color2.coffee
+++ src/color2.coffee
@@ -75,6 +75,10 @@
       b = hueToRgb(p, q, h - 1/3)

       rgbMap = (channel * 0xFF for channel in [r, g, b])
+
+      rgbMap[0] = rgbMap[0].round()
+      rgbMap[1] = rgbMap[1].round()
+      rgbMap[2] = rgbMap[2].round()

     return rgbMap.concat(a)

@@ -174,6 +178,8 @@
       [@r, @g, @b, @a] = hslToRgb(hsl)

       @r = @r.round()
+      @g = @g.round()
+      @b = @b.round()

       return this


Cached files based on the file ID and the method type (JSON or String) used for downloading them.

--- src/common.coffee
+++ src/common.coffee
@@ -134,16 +134,16 @@
 download = (method, fileId, collectionName) ->
   unless fileId?
     return Q.reject('No file ID given')
-  fileDf = fileCache[fileId]
+  fileDf = fileCache[fileId]?[method]
   unless fileDf
-    fileDf = fileCache[fileId] = Q.defer()
+    fileDf = fileCache[fileId][method] = Q.defer()
     _download(method, fileId, collectionName, 10)
   fileDf.promise.then(
     (data) -> Setter.clone(data)
   )

 _download = (method, fileId, collectionName, triesLeft) ->
-  fileDf = fileCache[fileId]
+  fileDf = fileCache[fileId][method]
   if triesLeft <= 0
     fileDf.reject('Could not download file ' + fileId + ' - no tries left.')
     return


Embedly: Fixes "Embedly links break profile view" bug

--- client/Social/Activity/views/embedbox/embedboxlinkviewdescription.coffee
+++ client/Social/Activity/views/embedbox/embedboxlinkviewdescription.coffee
@@ -33,8 +33,8 @@

   viewAppended:->
     JView::viewAppended.call this
-    if @getData().link_embed?.descriptionEdited
-      @editIndicator.show()
+    # if @getData().link_embed?.descriptionEdited
+    #   @editIndicator.show()

   click:(event)->


removed height property

removed height property

--- client/app/Applications/Account.kdapplication/account/accKiteList.coffee
+++ client/app/Applications/Account.kdapplication/account/accKiteList.coffee
@@ -113,7 +113,6 @@
       overlay   : yes
       cssClass  : "kite-kdmodal"
       width     : 500
-      height    : 233
       view      : form
       buttons   :
         "Create New Kite" :


No need event

No need event

--- client/landing/app/Applications/Inbox.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Inbox.kdapplication/AppController.coffee
@@ -164,7 +164,7 @@

   goToMessages:(message)->
     @getView().showTab "messages"
-    @mainView.propagateEvent KDEventType : 'MessageSelectedFromOutside', {item: message, event}
+    @mainView.propagateEvent KDEventType : 'MessageSelectedFromOutside', {item: message}

   selectMessage:(data, item, paneView)->
     @selection[data.getId()] = {


Fetch comments 10 by 10 asynchronously

Fetch comments 10 by 10 asynchronously

--- client/landing/app/CommonViews/comments/commentlistviewcontroller.coffee
+++ client/landing/app/CommonViews/comments/commentlistviewcontroller.coffee
@@ -3,26 +3,28 @@
     super
     @startListeners()

-  instantiateListItems:(items)->
+  instantiateListItems:(items, keepDeletedComments = no)->

     newItems = []

     for comment, i in items
-
+
       nextComment = items[i+1]

       skipComment = no
       if nextComment? and comment.deletedAt
         if Date.parse(nextComment.meta.createdAt) > Date.parse(comment.deletedAt)
           skipComment = yes
-
+
       if not nextComment and comment.deletedAt
         skipComment = yes
+
+      skipComment = no if keepDeletedComments

       unless skipComment
         commentView = @getListView().addItem comment
         newItems.push commentView
-
+
     return newItems

   startListeners:->
@@ -31,15 +33,38 @@
     listView.on 'ItemWasAdded', (view, index)=>
       view.on 'CommentIsDeleted', ->
         listView.emit "CommentIsDeleted"
-
+
     listView.on "AllCommentsLinkWasClicked", (commentHeader)=>

       # some problems when logged out server doesnt responds
       @utils.wait 5000, -> listView.emit "BackgroundActivityFinished"
-
-      @fetchAllComments 0, (err, comments)=>
-        @removeAllItems()
-        @instantiateListItems comments
+
+      {repliesCount} = listView.getData()
+
+      log "Total comment: ", repliesCount
+      stack = []
+      removedAlready = no
+
+      stack.push (callback) =>
+        listView.emit "BackgroundActivityStarted"
+        callback()
+
+      for xto in [0..repliesCount] by 10
+        do (xto) =>
+          stack.push (callback) =>
+            @fetchCommentsByRange xto, xto+10, (err, comments) =>
+              if not removedAlready
+                @removeAllItems()
+                removedAlready = yes
+              @instantiateListItems comments, yes
+              callback err, comments
+
+      async.parallel stack, (error, result) =>
+        listView.emit "BackgroundActivityFinished"
+        if not error
+          listView.emit "AllCommentsWereAdded"
+        else
+          log "Failed to get comments..."

     listView.registerListener
       KDEventTypes  : "CommentSubmitted"
@@ -60,9 +85,9 @@
     message.commentsByRange query,(err,comments)=>
       @getListView().emit "BackgroundActivityFinished"
       callback err,comments
-
+
   fetchAllComments:(skipCount=3, callback = noop)=>
-
+
     listView = @getListView()
     listView.emit "BackgroundActivityStarted"
     message = @getListView().getData()
@@ -70,7 +95,7 @@
       listView.emit "BackgroundActivityFinished"
       listView.emit "AllCommentsWereAdded"
       callback err, comments
-
+
   replaceAllComments:(comments)->
     @removeAllItems()
     @instantiateListItems comments


Fix logging typo

Fix logging typo

--- services/web/app/coffee/Features/Collaborators/CollaboratorsInviteHandler.coffee
+++ services/web/app/coffee/Features/Collaborators/CollaboratorsInviteHandler.coffee
@@ -82,7 +82,7 @@
 					if err?
 						logger.err {projectId, email}, "error sending messages for invite"
 				callback(null, invite)
-
+

 	revokeInvite: (projectId, inviteId, callback=(err)->) ->
 		logger.log {projectId, inviteId}, "removing invite"
@@ -104,7 +104,7 @@
 				return callback(null)
 			CollaboratorsInviteHandler._sendMessages projectId, sendingUser, invite, (err) ->
 				if err?
-					logger.err {projectid, inviteId}, "error resending invite messages"
+					logger.err {projectId, inviteId}, "error resending invite messages"
 					return callback(err)
 				callback(null)


More 404

More 404

--- src/proxy.coffee
+++ src/proxy.coffee
@@ -117,7 +117,9 @@
     "atelierzen.canalblog.com",
     "www.shipleyschool.org",
     "www.cropscience.bayer.com",
-    "www.bayer.com"
+    "www.bayer.com",
+    "www.chase.com",
+    "www.credit-agricole.fr"
 ]

 BLACKLIST_CONTENT = FS.readFileSync "#{__dirname}/../static/404.html"


Issue #12: add the strs function to the Atom plugin

--- tools/atom-plugin/language-micro/grammars/micro.cson
+++ tools/atom-plugin/language-micro/grammars/micro.cson
@@ -47,7 +47,7 @@
 	}
 	{
 		'comment': 'Built-in functions (it should be described before functions)'
-		'match': '\\b(nil|false|true|num|type|arity|apply|_|floor|ceil|trunc|round|sin|cos|tn|arcsin|arccos|arctn|angle|pow|sqrt|exp|ln|lg|abs|random|head|tail|keys|if|str|strb|strl|strh|strhh|args|env|time|in|out|outln|err|errln|exit)\\b'
+		'match': '\\b(nil|false|true|num|type|arity|apply|_|floor|ceil|trunc|round|sin|cos|tn|arcsin|arccos|arctn|angle|pow|sqrt|exp|ln|lg|abs|random|head|tail|keys|if|str|strb|strs|strl|strh|strhh|args|env|time|in|out|outln|err|errln|exit)\\b'
 		'name': 'variable.function.micro'
 	}
 	{


Added comment regarding the fact that the temporary bug fix should be eventually removed.

--- common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.coffee
+++ common/lib/xmodule/xmodule/js/src/videoalpha/display/video_player.coffee
@@ -74,6 +74,9 @@
     # when this change is requested (instead of simply requesting a speed change to 1.0). This has to
     # be done only when the video is being watched in Firefox. We need to figure out what browser is
     # currently executing this code.
+    #
+    # TODO: Check the status of http://code.google.com/p/gdata-issues/issues/detail?id=4654
+    #       When the YouTube team fixes the API bug, we can remove this temporary bug fix.
     @video.isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1

     if @video.videoType is 'html5'
@@ -252,6 +255,9 @@
     # or when we are in Firefox, and the new speed is 1.0. The second case is necessary to
     # avoid the bug where in Firefox speed switching to 1.0 in HTML5 player mode is handled
     # incorrectly by YouTube API.
+    #
+    # TODO: Check the status of http://code.google.com/p/gdata-issues/issues/detail?id=4654
+    #       When the YouTube team fixes the API bug, we can remove this temporary bug fix.
     if (@video.videoType is 'youtube') or ((@video.isFirefox) and (@video.playerType is 'youtube') and (newSpeed is '1.0'))
       if @isPlaying()
         @player.loadVideoById(@video.youtubeId(), @currentTime)


Reenable cli clearing spec

Reenable cli clearing spec

--- test/units/tasks/watch/watcher.spec.coffee
+++ test/units/tasks/watch/watcher.spec.coffee
@@ -43,7 +43,7 @@
       it 'should have closed the cli', ->
         expect(@watcher.cli.close).toHaveBeenCalled()

-    describe '#init', ->
+    describe '::init', ->

       given 'value', -> @promise.valueOf()
       given 'paths', -> fs.watch.argsForCall.map (a) -> a[0]
@@ -156,9 +156,9 @@
             beforeEach ->
               @watcher.keypressListener 'l', name: 'l', ctrl: true

-            xit 'should have cleared the terminal', ->
-              expect(logger.log)
-              .toHaveBeenCalledWith('\u001B[2J\u001B[0;0f')
+            it 'should have cleared the terminal', ->
+              expect(logger.log.argsForCall.last())
+              .toEqual(['\u001B[2J\u001B[0;0f\n', 0]  )

           describe 'when a sigint is triggered', ->
             beforeEach ->


add tests for empty element with format option

--- test/empty-element-test.coffee
+++ test/empty-element-test.coffee
@@ -2,35 +2,74 @@
 bHtml = require './'

 describe 'EmptyElement (</)', ->
-  it 'works', ->
-    source = '''
-      </img
-    '''
-    assert bHtml(source, format: 'demo') is ''
+  context '1', ->
+    it 'works', ->
+      source = '''
+
+        assert nodes.length is 1
+        assert nodes[0].type is 'empty element'
+        assert nodes[0].name is 'img'
+        assert nodes[0].attributes.length is 0
+        assert nodes[0].children.length is 0
+        assert.deepEqual options, { format }
+      bHtml source, { format }
+      assert bHtml(source) is ''
+      assert bHtml(source, format: 'demo') is ''

-    source = '''
-      </img
-        @src /images/sample.png
-    '''
-    assert bHtml(source) is ''
-    assert bHtml(source, format: 'demo') is '''
-
-    '''
+  context '2', ->
+    it 'works', ->
+      source = '''
+
+        assert nodes.length is 1
+        assert nodes[0].type is 'empty element'
+        assert nodes[0].name is 'img'
+        assert nodes[0].attributes.length is 1
+        assert nodes[0].attributes[0].type is 'attribute'
+        assert nodes[0].attributes[0].name is 'src'
+        assert nodes[0].attributes[0].value is '/images/sample.png'
+        assert nodes[0].children.length is 0
+        assert.deepEqual options, { format }
+      bHtml source, { format }
+      assert bHtml(source) is ''
+      assert bHtml(source, format: 'demo') is '''
+
+      '''

-    source = '''
-      </img
-        @alt sample
-        @src /images/sample.png
-    '''
-    assert bHtml(source) is ''
-    assert bHtml(source, format: 'demo') is '''
-
-    '''
+  context '3', ->
+    it 'works', ->
+      source = '''
+
+        assert nodes.length is 1
+        assert nodes[0].type is 'empty element'
+        assert nodes[0].name is 'img'
+        assert nodes[0].attributes.length is 2
+        assert nodes[0].attributes[0].type is 'attribute'
+        assert nodes[0].attributes[0].name is 'alt'
+        assert nodes[0].attributes[0].value is 'sample'
+        assert nodes[0].attributes[1].type is 'attribute'
+        assert nodes[0].attributes[1].name is 'src'
+        assert nodes[0].attributes[1].value is '/images/sample.png'
+        assert nodes[0].children.length is 0
+        assert.deepEqual options, { format }
+      bHtml source, { format }
+      assert bHtml(source) is ''
+      assert bHtml(source, format: 'demo') is '''
+
+      '''

   context '(errors)', ->
     it 'works', ->


fix(categories): Fix Sentry #11613

fix(categories): Fix Sentry #11613

--- src/flux/stores/category-store.coffee
+++ src/flux/stores/category-store.coffee
@@ -93,6 +93,7 @@
   getArchiveCategory: (accountOrId) ->
     return null unless accountOrId
     account = asAccount(accountOrId)
+    return null unless account

     if account.usesFolders()
       return @getStandardCategory(account.id, "archive")


Update view.coffee

Update view.coffee

--- app/assets/javascripts/app/content/view.coffee
+++ app/assets/javascripts/app/content/view.coffee
@@ -1,6 +1,7 @@
 class @Content extends Backbone.View

   renderItemFromUrl : (url, cb) ->
+    $(document).trigger 'before-content-render'
     @_updateHistory(url)
     $.get url, layout : false, (html) =>
       $contentItem = $(html)
@@ -56,4 +57,4 @@

 $ ->
   $(document).on 'page:load ready', () ->
-    Content.getInstance().bindClick $(document)+    Content.getInstance().bindClick $(document)


Refactoring to pass tests.

Refactoring to pass tests.

--- src/config.coffee
+++ src/config.coffee
@@ -9,6 +9,7 @@
     platform = if process.platform is 'win32' then 'USERPROFILE' else 'HOME'
     @file = path.join process.env[platform], '.snail'
     @open()
+    @config

   # Return contents of ~/.snail or return an empty object {}
   open: ->
@@ -27,6 +28,7 @@
   reset: ->
     @config = {}
     @save()
+    @config

   addHostname: (hostname) ->
     hostname = helpers.getHostname hostname
@@ -52,7 +54,10 @@
   addPlugin: (hostname, plugin_name, opts) ->
     hostname = helpers.getHostname hostname

-    if not @getHostname hostname
+    if not _.size opts
+      opts = {}
+
+    if @getPlugin hostname, plugin_name
       false
     else
       @config[hostname].push
@@ -63,23 +68,19 @@

   getPlugin: (hostname, plugin_name) ->
     hostname = helpers.getHostname hostname
+    plugins = @getHostname hostname

-    if not @getHostname hostname or not plugin_name
+    if not plugins or not plugin_name
       false
     else
-      plugins = @getHostname hostname
-      plugin = false
-      _.each plugins, (p) ->
-        if p.name is plugin_name
-          plugin = p
+      plugin = _.where plugins, { name : plugin_name }

-      if not _.isObject plugin
+      if not plugin.length
         false
-      else
-        plugin
+      else
+        plugin[0]

   updatePlugin: (hostname, plugin_name, opts) ->
-    console.log 'updatePlugin'
     hostname = helpers.getHostname hostname

     if not @getHostname hostname or not plugin_name
@@ -88,8 +89,6 @@
       if not @getPlugin hostname, plugin_name
         false
       else
-        #@deletePlugin hostname, plugin_name
-        #@addPlugin hostname, plugin_name, opts
         _.each opts, (val, key) ->
           @config[hostname][plugin]['opts'][key] = val


Rename typeFilters to schemaValidators; add typeless validators

--- src/config.coffee
+++ src/config.coffee
@@ -27,24 +27,25 @@
 module.exports =
 class Config
   EmitterMixin.includeInto(this)
-  @typeFilters = {}
-
-  @addTypeFilter: (typeName, filterFunction) ->
-    @typeFilters[typeName] ?= []
-    @typeFilters[typeName].push(filterFunction)
-
-  @addTypeFilters: (filters) ->
+  @schemaValidators = {}
+
+  @addSchemaValidator: (typeName, validatorFunction) ->
+    @schemaValidators[typeName] ?= []
+    @schemaValidators[typeName].push(validatorFunction)
+
+  @addSchemaValidators: (filters) ->
     for typeName, functions of filters
-      for name, filterFunction of functions
-        @addTypeFilter(typeName, filterFunction)
-
-  @executeTypeFilters: (value, schema) ->
+      for name, validatorFunction of functions
+        @addSchemaValidator(typeName, validatorFunction)
+
+  @executeSchemaValidators: (value, schema) ->
     failedValidation = false
     types = schema.type
     types = [types] unless Array.isArray(types)
     for type in types
       try
-        if filterFunctions = @typeFilters[type]
+        if filterFunctions = @schemaValidators[type]
+          filterFunctions = filterFunctions.concat(@schemaValidators['*'])
           for filter in filterFunctions
             value = filter.call(this, value, schema)
           failedValidation = false
@@ -394,34 +395,20 @@
       defaults

   scrubValue: (keyPath, value) ->
-    value = @constructor.executeTypeFilters(value, schema) if schema = @schemaForKeyPath(keyPath)
+    value = @constructor.executeSchemaValidators(value, schema) if schema = @schemaForKeyPath(keyPath)
     value

-Config.addTypeFilters
+Config.addSchemaValidators
   'integer':
     coercion: (value, schema) ->
       value = parseInt(value)
       throw new Error() if isNaN(value)
       value

-    minMaxCoercion: (value, schema) ->
-      if schema.minimum? and typeof schema.minimum is 'number'
-        value = Math.max(value, schema.minimum)
-      if schema.maximum? and typeof schema.maximum is 'number'
-        value = Math.min(value, schema.maximum)
-      value
-
   'number':
     coercion: (value, schema) ->
       value = parseFloat(value)
       throw new Error() if isNaN(value)
-      value
-
-    minMaxCoercion: (value, schema) ->
-      if schema.minimum? and typeof schema.minimum is 'number'
-        value = Math.max(value, schema.minimum)
-      if schema.maximum? and typeof schema.maximum is 'number'
-        value = Math.min(value, schema.maximum)
       value

   'boolean':
@@ -448,7 +435,7 @@
       throw new Error() if typeof value isnt 'object'
       return value unless schema.properties?
       for prop, childSchema of schema.properties
-        value[prop] = @executeTypeFilters(value[prop], childSchema) if prop of value
+        value[prop] = @executeSchemaValidators(value[prop], childSchema) if prop of value
       value

   'array':
@@ -456,6 +443,15 @@
       throw new Error() unless Array.isArray(value)
       itemSchema = schema.items
       if itemSchema?
-        @executeTypeFilters(item, itemSchema) for item in value
+        @executeSchemaValidators(item, itemSchema) for item in value
       else
         value
+
+  '*':
+    minimumAndMaximumCoercion: (value, schema) ->
+      return value unless typeof value is 'number'
+      if schema.minimum? and typeof schema.minimum is 'number'
+        value = Math.max(value, schema.minimum)
+      if schema.maximum? and typeof schema.maximum is 'number'
+        value = Math.min(value, schema.maximum)
+      value


Fix Config::getSettings

Fix Config::getSettings

--- src/config.coffee
+++ src/config.coffee
@@ -608,7 +608,7 @@
   # defaults. Returns the scoped settings when a `scopeSelector` is specified.
   getSettings: ->
     deprecate "Use ::get(keyPath) instead"
-    _.deepExtend(@settings, @defaultSettings)
+    _.deepExtend({}, @settings, @defaultSettings)

   # Extended: Get the {String} path to the config file being used.
   getUserConfigPath: ->


Simplfy iterate

Simplfy iterate

--- client/app/MainApp/filetree/controllers/findercontroller.coffee
+++ client/app/MainApp/filetree/controllers/findercontroller.coffee
@@ -251,16 +251,16 @@
     callback {message:"Folder not exists: #{folderPath}"}

   reloadPreviousState:(vmName)->
-    iterate = (folders, index)=>
+    iterate = (folders, index=0)=>
       @expandFolder folders[index], (err)=>
         if err then @unsetRecentFolder folders[index]
-        index += 1
+        index++
         iterate folders, index  if index <= folders.length
     recentFolders = @getRecentFolders()
     if vmName
       recentFolders = recentFolders.filter (folder)->
         folder.indexOf "[#{vmName}]" is 0
-    iterate recentFolders, 0
+    iterate recentFolders

   _pipedVmName:(vmName)-> vmName.replace /\./g, '|'


Removed bundling logic

Removed bundling logic

--- core/app/backbone/views/activities/activities_group_view.coffee
+++ core/app/backbone/views/activities/activities_group_view.coffee
@@ -1,4 +1,8 @@
 class window.ActivitiesGroupView extends Backbone.Marionette.CompositeView
+  className: 'activity-group'
+  itemView: Backbone.View
+  itemViewContainer: ".js-region-activities"
+
   @new: (options)->
     new (@classForModel(options.model))(options)

@@ -14,7 +18,7 @@
       if action in group_view.actions
         return group_view

-    return UserActivitiesGroupView
+    return ActivitiesGroupView

   templateHelpers: ->
     user: @user?.toJSON()
@@ -26,52 +30,16 @@

   actions: -> []

-  appendable: (model) -> model.get('action') in @actions()
-
-  tryAppend: (model) ->
-    return false unless @appendable(model)
-    @append model
-    true
-
-  append: (model) ->
-    unless @lastView?.tryAppend(model)
-      @collection.add model
-
-class UserActivitiesGroupView extends ActivitiesGroupView
-  className: 'activity-group'
-  itemView: Backbone.View
-  itemViewContainer: ".js-region-activities"
-
-  constructor: ->
-    super
-    @on 'render', @makeUserTooltip
-
-  itemViewOptions: ->
-    $offsetParent: @$el
-
-  sameUser: (model) -> @model.user().get('username') == model.user().get('username')
-
-  appendable: (model) -> super(model) and @sameUser(model)
+  tryAppend: (model) -> return false

   buildItemView: (item, ItemView, itemViewOptions) ->
     options = _.extend({model: item}, itemViewOptions)
     @lastView = ActivityItemView.for(options)

-  activityMadeRedundantBy: (newActivity, oldActivity) -> false
-  newActivityIsRedundant: (newActivity) ->
-    return false unless @collection.models.length > 1
-    @activityMadeRedundantBy newActivity,
-      @collection.models[@collection.length - 2]
-
-  appendHtml: (collectionView, itemView, index) ->
-    return if @newActivityIsRedundant(itemView.model)
-    super
-
-class UserFactActivitiesGroupView extends UserActivitiesGroupView
+class UserFactActivitiesGroupView extends ActivitiesGroupView
   template: 'activities/user_fact_activities_group'

-  @actions: ["created_comment", "created_sub_comment", "believes", "disbelieves", "doubts"]
-  actions: -> UserFactActivitiesGroupView.actions
+  @actions: ["created_comment", "created_sub_comment"]

   onRender: ->
     @$('.js-region-fact').html @factView().render().el
@@ -86,27 +54,8 @@

   fact: -> new Fact @model.get("activity").fact

-  sameFact: (model) ->
-    @model.get('activity').fact?.id == model.get('activity').fact?.id
-
-  appendable: (model) -> super(model) and @sameFact(model)
-
-  isOpinion: (activity) ->
-    activity.get('action') in ['believes', 'disbelieves', 'doubts']
-
-  isAddedArgument: (activity) ->
-    activity.get('action') == "created_comment"
-
-  activityMadeRedundantBy: (newActivity, oldActivity) ->
-    @isOpinion(oldActivity) && @isOpinion(newActivity) ||
-      @isAddedArgument(oldActivity) && @isAddedArgument(newActivity)
-
-class UsersFollowedGroupView extends UserActivitiesGroupView
+class UsersFollowedGroupView extends ActivitiesGroupView
   template: 'activities/users_followed_group'

   @actions: ["followed_user"]
-  actions: -> UsersFollowedGroupView.actions

-  activityMadeRedundantBy: (newActivity, oldActivity) ->
-    newActivity.get('activity').followed_user.username ==
-      oldActivity.get('activity').followed_user.username


Added sin and cos to the glsl api

Added sin and cos to the glsl api

--- src/generator/compile.glsl.api.coffee
+++ src/generator/compile.glsl.api.coffee
@@ -38,6 +38,18 @@
       else
         "abs(#{glsl.literal a})"

+    cos: (a) ->
+      if typeof a == 'number'
+        Math.cos a
+      else
+        "cos(#{a})"
+
+    sin: (a) ->
+      if typeof a == 'number'
+        Math.sin a
+      else
+        "sin(#{a})"
+
     dot: (a, b) ->
       if typeof a == 'string' or typeof b == 'string'
         "dot(#{a}, #{b})"


Forgot the `func` argument.

Forgot the `func` argument.

--- src/spine.coffee
+++ src/spine.coffee
@@ -71,7 +71,7 @@
     obj.extended?.apply(@)
     this

-  @proxy: ->
+  @proxy: (func) ->
     => func.apply(@, arguments)

   proxy: (func) ->


Fixes #4046 - Core Workflow - Unable to select "has changed" logic when creating new workflow. It is also replaced with "is" in previously created workflows.

--- app/assets/javascripts/app/controllers/_ui_element/core_workflow_condition.coffee
+++ app/assets/javascripts/app/controllers/_ui_element/core_workflow_condition.coffee
@@ -50,16 +50,16 @@

     operatorsType =
       'active$': [__('is')]
-      'boolean$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to')]
-      'integer$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to')]
-      '^select$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to')]
+      'boolean$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to')]
+      'integer$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to')]
+      '^select$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to')]
       '^multiselect$': [__('contains'), __('contains not'), __('contains all'), __('contains all not'), __('is set'), __('not set'), __('has changed'), __('changed to')]
-      '^tree_select$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to')]
-      '^(input|textarea|richtext)$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to'), __('regex match'), __('regex mismatch')]
+      '^tree_select$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to')]
+      '^(input|textarea|richtext)$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to'), __('regex match'), __('regex mismatch')]

     operatorsName =
-      '_id$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to')]
-      '_ids$': [__('is'), __('is not'), __('is set'), __('not set'), _('has changed'), __('changed to')]
+      '_id$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to')]
+      '_ids$': [__('is'), __('is not'), __('is set'), __('not set'), __('has changed'), __('changed to')]

     # merge config
     elements = {}


remove useless code

remove useless code

--- src/project/states/main/controller.coffee
+++ src/project/states/main/controller.coffee
@@ -79,7 +79,7 @@
     $scope.project.save().then (savedProject) ->
       user.project = savedProject
       user.save().then ->
-        $scope.$emit 'project:update', {project: savedProject, nextState: 'tab.board'}
+        $scope.$emit 'project:update', nextState: 'tab.board'
       .catch ->
         $scope.saving = false
     .catch ->


Don't add view specimen if constructor filepath isn't found

--- app/assets/javascripts/xray-backbone.js.coffee
+++ app/assets/javascripts/xray-backbone.js.coffee
@@ -9,8 +9,8 @@
 _ensureElement = Backbone.View::_ensureElement
 Backbone.View::_ensureElement = ->
   _.defer =>
-    info = Xray.constructorInfo @constructor
-    Xray.ViewSpecimen.add @el, info
+    if info = Xray.constructorInfo @constructor
+      Xray.ViewSpecimen.add @el, info
   _ensureElement.apply(this, arguments)

 # Cleanup when view is removed.


move methods around, add invariant for Store.set(name, undefined)

--- src/store.coffee
+++ src/store.coffee
@@ -63,7 +63,7 @@
 			# Check if the function is a reference to a prototype method, and warn.
 			for own prop of (@::) when fn is @::[prop]
 				console.warn """
-					Store.action(...): Action %s is referring to a method on the store prototype (%o).
+					Store.action(...): Action %s is referring to a method on the store prototype (%O).
 					This is bad practice and should be avoided.
 					The handler itself may call prototype methods,
 					and is called with the store instance as context for that reason.
@@ -94,6 +94,23 @@
 				val = _.cloneDeep @_properties
 			return val

+		set: (name, val) ->
+			invariant _.isObject(name) or _.isString(name) and val?,
+				"""
+					Store.set(...): You can only set an object or pass a string and a value.
+					Use Store.unset(#{name}) to unset the property.
+				"""
+			if _.isString(name)
+				properties = {}
+				properties[name] = val
+			if _.isObject(name)
+				properties = name
+			newProps =  _.cloneDeep properties
+			_.assign @_properties, newProps
+
+			@changed.dispatch 'set', newProps
+
+			return @

 		merge: (name, val) ->
 			if _.isString(name)
@@ -106,19 +123,6 @@

 			changedProps = _.pick @_properties, _.keys(newProps)
 			@changed.dispatch 'merge', changedProps
-
-			return @
-
-		set: (name, val) ->
-			if _.isString(name)
-				properties = {}
-				properties[name] = val
-			if _.isObject(name)
-				properties = name
-			newProps =  _.cloneDeep properties
-			_.assign @_properties, newProps
-
-			@changed.dispatch 'set', newProps

 			return @


Cursor::getScopes -> Cursor::getScopeDescriptor

--- src/cursor.coffee
+++ src/cursor.coffee
@@ -198,7 +198,7 @@
     [before, after] = @editor.getTextInBufferRange(range)
     return false if /\s/.test(before) or /\s/.test(after)

-    nonWordCharacters = atom.config.get(@getScopes(), 'editor.nonWordCharacters').split('')
+    nonWordCharacters = atom.config.get(@getScopeDescriptor(), 'editor.nonWordCharacters').split('')
     _.contains(nonWordCharacters, before) isnt _.contains(nonWordCharacters, after)

   # Public: Returns whether this cursor is between a word's start and end.
@@ -214,11 +214,14 @@
     else
       @getBufferColumn()

-  # Public: Retrieves the grammar's token scopes for the line.
+  # Public: Retrieves the scope descriptor for the cursor's current position.
   #
   # Returns an {Array} of {String}s.
+  getScopeDescriptor: ->
+    @editor.scopeDescriptorForBufferPosition(@getBufferPosition())
   getScopes: ->
-    @editor.scopesForBufferPosition(@getBufferPosition())
+    deprecate 'Use Cursor::getScopeDescriptor() instead'
+    @getScopeDescriptor()

   # Public: Returns true if this cursor has no non-whitespace characters before
   # its current position.
@@ -617,7 +620,7 @@
   # Returns a {RegExp}.
   wordRegExp: ({includeNonWordCharacters}={}) ->
     includeNonWordCharacters ?= true
-    nonWordCharacters = atom.config.get(@getScopes(), 'editor.nonWordCharacters')
+    nonWordCharacters = atom.config.get(@getScopeDescriptor(), 'editor.nonWordCharacters')
     segments = ["^[\t ]*$"]
     segments.push("[^\\s#{_.escapeRegExp(nonWordCharacters)}]+")
     if includeNonWordCharacters


remove logs

remove logs

--- app/assets/javascripts/angular/shared/submit_form.js.coffee
+++ app/assets/javascripts/angular/shared/submit_form.js.coffee
@@ -11,9 +11,7 @@

     displayErrors: ($form, data) =>
       errors = @formatErrors(data)
-      console.log errors
       for input, messages of errors
-        console.log input, messages
         $input = $form.find("input[name=#{input}], input[name*=\"[#{input}]\"], select[name=#{input}], select[name*=\"[#{input}]\"], textarea[name=#{input}], textarea[name*=\"[#{input}]\"]")

         if $input.length > 0


refs #311 現在のユーザの状態の初期値の誤りを修正

refs #311 現在のユーザの状態の初期値の誤りを修正

--- app/assets/javascripts/components/sheets/sheet_list.js.cjsx
+++ app/assets/javascripts/components/sheets/sheet_list.js.cjsx
@@ -8,7 +8,7 @@
       renderAds: UserStore.renderAds()
       viewport: EnvironmentStore.findBy 'viewport'
       reverse: EnvironmentStore.findBy 'reverseSheet'
-      currentUser: {}
+      currentUser: UserStore.get()

   onChangeViewPortAndReverse: =>
     @setState


Fix gravatar to show mystery man if no email is present

--- app/assets/javascripts/directives/gravatar_directive.coffee
+++ app/assets/javascripts/directives/gravatar_directive.coffee
@@ -6,8 +6,8 @@
     linker = ($scope, $element, $attrs)->
       email = size = null
       setGravatarSrc = (email, size)->
-        if email?
-          $element.attr('src', Gravtastic(email, default: 'mm', size: (size ||= 22)))
+        email = "" unless email?
+        $element.attr('src', Gravtastic(email, default: 'mm', size: (size ||= 22)))

       updateEmail = (newEmail)->
         return if newEmail == email


MasterIO: Add some debugging

MasterIO: Add some debugging

--- src/streammachine/master/master_io.coffee
+++ src/streammachine/master/master_io.coffee
@@ -1,4 +1,6 @@
 _ = require "underscore"
+
+debug = require("debug")("sm:master:master_io")

 module.exports = class MasterIO extends require("events").EventEmitter
     constructor: (@master,@log,@opts) ->
@@ -34,20 +36,23 @@

         # add our authentication
         @io.use (socket,next) =>
-            @log.silly "Authenticating slave connection."
+            debug "Authenticating slave connection."
             if @opts.password == socket.request._query?.password
-                @log.silly "Slave password is valid."
+                debug "Slave password is valid."
                 next()
             else
                 @log.debug "Slave password is incorrect."
+                debug "Slave password is incorrect."
                 next new Error "Invalid slave password."

         # look for slave connections
         @io.on "connection", (sock) =>
-            @log.silly "Master got connection"
+            debug "Master got connection"
             # a slave may make multiple connections to test transports. we're
             # only interested in the one that gives us the OK
             sock.once "ok", (cb) =>
+                debug "Got OK from incoming slave connection at #{sock.id}"
+
                 # ping back to let the slave know we're here
                 cb "OK"


Remove unnecessary params from Editor::getScrollWidth

--- src/editor.coffee
+++ src/editor.coffee
@@ -2040,7 +2040,7 @@
   setScrollRight: (scrollRight) -> @displayBuffer.setScrollRight(scrollRight)

   getScrollHeight: -> @displayBuffer.getScrollHeight()
-  getScrollWidth: (scrollWidth) -> @displayBuffer.getScrollWidth(scrollWidth)
+  getScrollWidth: -> @displayBuffer.getScrollWidth()

   getVisibleRowRange: -> @displayBuffer.getVisibleRowRange()


follow docs

follow docs

--- src/follow.coffee
+++ src/follow.coffee
@@ -3,7 +3,7 @@
 velocity so that it will approach another object.

-# follow relies on an object having a bou
+#
 player = GameObject
   x: 50
   y: 50


follow docs

follow docs

--- src/follow.coffee
+++ src/follow.coffee
@@ -11,7 +11,7 @@
   width: 10
   height: 10

-
+enemy =

 player.update()
 </pre></code>


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/follow.coffee
+++ src/follow.coffee
@@ -65,5 +65,5 @@
   @param {GameObject} obj The object you want to follow
   ###
   follow: (obj) ->
-    if
-    I.velocity = obj.position().subtract(self.position()).norm(I.speed)
+    if obj
+      I.velocity = obj.position().subtract(self.position()).norm(I.speed)


creates block but doesnt update yet

creates block but doesnt update yet

--- apps/channel/client/block_skeleton_view.coffee
+++ apps/channel/client/block_skeleton_view.coffee
@@ -2,6 +2,7 @@
 _ = require 'underscore'
 sd = require("sharify").data
 mediator = require '../../../lib/mediator.coffee'
+Block = require '../../../models/block.coffee'
 BlockView = require '../../../components/block_collection/client/block_view.coffee'

 module.exports = class BlockSkeletonView extends Backbone.View
@@ -15,9 +16,18 @@
     @collection.on "merge:skeleton", @renderSkeleton, @
     @collection.on "placeholders:replaced", @completeRequest, @

+    mediator.on 'upload:done', @makeBlock, @
+
     @collection.loadSkeleton()

     super
+
+  makeBlock: (location) ->
+    console.log 'makeBlock'
+    block = new Block block_type: "Block", source: location
+    @collection.create block.toJSON(),
+      url: "#{sd.API_URL}/channels/#{@channel.get('slug')}/blocks"
+      wait: true

   appendBlock: (model)->
     containerMethod = if model?.options?.wait is true then 'after' else 'append'


Add point in frame function to utils

Add point in frame function to utils

--- src/utils.coffee
+++ src/utils.coffee
@@ -186,8 +186,10 @@
 		x: Math.abs point.x
 		y: Math.abs point.y

-exports.pointInRect = (point, rect) ->
-	alert "Not implemented, you lazy man"
+exports.pointInFrame = (point, frame) ->
+	return false  if point.x < frame.minX or point.x > frame.maxX
+	return false  if point.y < frame.minY or point.y > frame.maxY
+	true

 exports.convertPoint = (point, view1, view2) ->


416: Refactor JS

416: Refactor JS

--- app/assets/javascripts/backbone/views/file_upload_view.coffee
+++ app/assets/javascripts/backbone/views/file_upload_view.coffee
@@ -36,19 +36,17 @@
   fileAdded: (file, dz) ->
     dz.removeFile(dz.files[0]) if dz.files[1] # Replace existing dragged file if present
     @dzForm.addClass('existing-deleted') if @dzForm.is('.has-existing')
-    @mainForm.find("[id$=_#{@attrib}_new_signed_id]").val('') # Will be set when upload finished
+    @setSignedId('') # Will be set when upload finished
     @setDestroyFlag(false)

   fileUploaded: (file, response, dz) ->
-    @mainForm.find("[id$=_#{@attrib}_new_signed_id]").val(response.blob_id)
-    @mainForm.find("[id$=_#{@attrib}_destroy]").val('')
+    @setSignedId(response.blob_id)
     @errorForm.hide()

   delete: (e) ->
     e.preventDefault()
     @setDestroyFlag(true)
-    @mainForm.find("[id$=_#{@attrib}_new_signed_id]").val('')
-    @mainForm.find("[id$=_#{@attrib}_destroy]").val('1')
+    @setSignedId('')
     @dzForm.addClass('existing-deleted')
     @dropzone.removeFile(@dropzone.files[0]) if @hasNewFile()

@@ -56,9 +54,11 @@
     !!@dropzone.files[0]

   setDestroyFlag: (bool) ->
-    if @dzForm.is('.has-existing')
-      @destroyFlag = bool
-      @mainForm.find("[id$=_#{@attrib}_destroy]").val(if bool then '1' else '0')
+    @destroyFlag = bool
+    @mainForm.find("[id$=_#{@attrib}_destroy]").val(if bool then '1' else '0')
+
+  setSignedId: (id) ->
+    @mainForm.find("[id$=_#{@attrib}_new_signed_id]").val(id)

   showExisting: (bool) ->
     @dzForm.find('.existing')[if bool then 'show' else 'hide']()


Remove obsolete 'this'

Remove obsolete 'this'

--- app/assets/javascripts/components/validation_errors.js.coffee
+++ app/assets/javascripts/components/validation_errors.js.coffee
@@ -3,11 +3,11 @@
   constructor: (props, context) ->
     super(props, context)
     @state = {
-      data: @props.validationErrors,
+      data: props.validationErrors,
       numToShow: 5
       showAllErrors: false
       hideAll: false
-      ignored: @props.ignored
+      ignored: props.ignored
     }
     @toggleBox = @toggleBox.bind(@)
     @showMoreErrors = @showMore.bind(@)