working on NewAnalyzer

working on NewAnalyzer

* remove unnecessary comments

--- src/NewAnalyzer.coffee
+++ src/NewAnalyzer.coffee
@@ -8,21 +8,11 @@
     openParenthesis: '('
     closeParenthesis: ')'

-  # crntChar = undefined
-
-  # # current char status
-  # quote            =
-  # escape           =
-  # endOfLine        =
-  # doubleQuote      =
-  # openParenthesis  =
-  # closeParenthesis = undefined
-
   # string position status
-  inDsl       =
   dumped      =
   escaped     =
-  inString    = undefined
+  inString    =
+  inDslParams = undefined
   parentheses = []

   get = (name)-> eval name
@@ -77,11 +67,3 @@
       return -> get(name)

     (char)-> e('newChar').emitWith char
-      # dump(char)
-      # callInChain(
-      #   escapeTracker
-      #   charFilter
-      #   stringTracker
-      #   parenthesesTracker
-      #   dslTracker
-      # )


Make WheelZoomTool active unless other tool is active

--- bokehjs/src/coffee/tool/event_generators.coffee
+++ bokehjs/src/coffee/tool/event_generators.coffee
@@ -168,13 +168,12 @@
       @eventSink = eventSink
       @plotview.canvas_wrapper.bind("mousewheel",
         (e, delta, dX, dY) =>
-          if not @tool_active
-            return
-          set_bokehXY(e)
-          e.delta = delta
-          eventSink.trigger("#{toolName}:zoom", e)
-          e.preventDefault()
-          e.stopPropagation())
+          if @tool_active or not @eventSink.active
+            set_bokehXY(e)
+            e.delta = delta
+            eventSink.trigger("#{toolName}:zoom", e)
+            e.preventDefault()
+            e.stopPropagation())

       $(document).bind('keydown', (e) =>
         #disable the tool when ESC is pressed


Implement find_by in JS store

Implement find_by in JS store

--- app/assets/javascripts/rglossa/react/store.coffee
+++ app/assets/javascripts/rglossa/react/store.coffee
@@ -20,21 +20,34 @@

   find: (model, id) ->
+    @findBy(model, 'id', id)
+
+  # Looks up the model in the store by the given attribute, assuming that this attribute
+  # will be the one that is used as the key in the store. If the model is not already
+  # loaded, we send a request to the server to fetch it. If the attribute is 'id', we
+  # use the normal RESTful plural-model-name/id approach which will cause the 'show' method
+  # to be called in Rails; otherwise we use plural-model-name/find_by?attribute=value, which
+  # will have to be supported by the Rails controller for the resouce.
+  findBy: (model, attribute, value) ->
     plural = @getPlural(model)
-    data = @models[plural][id]
+    data = @models[plural][value]
     return data if data?  # Store already contains the model

     # Store does not already contain the model, so fetch it
-    url = "#{plural}/#{id}"
+    url = if attribute is 'id'
+            "#{plural}/#{value}"
+          else
+            "#{plural}/find_by?#{attribute}=#{value}"
+
     $.getJSON(url)
       .done( (res) =>
-        @setData(model, id, res[model])
+        @setData(model, value, res[model])
       )
       .fail -> alert('Error fetching data from the server. Please reload the page.')

     # Return null since the store did not contain the model. When the model has been
-    # loaded, @storeChangedHandler will be called, and then the client can call `find`
-    # again to retrieve the model.
+    # loaded, @storeChangedHandler will be called (via @setData), and then the client
+    # can call `find` again to retrieve the model.
     null


allow cancelation of rails ujs events by bubbling up return values to subsequent event handlers

--- app/assets/javascripts/s3_direct_upload.js.coffee
+++ app/assets/javascripts/s3_direct_upload.js.coffee
@@ -74,10 +74,22 @@
             type: $uploadForm.data('callback-method')
             url: callback_url
             data: content
-            beforeSend: ( xhr, settings )       -> $uploadForm.trigger( 'ajax:beforeSend', [xhr, settings] )
-            complete:   ( xhr, status )         -> $uploadForm.trigger( 'ajax:complete', [xhr, status] )
-            success:    ( data, status, xhr )   -> $uploadForm.trigger( 'ajax:success', [data, status, xhr] )
-            error:      ( xhr, status, error )  -> $uploadForm.trigger( 'ajax:error', [xhr, status, error] )
+            beforeSend: ( xhr, settings )       ->
+              event = $.Event('ajax:beforeSend')
+              $uploadForm.trigger(event, [xhr, settings])
+              return event.result
+            complete:   ( xhr, status )         ->
+              event = $.Event('ajax:complete')
+              $uploadForm.trigger(event, [xhr, status])
+              return event.result
+            success:    ( data, status, xhr )   ->
+              event = $.Event('ajax:success')
+              $uploadForm.trigger(event, [data, status, xhr])
+              return event.result
+            error:      ( xhr, status, error )  ->
+              event = $.Event('ajax:error')
+              $uploadForm.trigger(event, [xhr, status, error])
+              return event.result

         data.context.remove() if data.context && settings.remove_completed_progress_bar # remove progress bar
         $uploadForm.trigger("s3_upload_complete", [content])


Squashed 'subtree/bokehjs/' changes from 074d4ef..fa902cc

fa902cc Removing calls to no_scroll and restore_scroll in EventGenerators, because the addition of the hidden class was causing layout issues for the Zoom and Save tools

git-subtree-dir: subtree/bokehjs
git-subtree-split: fa902ccbeca20870c19b590507471f4da19819f0

--- static/coffee/tools/eventgenerators.coffee
+++ static/coffee/tools/eventgenerators.coffee
@@ -202,13 +202,11 @@
       @tool_active=false;
       @button_activated = false;
       @$tool_button.removeClass('active')
-      restore_scroll(@plotview.$el[0])
       document.body.style.overflow = @old_overflow)

     eventSink.on("#{toolName}:activated", =>
       @tool_active=true;
-      @$tool_button.addClass('active')
-      no_scroll(@plotview.$el[0]))
+      @$tool_button.addClass('active'))

     return eventSink

@@ -272,13 +270,11 @@
       @tool_active=false;
       @button_activated = false;
       @$tool_button.removeClass('active')
-      restore_scroll(@plotview.$el[0])
       document.body.style.overflow = @old_overflow)

     eventSink.on("#{toolName}:activated", =>
       @tool_active=true;
-      @$tool_button.addClass('active')
-      no_scroll(@plotview.$el[0]))
+      @$tool_button.addClass('active'))

     return eventSink


rename variables

rename variables

--- zechat/static/peers.coffee
+++ zechat/static/peers.coffee
@@ -61,15 +61,15 @@
       if packet.recipient == @identity.fingerprint()
         @on_message(packet.data)

-  on_message: (data) ->
-    unpacked_data = JSON.parse(zc.b64decode(data))
-    message = JSON.parse(zc.b64decode(unpacked_data.message))
-    sender = new zc.Crypto(unpacked_data.sender_key)
+  on_message: (packed_data) ->
+    data = JSON.parse(zc.b64decode(packed_data))
+    message = JSON.parse(zc.b64decode(data.message))
+    sender = new zc.Crypto(data.sender_key)

-    sender.verify(unpacked_data.message, unpacked_data.signature)
+    sender.verify(data.message, data.signature)
     .then (ok) =>
       unless ok
-        @trigger('verification-failed', data)
+        @trigger('verification-failed', packed_data)
         return

       sender.fingerprint()
@@ -81,20 +81,20 @@
     .done()

   send: (peer, contents) ->
-    message = zc.b64encode(JSON.stringify(contents))
+    packed_message = zc.b64encode(JSON.stringify(contents))

-    @identity.crypto().sign(message)
+    @identity.crypto().sign(packed_message)

     .then (signature) =>
-      data = zc.b64encode(JSON.stringify(
-        message: message
+      data = {
+        message: packed_message
         sender_key: @identity.public_key()
         signature: signature
-      ))
+      }
       @transport.send(
         type: 'message'
         recipient: peer.get('fingerprint')
-        data: data
+        data: zc.b64encode(JSON.stringify(data))
       )

     .done()


remove bug-tagged class on bug tag removed.

--- client/Social/Activity/views/inputwidget.coffee
+++ client/Social/Activity/views/inputwidget.coffee
@@ -18,7 +18,7 @@
     # FIXME we need to hide bug warning in a proper way ~ GG
     @input.on "keyup", =>
       val = @input.getValue()
-      # @unsetClass 'bug-tagged'  if val.indexOf("5051003840118f872e001b91") is -1
+      @unsetClass 'bug-tagged'  if val.indexOf("5051003840118f872e001b91") is -1

     @on "ActivitySubmitted", =>
       @unsetClass "bug-tagged"


PrivateMessage: Fixes "Realtime private messages are received from wrong channel" bug

--- client/Social/Activity/views/messagepane.coffee
+++ client/Social/Activity/views/messagepane.coffee
@@ -25,8 +25,8 @@
     @createInputWidget()

     {socialapi} = KD.singletons
+    @once 'ChannelReady', @bound 'bindChannelEvents'
     socialapi.onChannelReady data, @lazyBound 'emit', 'ChannelReady'
-    @once 'ChannelReady', @bound 'bindChannelEvents'

     @on 'LazyLoadThresholdReached', @bound 'lazyLoad'  if typeConstant in ['group', 'topic']


client: call fetch group invoices from payment controller

--- client/app/lib/payment/paymentcontroller.coffee
+++ client/app/lib/payment/paymentcontroller.coffee
@@ -47,6 +47,9 @@

   invoices: (callback) -> @api().invoices {}, callback
+
+
+  fetchGroupInvoices: (callback) -> @api().fetchGroupInvoices {}, callback

   creditCard: (callback) ->


Better regex to match - and other non word characters

--- client/apps/edit/components/layout/index.coffee
+++ client/apps/edit/components/layout/index.coffee
@@ -140,7 +140,7 @@

   getLinkableText: ->
     fullText = @getBodyText()
-    fullText.match(/==(\S+[\w|\s]*?\S)==/ig)
+    fullText.match(/==(\S+.*?\S)==/ig)

   autolinkText: ->
     $('#autolink-status').addClass('searching').html('Linking...')


delete require PageForm

delete require PageForm

--- components/page.cjsx
+++ components/page.cjsx
@@ -5,7 +5,6 @@
 ReactDOM = require 'react-dom'
 PageTitle = require './pagetitle'
 PageContent = require './pagecontent.jsx'
-PageForm = require './pageform.jsx'

 App = React.createClass
   getInitialState: ->


Home: registration form code styling

Home: registration form code styling

--- client/Main/CommonViews/login/registerform.coffee
+++ client/Main/CommonViews/login/registerform.coffee
@@ -32,20 +32,20 @@
           container      : this
           rules          :
             required     : yes
-            rangeLength  : [4,25]
+            rangeLength  : [4, 25]
             regExp       : /^[a-z\d]+([-][a-z\d]+)*$/i
             usernameCheck: (input, event)=> @usernameCheck input, event
             finalCheck   : (input, event)=> @usernameCheck input, event, 0
           messages       :
-            required     : "Please enter a username."
-            regExp       : "For username only lowercase letters and numbers are allowed!"
-            rangeLength  : "Username should be between 4 and 25 characters!"
+            required     : 'Please enter a username.'
+            regExp       : 'For username only lowercase letters and numbers are allowed!'
+            rangeLength  : 'Username should be between 4 and 25 characters!'
           events         :
-            required     : "blur"
-            rangeLength  : "keyup"
-            regExp       : "keyup"
-            usernameCheck: "keyup"
-            finalCheck   : "blur"
+            required     : 'blur'
+            rangeLength  : 'blur'
+            regExp       : 'keyup'
+            usernameCheck: 'keyup'
+            finalCheck   : 'blur'
         decorateValidation: no

     {buttonTitle} = @getOptions()
@@ -53,14 +53,14 @@
     @button = new KDButtonView
       title         : buttonTitle or 'Create account'
       type          : 'submit'
-      style         : "solid green medium"
+      style         : 'solid green medium'
       loader        : yes
       callback      : @bound 'submitForm'

     @invitationCode = new LoginInputView
-      cssClass      : "hidden"
+      cssClass      : 'hidden'
       inputOptions  :
-        name        : "inviteCode"
+        name        : 'inviteCode'
         type        : 'hidden'

     @domain = new KDCustomHTMLView
@@ -107,6 +107,49 @@
             else
               input.setValidationResult "usernameCheck", null

+
+  getEmailValidator: ->
+    container   : this
+    event       : 'blur'
+    rules       :
+      required  : yes
+      email     : yes
+      available : (input, event) =>
+        return if event?.which is 9
+        input.setValidationResult 'available', null
+        email = input.getValue()
+        if input.valid
+          # @email.loader.show()
+          KD.remote.api.JUser.emailAvailable email, (err, response)=>
+            # @email.loader.hide()
+            if err then warn err
+            else
+              if response
+                input.setValidationResult "available", null
+              else
+                input.setValidationResult "available", "Sorry, \"#{email}\" is already in use!"
+        return
+    messages    :
+      required  : 'Please enter your email address.'
+      email     : 'That doesn\'t seem like a valid email address.'
+
+
+  submitForm: (event) ->
+
+    # KDInputView doesn't give clear results with
+    # async results that's why we maintain those
+    # results manually in EMAIL_VALID and USERNAME_VALID
+    # at least for now - SY
+    if EMAIL_VALID and USERNAME_VALID and @username.input.valid and @email.input.valid
+      @submit event
+      return yes
+    else
+      @button.hideLoader()
+      @username.input.validate()
+      @email.input.validate()
+      return no
+
+
   viewAppended:->

     super
@@ -124,45 +167,6 @@
           @addSubView new ProfileTextView({}, account), '.invited-by .wrapper'
       else
         @$('.invited-by').addClass('hidden')
-
-  getEmailValidator: ->
-    container   : this
-    event       : "blur"
-    rules       :
-      required  : yes
-      email     : yes
-      available : (input, event)=>
-        return if event?.which is 9
-        input.setValidationResult "available", null
-        email = input.getValue()
-        if input.valid
-          # @email.loader.show()
-          KD.remote.api.JUser.emailAvailable email, (err, response)=>
-            # @email.loader.hide()
-            if err then warn err
-            else
-              if response
-                input.setValidationResult "available", null
-              else
-                input.setValidationResult "available", "Sorry, \"#{email}\" is already in use!"
-        return
-    messages    :
-      required  : "Please enter your email address."
-      email     : "That doesn't seem like a valid email address."
-  submitForm: (event) ->
-
-    # KDInputView doesn't give clear results with
-    # async results that's why we maintain those
-    # results manually in EMAIL_VALID and USERNAME_VALID
-    # at least for now - SY
-    if EMAIL_VALID and USERNAME_VALID and @username.input.valid and @email.input.valid
-      @submit event
-      return yes
-    else
-      @button.hideLoader()
-      @username.input.validate()
-      @email.input.validate()
-      return no

   pistachio:->
     """


Main: minor code styling

Main: minor code styling

--- client/Main/CommonViews/tagcontextmenuitem.coffee
+++ client/Main/CommonViews/tagcontextmenuitem.coffee
@@ -1,6 +1,9 @@
 class TagContextMenuItem extends JContextMenuItem
+
   constructor: (options = {}, data) ->
+
     options.cssClass = KD.utils.curry "tag-context-menu-item", options.cssClass
+
     super options, data

   viewAppended: JView::viewAppended


activity: define `CommentView::listPreviousReplies` method

--- client/Social/Activity/views/comments/view.coffee
+++ client/Social/Activity/views/comments/view.coffee
@@ -21,6 +21,28 @@
     data
       .on "AddReply", @controller.bound "addItem"
       .on "RemoveReply", @controller.lazyBound "removeItem", null
+
+
+  listPreviousReplies: ->
+
+    @emit "AsyncJobStarted"
+
+    activity = @getData()
+    from     = activity.replies[0].meta.createdAt.toISOString()
+    limit    = 10
+
+    KD.singleton("appManager").tell "Activity", "listReplies", {activity, from, limit}, (err, replies) =>
+
+      @emit "AsyncJobFinished"
+
+      return KD.showError err  if err
+
+      replies.reverse()
+
+      activity.replies = replies.concat activity.replies
+
+      @controller.addItem reply, index for reply, index in replies
+      @listPreviousLink.update()

   reply: (body, callback = noop) ->


PrivateMessages: get likers from social api.

--- client/Social/Activity/views/replylikeview.coffee
+++ client/Social/Activity/views/replylikeview.coffee
@@ -62,16 +62,21 @@

     @getTooltip().update {title}

+
   fetchAccounts: (callback) ->

-    {actorsPreview} = @getData().interactions.like
+    { socialapi } = KD.singletons

-    return callback null, actorsPreview  unless actorsPreview.length
+    socialapi.message.listLikers { id: @getData().id }, (err, res) =>
+      actorsPreview = res

-    constructorName = "JAccount"
-    origins = actorsPreview.map (id) -> {id, constructorName}
+      return callback null, actorsPreview  unless actorsPreview.length

-    KD.remote.cacheable origins, callback
+      constructorName = "JAccount"
+      origins = actorsPreview.map (id) -> {id, constructorName}
+
+      KD.remote.cacheable origins, callback
+

   pistachio: -> ''


flux/teams: add update func to team store

--- client/app/lib/flux/teams/stores/teamstore.coffee
+++ client/app/lib/flux/teams/stores/teamstore.coffee
@@ -14,6 +14,14 @@
   initialize: ->

     @on actions.LOAD_TEAM_SUCCESS, @load
+    @on actions.UPDATE_TEAM_SUCCESS, @update

   load: (oldTeam, { team }) -> toImmutable team
+
+
+  update: (oldTeam, { dataToUpdate }) ->
+
+    return oldTeam.set 'title', dataToUpdate.title  if dataToUpdate.title?
+    if dataToUpdate.customize?.logo?
+      oldTeam.setIn ['customize', 'logo'], dataToUpdate.customize.logo


client: warn if template was removed

client: warn if template was removed

--- client/app/lib/providers/computecontroller.coffee
+++ client/app/lib/providers/computecontroller.coffee
@@ -1291,6 +1291,9 @@

       @fetchBaseStackTemplate stack, (err, template) =>

+        if err or not template
+          console.warn 'The base template of the stack has been removed:', stack.baseStackId
+
         groupStack = stack.config?.groupStack

         @destroyStack stack, (err) =>


Fixing the fading.

Fixing the fading.

--- src/game/states/game.coffee
+++ src/game/states/game.coffee
@@ -82,10 +82,10 @@

      	 if @xdistance < 20 && @ydistance < 20
         #if Player on star
-     	       @game.add.tween(@star).to({alpha:0.1},1000,Phaser.Easing.Cubic.Out,true)
+     	       @game.add.tween(star).to({alpha:1},100,Phaser.Easing.Cubic.Out,true)
      	 else
        #if Player not on star
-     	       @game.add.tween(@star).to({alpha:0.1},3000,Phaser.Easing.Cubic.Out,true)
+     	       @game.add.tween(star).to({alpha:0.1},15000,Phaser.Easing.Cubic.Out,true)

      if @cursors.left.isDown
         @player.body.moveLeft(200)


Fix calendar click

Fix calendar click

--- client/components/ContributeByWeekCalendar.coffee
+++ client/components/ContributeByWeekCalendar.coffee
@@ -38,7 +38,7 @@
                     color = "#30a14e"
                 else
                     color = "#216e39"
-            onClickFun = do (currDay) -> -> if submits and (currDay of submits) then @props.clickOnDay(currDay)
+            onClickFun = do (currDay) => => if submits and (currDay of submits) then @props.clickOnDay(currDay)
             title = currDay
             if submits and (currDay of submits)
                 title += ": #{submits[currDay]}"


fixed the @clear. removing starting ! before adding to visitedRoutes

--- client/landing/app/MainApp/login/loginview.coffee
+++ client/landing/app/MainApp/login/loginview.coffee
@@ -307,8 +307,7 @@
             router.handleRoute route
             routed = yes
             break
-
-        @clear  unless routed
+        router.clear()  unless routed

   animateToForm: (name)->


Tests: Helpers: environmentHelper: change selector for clickCreateVMButton helper.

--- client/test/lib/helpers/environmenthelpers.coffee
+++ client/test/lib/helpers/environmenthelpers.coffee
@@ -107,5 +107,5 @@
       .waitForElementVisible    '.env-modal.paid-plan', 25000
       .click                    '.env-modal.paid-plan button'
       .waitForElementNotVisible '.env-modal.paid-plan', 250000
-      .waitForElementVisible    'a[title="koding-vm-1"]', 25000
+      .waitForElementVisible    '.my-machines .koding-vm-1 a:first-child', 25000
       .end()


Workspace: Make `JWorkspace#createDefault` function secure

--- workers/social/lib/social/models/workspace.coffee
+++ workers/social/lib/social/models/workspace.coffee
@@ -174,7 +174,7 @@
       ws.update options, callback

-  @createDefault: (client, machineUId, callback) ->
+  @createDefault: secure (client, machineUId, callback) ->

     JMachine.one$ client, machineUId, (err, machine) =>


enh: better code for image generation

enh: better code for image generation

--- src/application.coffee
+++ src/application.coffee
@@ -266,8 +266,12 @@
     @dialog.style.display="none"

   show: (svg) ->
-    dataUri = "data:image/svg+xml;utf8," + encodeURI(svg)
-    @imgContainer.innerHTML = "<img style=\"width:100%\" src=\"#{dataUri}\" alt=\"SVG\"/>"
+    dataUri = "data:image/svg+xml;utf8," + encodeURIComponent(svg)
+    dom = new DomBuilder()
+    dom.tag('img').a('src', dataUri).a('alt', 'SVG image').a('title', 'Use right click to save SVG image').end()
+    @imgContainer.innerHTML = ""
+    @imgContainer.appendChild dom.finalize()
+    #@imgContainer.innerHTML = svg
     @dialog.style.display=""


code: more generalization

code: more generalization

--- src/application.coffee
+++ src/application.coffee
@@ -100,7 +100,7 @@
   getCanvasResize: -> canvasSizeUpdateBlocked
   redraw: -> redraw()
   getObserver: -> @observer
-  drawEverything: -> drawEverything(context)
+  drawEverything: -> drawEverything canvas.width, canvas.height, context
   uploadToServer: (name, cb) -> uploadToServer name, cb
   getCanvas: -> canvas
   getGroup: -> @tessellation.group
@@ -248,8 +248,9 @@
     return [fieldData, catalogRecord]

   doExportSvg: ->
-    svgContext = new C2S(canvas.width, canvas.height)
-    drawEverything svgContext
+    sz = 1024
+    svgContext = new C2S sz, sz#(canvas.width, canvas.height)
+    drawEverything sz, sz, svgContext
     showExportDialog svgContext.getSerializedSvg()

@@ -410,13 +411,13 @@
 dirty = true
 redraw = -> dirty = true

-drawEverything = (context) ->
+drawEverything = (w, h, context) ->
   return false unless application.observer.canDraw()
   context.fillStyle = "white"
   #context.clearRect 0, 0, canvas.width, canvas.height
-  context.fillRect 0, 0, canvas.width, canvas.height
+  context.fillRect 0, 0, w, h
   context.save()
-  s = Math.min( canvas.width, canvas.height ) / 2 #
+  s = Math.min( w, h ) / 2 #
   context.scale s, s
   context.translate 1, 1
   context.fillStyle = "black"
@@ -434,7 +435,7 @@
 redrawLoop = ->
   if dirty
     if not fpsLimiting or ((t=Date.now()) - lastTime > dtMax)
-      if drawEverything(context)
+      if drawEverything canvas.width, canvas.height, context
         tDraw = Date.now() - t
         #adaptively update FPS
         dtMax = dtMax*0.9 + tDraw*2*0.1


add test case for loading module in workers

--- coffeescript/004-webworkers/multiplication.coffee
+++ coffeescript/004-webworkers/multiplication.coffee
@@ -4,13 +4,15 @@
   a demo webworker for mutiplication:
 ###
 define [
-  'underscore'
-], (_) ->
+  'underscore',
+  'cs!/wahlque/units/au'
+], (_, au) ->
     self.postMessage('before binding')
     self.onmessage = (e) ->
         self.postMessage('hello from worker!')
         result = _.reduce(e.data, ((memo, elem) -> memo * elem), 1)
         self.postMessage(result)
+        self.postMessage(au.G)
         true
     self.postMessage('after binding')
     true


Use better documented trigger:true

Use better documented trigger:true

--- core/app/assets/javascripts/intermediate.coffee
+++ core/app/assets/javascripts/intermediate.coffee
@@ -40,7 +40,7 @@
   history = backbone?.history
   if history && backbone.History.started
     history.fragment = null # Force loading the url, even if already showing that url
-    history.navigate url, true
+    history.navigate url, trigger: true
   else
     showFrame.onload = -> window.onModalReady()
     showFrame.src = url


test action filters with USSD flow type

test action filters with USSD flow type

--- karma/flows/test_controllers.coffee
+++ karma/flows/test_controllers.coffee
@@ -233,6 +233,13 @@
         expect(modalScope.validActionFilter(getAction('play'))).toBe(false)
         expect(modalScope.validActionFilter(getAction('api'))).toBe(false)

+        # USSD flow
+        flowService.flow.flow_type = 'U'
+        expect(modalScope.validActionFilter(getAction('reply'))).toBe(true)
+        expect(modalScope.validActionFilter(getAction('say'))).toBe(false)
+        expect(modalScope.validActionFilter(getAction('play'))).toBe(false)
+        expect(modalScope.validActionFilter(getAction('api'))).toBe(false)
+
       $timeout.flush()

     it 'updateContactAction should not duplicate fields on save', ->


Use correct variable name

Use correct variable name

--- src/grammar-registry.coffee
+++ src/grammar-registry.coffee
@@ -84,7 +84,7 @@
         callback?(error)
       else
         if typeof grammar.scopeName is 'string' and grammar.scopeName.length > 0
-          callback?(null, @createGrammar(grammarPath, object))
+          callback?(null, @createGrammar(grammarPath, grammar))
         else
           callback?(new Error("Grammar missing required scopeName property: #{grammarPath}"))


Add GrammarRegistry::clearObservers for specs

--- src/grammar-registry.coffee
+++ src/grammar-registry.coffee
@@ -223,6 +223,11 @@
   selectGrammar: (filePath, fileContents) ->
     _.max @grammars, (grammar) -> grammar.getScore(filePath, fileContents)

+  # Test-Only: Clear all observers registered with ::on* methods.
+  clearObservers: ->
+    @off()
+    @emitter = new Emitter
+
   createToken: (value, scopes) -> {value, scopes}

   grammarUpdated: (scopeName) ->


Group within "groups"

Group within "groups"

--- components/GroupBy.coffee
+++ components/GroupBy.coffee
@@ -18,11 +18,23 @@
     @inPorts.in.on "connect", =>
       @objects = []

+    @inPorts.in.on "begingroup", (group) =>
+      @outPorts.out.beginGroup group
+
     @inPorts.in.on "data", (object) =>
       @objects.push object

+    @inPorts.in.on "endgroup", (group) =>
+      @flush()
+      @outPorts.out.endGroup()
+
     @inPorts.in.on "disconnect", =>
-      @outPorts.out.send _.groupBy @objects, @property
+      @flush()
       @outPorts.out.disconnect()

+  flush: ->
+    return if _.isEmpty @objects
+    @outPorts.out.send _.groupBy @objects, @property
+    @objects = []
+
 exports.getComponent = -> new GroupBy


Added new parameter divedeHours for HTimesheet

--- js/datetime/timesheet/timesheet.coffee
+++ js/datetime/timesheet/timesheet.coffee
@@ -23,6 +23,7 @@
     autoLabel:      false # Automatically set the label to the date, when enabled
     autoLabelFn: 'formatDate' # The name of the function to return formatted date/time
     notchesPerHour:     4 # by default 1/4 of an hour precision (15 minutes)
+    divideHours:        1 # by default all hours is shown
     snapToNotch:     true # Snaps time to nearest notch/line
     itemOffsetLeft:    64 # Theme settings; don't enter in options
     itemOffsetRight:    0 # Theme settings; don't enter in options
@@ -84,6 +85,7 @@
     _pxPerLine  = _pxPerHour / _notchesPerHour
     _bottomPos  = _rectHeight-_height-_topOffset-2
     _pxPerNotch = _pxPerHour / _notchesPerHour
+    _divideHours = @options.divideHours

     ELEM.setStyle( _hourParent, 'visibility', 'hidden', true )
     ELEM.setStyle( @markupElemIds.value, 'bottom', _bottomPos+'px' )
@@ -101,7 +103,7 @@

     for _hour in [_hourStart.._hourEnd]
       _lineTop  = Math.round( _topOffset + (_hour*_pxPerHour) )
-      if _hour != _hourStart
+      if _hour != _hourStart and _hour % _divideHours == 0
         _hourTop = _lineTop + @options.hourOffsetTop
         @hourItems.push( ELEM.make( @markupElemIds.timeline, 'div',
           attr:


Eliminate duplicate 'gutter' class

Eliminate duplicate 'gutter' class

This was previously needed when we applied 'editor-colors' to the
line numbers to give them an opaque background in hopes of supporting
sub pixel AA, but that dream is dead for now anyway. This makes the
gutter harder to style, so I'm nixing it.

--- src/gutter-component.coffee
+++ src/gutter-component.coffee
@@ -19,7 +19,7 @@
     {scrollHeight, scrollViewHeight, onMouseDown} = @props

     div className: 'gutter', onClick: @onClick, onMouseDown: onMouseDown,
-      div className: 'gutter line-numbers', ref: 'lineNumbers', style:
+      div className: 'line-numbers', ref: 'lineNumbers', style:
         height: Math.max(scrollHeight, scrollViewHeight)
         WebkitTransform: @getTransform()


Skip Logic Refactoring - removing obsolete tests

--- jsapp/test/unit/SkipLogic.Tests.coffee
+++ jsapp/test/unit/SkipLogic.Tests.coffee
@@ -768,72 +768,9 @@
         expect(_presenter_stubs[0].model.cid).toBe 2

   describe 'hand code helper', () ->
-    _view_factory = sinon.stubObject $vRdsl.SkipLogicViewFactory
-    _builder = null
-    _facade = null
-    _view = null
-
-    beforeEach () ->
-      _view = sinon.stubObject $vRdsl.SkipLogicHandCodeView
-      _builder = sinon.stubObject($slh.SkipLogicBuilder)
-      _view_factory.create_hand_code_view.returns _view
-      _view.render.returns _view
-      _view.$.withArgs('.skiplogic-handcode__cancel').returns(click: sinon.spy())
-      _facade = new $slh.SkipLogicHandCodeHelper(
-        'test criteria'
-        _builder
-        _view_factory
-        sinon.stubObject($slh.SkipLogicHelperContext)
-      )
-
-
-    describe 'render', () ->
-      _textarea_spy = null
-
-      beforeEach () ->
-        _textarea_spy = val: sinon.spy()
-
-        _view.$.withArgs('textarea').returns _textarea_spy
-        _facade.render 'test'
-
-      it 'renders the view', () ->
-        expect(_view.render).toHaveBeenCalledOnce()
-      it 'attaches root view to provided destination', () ->
-        expect(_view.attach_to).toHaveBeenCalledWith 'test'
-      it "set the view's text area to the passed criteria", () ->
-        expect(_textarea_spy.val).toHaveBeenCalledWith 'test criteria'
-    describe 'serialize', () ->
-      it "returns the value of the view's text area", ->
-        textarea_stub = val: sinon.stub()
-        _view.$.withArgs('textarea').returns textarea_stub
-        textarea_stub.val.returns 'test criteria'
-        expect(_facade.serialize()).toBe 'test criteria'
-
-    describe 'constructor', () ->
+

   describe 'mode selector helper', () ->
-    describe 'render', () ->
-      initialize_mode_selector_helper = () ->
-
-        view_factory_stub = sinon.stubObject($vRdsl.SkipLogicViewFactory)
-        view_stub = sinon.stubObject($vRdsl.SkipLogicPickerView)
-
-        view_stub.render.returns view_stub
-        view_factory_stub.create_skip_logic_picker_view.returns view_stub
-
-
-        return new $slh.SkipLogicModeSelectorHelper(view_factory_stub)
-
-      it 'renders the view', () ->
-        helper = initialize_mode_selector_helper()
-        helper.render('destination')
-
-        expect(helper.view.render).toHaveBeenCalledOnce()
-      it 'attaches the view to passed destination', () ->
-        helper = initialize_mode_selector_helper()
-        helper.render('destination')
-        expect(helper.view.attach_to).toHaveBeenCalledWith('destination')
-
     describe 'serialize', () ->
       it 'returns an empty string', () ->
         helper = new $slh.SkipLogicModeSelectorHelper(sinon.stubObject($vRdsl.SkipLogicViewFactory))
@@ -870,26 +807,7 @@
         expect(state_spy.serialize).toHaveBeenCalledOnce()

     describe 'use criterion builder helper', () ->
-      it 'switches inner state to criterion builder helper', () ->
-        context = initialize_helper_context()
-        context.state = serialize: sinon.stub().returns 'test'
-
-        context.view_factory.create_criterion_builder_view.returns {}
-        context.builder.build_criterion_builder.withArgs('test').returns('test presenter', 'and')
-
-        context.use_criterion_builder_helper()
-
-        expect(context.state).toBeInstanceOf $slh.SkipLogicCriterionBuilderHelper
-      it 'sets state to null when builder can`t build criterion builder', () ->
-        context = initialize_helper_context()
-        context.state = serialize: sinon.stub().returns 'test'
-
-        context.view_factory.create_criterion_builder_view.returns {}
-        context.builder.build_criterion_builder.withArgs('test').returns(false)
-
-        context.use_criterion_builder_helper()
-
-        expect(context.state).toBeNull()
+
     describe 'use hand code helper', () ->
       it 'switches inner state to hand code helper', () ->
         context = initialize_helper_context()
@@ -935,24 +853,6 @@
       helper_factory = sinon.stubObject $slh.SkipLogicHelperFactory

       new $slh.SkipLogicBuilder(model_factory, view_factory, survey, current_question, helper_factory)
-    describe 'build', () ->
-      it "returns a helper context", () ->
-        relevant_stub = get: sinon.stub()
-        relevant_stub.get.withArgs('value').returns('test criteria')
-
-        builder = initialize_builder()
-
-        builder.build_criterion_builder = sinon.stub()
-        builder.build_criterion_builder.withArgs('test criteria').returns('test criterion builder')
-
-        builder.current_question.get.withArgs('relevant').returns(relevant_stub)
-
-        original_skip_logic_helper_context = $slh.SkipLogicHelperContext
-        $slh.SkipLogicHelperContext =  () -> return
-        result = builder.build()
-        expect(result).toBeInstanceOf $slh.SkipLogicHelperContext
-
-        $slh.SkipLogicHelperContext = original_skip_logic_helper_context

     describe 'build criterion builder', () ->
       _builder = null


About page: link to BHL home page

About page: link to BHL home page

--- content/about.coffee
+++ content/about.coffee
@@ -6,7 +6,7 @@

BHL and Constructing Scientific Communities

-
‘Science Gossip’ is born from a collaboration between an Arts and Humanities Research Council project in the UK, called ‘Constructing Scientific Communities: Citizen Science in the 19th and 21st Centuries’ (ConSciCom) and the Missouri Botanical Garden who are providing content from the Biodiversity Heritage Library (BHL).

+
‘Science Gossip’ is born from a collaboration between an Arts and Humanities Research Council project in the UK, called ‘Constructing Scientific Communities: Citizen Science in the 19th and 21st Centuries’ (ConSciCom) and the Missouri Botanical Garden who are providing content from the Biodiversity Heritage Library (BHL).

BHL is currently engaged in several citizen science initiatives that help leverage the crowd in improving access to its content.  Projects include:  Art of Life, where the public helps in describing natural history images; Purposeful Gaming and BHL where players engage in online games to help with text correction; Mining Biodiversity where annotators help train mining algorithms for named entities, such as taxa, places, habitats and traits; and the Field Book Project where “volunpeers” transcribe hand-written field book content.  More information about these projects can be found in the BHL blog post on Crowdsourcing and BHL


BUG-FIX template property should be set to `undefined` by default BUG-FIX DI property should be set to globals (as ui-neck does)

--- src/modules/controller.coffee
+++ src/modules/controller.coffee
@@ -3,10 +3,10 @@
   @REVERSE_PARSING: $('<div ui-test1 ui-test2></div>')[0].attributes[0].name is 'ui-test2'

   divWrapper: true
-  template: false
   parseSelf: true
+  template: undefined

-  injector: Neck.DI.commonjs
+  injector: Neck.DI.globals

   constructor: (opts = {})->
     super
@@ -23,7 +23,7 @@
       # Inherit injector
       @injector = @parent.injector

-    if opts.template and not @template
+    if opts.template and @template is undefined
       @template = opts.template

     if @template is true
@@ -88,7 +88,7 @@

       for item in buffer
         helper = new item.controller(el: el, parent: @, mainAttr: item.value)
-        stop = true if helper.template isnt false
+        stop = true if helper.template isnt undefined

     @_parseNode child for child in node.childNodes unless stop or not node
     undefined


Export Bacon.Model instead of Bacon

Export Bacon.Model instead of Bacon

--- src/bacon.model.coffee
+++ src/bacon.model.coffee
@@ -25,7 +25,7 @@

   copy

-init = (Bacon) ->
+factory = (Bacon) ->
   _ = Bacon._
   idCounter = 1

@@ -174,13 +174,13 @@

   valueLens = Lens.objectLens("value")

-  Bacon
+  Model

 if module? && module.exports?
   Bacon = require("baconjs")
-  module.exports = init(Bacon)
+  module.exports = factory(Bacon)
 else
   if typeof define == "function" and define.amd
-    define ["bacon"], init
+    define ["bacon"], factory
   else
-    init(this.Bacon)
+    factory(this.Bacon)


Fix spec to now that we don't build PreviewItems

--- spec/extensions/command-panel-spec.coffee
+++ spec/extensions/command-panel-spec.coffee
@@ -131,10 +131,10 @@
         runs ->
           expect(commandPanel).toBeVisible()
           expect(commandPanel.previewList).toBeVisible()
-          previewItem = commandPanel.previewList.find("li:contains(dir/a)").view()
-          expect(previewItem.path.text()).toBe "dir/a"
-          expect(previewItem.preview.text()).toBe "aaa bbb"
-          expect(previewItem.preview.find(".match").text()).toBe "aaa"
+          previewItem = commandPanel.previewList.find("li:contains(dir/a):first")
+          expect(previewItem.find('.path').text()).toBe "dir/a"
+          expect(previewItem.find('.preview').text()).toBe "aaa bbb"
+          expect(previewItem.find('.preview > .match').text()).toBe "aaa"

           rootView.trigger 'command-panel:toggle' # ensure we can close panel without problems


The compositeView doesn't rerender when something happens, because it doesn't get reset events, so explicitly check for sync

--- core/app/backbone/views/notifications_view.coffee
+++ core/app/backbone/views/notifications_view.coffee
@@ -22,8 +22,11 @@
       @hideDropdown()

   onRender: ->
+    @$("ul").preventScrollPropagation()
+    @listenTo @collection, 'sync', @updateUnreadCount
+
+  updateUnreadCount: ->
     @setUnreadCount @collection.unreadCount()
-    @$("ul").preventScrollPropagation()

   setUnreadCount: (count) ->
     @_unreadCount = count


use the gzip request option to unzip response body


Use `activatePane`, not `changeFocus`

Use `activatePane`, not `changeFocus`

In call to Workspace::open

--- lib/tree-view.coffee
+++ lib/tree-view.coffee
@@ -341,12 +341,12 @@
       directory.collapse(isRecursive)
       @selectEntry(directory)

-  openSelectedEntry: (changeFocus) ->
+  openSelectedEntry: (activatePane) ->
     selectedEntry = @selectedEntry()
     if selectedEntry instanceof DirectoryView
       selectedEntry.toggleExpansion()
     else if selectedEntry instanceof FileView
-      atom.workspace.open(selectedEntry.getPath(), {changeFocus})
+      atom.workspace.open(selectedEntry.getPath(), {activatePane})

   moveSelectedEntry: ->
     if @hasFocus()


a little more DRY

a little more DRY

--- core/KDObject.coffee
+++ core/KDObject.coffee
@@ -23,6 +23,10 @@
     o:(o)->o

   bound: Bongo.bound
+
+  lazyBound:(method, rest...)->
+    return @bound method  unless rest.length
+    return @[method].bind this, rest...

   ready:(listener)->
     if @readyState > 0 then listener()


:lipstick: Rename

:lipstick: Rename

--- lib/vim-state.coffee
+++ lib/vim-state.coffee
@@ -32,7 +32,7 @@
     @marks = {}
     @subscriptions.add @editor.onDidDestroy => @destroy()
     @operationStack = new OperationStack(this)
-    @counter = @getCounter()
+    @counter = @getCountManager()

     @subscriptions.add @editor.onDidChangeSelectionRange _.debounce(=>
       return unless @editor?
@@ -582,7 +582,7 @@
   # e - The event that triggered the Number prefix.
   #
   # Returns nothing.
-  getCounter: ->
+  getCountManager: ->
     count = null
     isOperatorPending = @isOperatorPending.bind(this)
     set: (e) ->


Remove unused redis package reference

Remove unused redis package reference

--- test/acceptance/coffee/RangesTests.coffee
+++ test/acceptance/coffee/RangesTests.coffee
@@ -3,7 +3,6 @@
 chai.should()
 expect = chai.expect
 async = require "async"
-rclient = require("redis").createClient()

 MockWebApi = require "./helpers/MockWebApi"
 DocUpdaterClient = require "./helpers/DocUpdaterClient"


helper function for stream callbacks

helper function for stream callbacks

--- lib/webserver.coffee
+++ lib/webserver.coffee
@@ -42,6 +42,12 @@
 # Routes
 # -----------------

+# Helper function for the stream callback
+sendFile = (err, stdout, req, res, next) ->
+  res.setHeader('Expires', new Date(Date.now() + 604800000))
+  res.setHeader('Content-Type', 'image/png')
+  stdout.pipe(res)
+
 # Root
 app.get '/', (req, res) -> res.redirect('http://avatars.adorable.io')

@@ -49,17 +55,13 @@
 app.get '/avatar/:name', (req, res, next) ->
   faceParts = potato.parts(req.params.name)
   face = imager.combine faceParts, (err, stdout) ->
-    res.setHeader('Expires', new Date(Date.now() + 604800000))
-    res.setHeader('Content-Type', 'image/png')
-    stdout.pipe(res)
+    sendFile(err, stdout, req, res, next)

 # Avatars: Route with custom Size
 app.get '/avatar/:size/:name', (req, res, next) ->
   faceParts = potato.parts(req.params.name)
   imager.resize faceParts, req.params.size, (err, stdout) ->
-    res.setHeader('Expires', new Date(Date.now() + 604800000))
-    res.setHeader('Content-Type', 'image/png')
-    stdout.pipe(res)
+    sendFile(err, stdout, req, res, next)

 module.exports = webserver


don't need to bind on panels' slide event anymore

--- app/assets/javascripts/ample_assets/classes/ample_assets.js.coffee
+++ app/assets/javascripts/ample_assets/classes/ample_assets.js.coffee
@@ -130,6 +130,7 @@
     if @options.pages[i]['url']
       data_type = @options.pages[i]['data_type'] if @options.pages[i]['data_type']
       $.get @options.pages[i]['url'], (response, xhr) ->
+        ref.options.pages[i]['loaded'] = true
         switch data_type
           when "json"
             ref.load_json i, response
@@ -142,7 +143,6 @@

   load_html: (i, response) ->
     @log "load(#{i}) html"
-    @options.pages[i]['loaded'] = true
     selector = "##{@options.id} .pages .page:nth-child(#{(i+1)})"
     selector += " ul" if @options.pages[i]['panels']
     $(selector).html(response)
@@ -165,8 +165,9 @@
       @log "panels(#{i})"
       el = @options.pages[i]['panel_selector'] = "##{@options.id} .pages .page:nth-child(#{(i+1)}) ul"
       $(el).attr('id',"#{@options.pages[i]['id']}-panel")
-      $(el).amplePanels(@options.pages_options).bind 'slide_horizontal', (e,d) ->
-        console.log "TODO: load next pages"
+      $(el).amplePanels(@options.pages_options)
+        #.bind 'slide_horizontal', (e,d) ->
+        #console.log "TODO: load next pages"
         #TODO: load next pages

   disable_panels: ->


added scroll to next required action

added scroll to next required action

--- app/assets/javascripts/app/views/tracks/track_video_form.js.coffee
+++ app/assets/javascripts/app/views/tracks/track_video_form.js.coffee
@@ -118,6 +118,10 @@
     current_time = @player.getCurrentTime()
     @$('input[name="track_video[video_offset]"]').val(current_time.toFixed(1))

+    $('html, body').animate({
+      scrollTop: $("#chart").offset().top - 71
+    }, 700);
+
   on_change_url: (e) ->
     elem_value = $(e.currentTarget).val()
     code = @get_code_from_url(elem_value)
@@ -132,6 +136,11 @@

     @$('input[name="track_video[video_code]"]').val(code || '')

+    if (!current_code && code)
+      $('html, body').animate({
+        scrollTop: $("#player").offset().top - 71
+      }, 700);
+
     @init_player() if @youtube_api_ready

   get_code_from_url: (url) ->


[fix] Numbered comments with a 1-based index (2m)

--- app/assets/javascripts/houston/feedback/views/comments_view.coffee
+++ app/assets/javascripts/houston/feedback/views/comments_view.coffee
@@ -222,7 +222,7 @@
       , 1500

     context = comment.toJSON()
-    context.index = $('.feedback-comment.selected').index()
+    context.index = $('.feedback-comment.selected').index() + 1
     context.total = @comments.length
     context.canCopy = @canCopy
     $('#feedback_edit').html @renderEditComment(context)


Change determineRelationshipType signature.

--- app/assets/javascripts/mixins/serialize_hasmany.js.coffee
+++ app/assets/javascripts/mixins/serialize_hasmany.js.coffee
@@ -15,7 +15,7 @@

     key = relationship.key
     idsKey = key.substr(0, key.length-1) + "_ids"
-    relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship)
+    relationshipType = record.constructor.determineRelationshipType(relationship)
     if @relationshipMap relationshipType
       json[@toSnakeCase(idsKey)] = Em.get(record, key).mapBy("id")
     return


8979: class comments, check for listener

--- app/assets/javascripts/views/file_uploader_view.js.coffee
+++ app/assets/javascripts/views/file_uploader_view.js.coffee
@@ -1,3 +1,9 @@
+# The FileUploaderView wraps provides a dropzone file upload interface for uploading one file.
+# The zone id is the id of the html element that is the 'dropzone'
+# The post path is where the file upload will be posted to.
+# The preview template controls what dropzone looks like and it typically dropzone_preview.html (found in /layouts)
+# The paramName is the key to the file in the http request dropzone posts.
+
 class ELMO.Views.FileUploaderView extends ELMO.Views.ApplicationView
   initialize: (options) ->
     @zone_id = options.zone_id
@@ -51,10 +57,12 @@
     @id_field.val('')

   upload_starting: ->
-    @listener.upload_starting()
+    if @listener
+      @listener.upload_starting()
     @$('img')[0].src = @generic_thumb_path
     @$('.dz-message').hide()
     @$('.error-msg').hide()

   upload_finished: ->
-    @listener.upload_finished()
+    if @listener
+      @listener.upload_finished()


Cleanup getVersion, checkComp

Cleanup getVersion, checkComp

--- lib/ghc-mod/ghc-modi-process.coffee
+++ lib/ghc-mod/ghc-modi-process.coffee
@@ -31,9 +31,8 @@
   initBackend: (rootDir) ->
     return @backend.get(rootDir) if @backend.has(rootDir)
     procopts = Util.getProcessOptions(rootDir)
-    vers = @getVersion(procopts)
-    vers.then (v) =>
-      @checkComp(procopts, v)
+    vers = procopts.then (opts) => @getVersion(opts)
+    vers.then (v) => procopts.then (opts) => @checkComp(opts, v)

     backend =
       vers
@@ -68,63 +67,55 @@
     @disposables.add atom.config.observe 'haskell-ghc-mod.maxBrowseProcesses', (value) =>
       @commandQueues.browse = new Queue(value)

-  getVersion: (procopts) ->
-    procopts
-    .then (opts) ->
-      opts1 = {}
-      for k, v of opts
-        opts1[k] = v
-      opts1.timeout = atom.config.get('haskell-ghc-mod.syncTimeout')
-      return opts1
-    .then (opts) ->
-      Util.execPromise atom.config.get('haskell-ghc-mod.ghcModPath'), ['version'], opts
+  getVersion: (opts) ->
+    opts1 = {}
+    for k, v of opts
+      opts1[k] = v
+    opts1.timeout = atom.config.get('haskell-ghc-mod.syncTimeout')
+    Util.execPromise atom.config.get('haskell-ghc-mod.ghcModPath'), ['version'], opts1
+    .then (stdout) ->
+      vers = /^ghc-mod version (\d+)\.(\d+)\.(\d+)(?:\.(\d+))?/.exec(stdout).slice(1, 5).map (i) -> parseInt i
+      comp = /GHC (.+)$/.exec(stdout.trim())[1]
+      Util.debug "Ghc-mod #{vers} built with #{comp}"
+      return {vers, comp}
+
+  checkComp: (opts, {comp}) ->
+    opts1 = {}
+    for k, v of opts
+      opts1[k] = v
+    opts1.timeout = atom.config.get('haskell-ghc-mod.syncTimeout')
+    stackghc =
+      Util.execPromise 'stack', ['ghc', '--', '--version'], opts1
       .then (stdout) ->
-        vers = /^ghc-mod version (\d+)\.(\d+)\.(\d+)(?:\.(\d+))?/.exec(stdout).slice(1, 5).map (i) -> parseInt i
-        comp = /GHC (.+)$/.exec(stdout.trim())[1]
-        Util.debug "Ghc-mod #{vers} built with #{comp}"
-        return {vers, comp}
-
-  checkComp: (procopts, {comp}) ->
-    procopts
-    .then (opts) ->
-      opts1 = {}
-      for k, v of opts
-        opts1[k] = v
-      opts1.timeout = atom.config.get('haskell-ghc-mod.syncTimeout')
-      return opts1
-    .then (opts) ->
-      stackghc =
-        Util.execPromise 'stack', ['ghc', '--', '--version'], opts
-        .then (stdout) ->
-          /version (.+)$/.exec(stdout.trim())[1]
-        .catch (error) ->
-          Util.warn error
-          return null
-      pathghc =
-        Util.execPromise 'ghc', ['--version'], opts
-        .then (stdout) ->
-          /version (.+)$/.exec(stdout.trim())[1]
-        .catch (error) ->
-          Util.warn error
-          return null
-      Promise.all [stackghc, pathghc]
-      .then ([stackghc, pathghc]) ->
-        Util.debug "Stack GHC version #{stackghc}"
-        Util.debug "Path GHC version #{pathghc}"
-        if stackghc? and stackghc isnt comp
-          warn = "
-            GHC version in your Stack '#{stackghc}' doesn't match with
-            GHC version used to build ghc-mod '#{comp}'. This can lead to
-            problems when using Stack projects"
-          atom.notifications.addWarning warn
-          Util.warn warn
-        if pathghc? and pathghc isnt comp
-          warn = "
-            GHC version in your PATH '#{pathghc}' doesn't match with
-            GHC version used to build ghc-mod '#{comp}'. This can lead to
-            problems when using Cabal or Plain projects"
-          atom.notifications.addWarning warn
-          Util.warn warn
+        /version (.+)$/.exec(stdout.trim())[1]
+      .catch (error) ->
+        Util.warn error
+        return null
+    pathghc =
+      Util.execPromise 'ghc', ['--version'], opts1
+      .then (stdout) ->
+        /version (.+)$/.exec(stdout.trim())[1]
+      .catch (error) ->
+        Util.warn error
+        return null
+    Promise.all [stackghc, pathghc]
+    .then ([stackghc, pathghc]) ->
+      Util.debug "Stack GHC version #{stackghc}"
+      Util.debug "Path GHC version #{pathghc}"
+      if stackghc? and stackghc isnt comp
+        warn = "
+          GHC version in your Stack '#{stackghc}' doesn't match with
+          GHC version used to build ghc-mod '#{comp}'. This can lead to
+          problems when using Stack projects"
+        atom.notifications.addWarning warn
+        Util.warn warn
+      if pathghc? and pathghc isnt comp
+        warn = "
+          GHC version in your PATH '#{pathghc}' doesn't match with
+          GHC version used to build ghc-mod '#{comp}'. This can lead to
+          problems when using Cabal or Plain projects"
+        atom.notifications.addWarning warn
+        Util.warn warn

   getCaps: ({vers}) ->
     caps =


Hook worker test skeleton updated

Hook worker test skeleton updated

--- test/unit/hooks-worker-client-test.coffee
+++ test/unit/hooks-worker-client-test.coffee
@@ -5,9 +5,21 @@

     describe 'when --language ruby option is given', () ->
       it 'should spawn the server process with command "dredd-worker-ruby"'
+      it 'should pass --hookfiles option as a array of arguments'
+
+      describe 'when the worker  is not installed', () ->
+        it 'should exit with 1'
+        it 'should write a hint how to install'
+

     describe 'when --language python option is given', () ->
       it 'should spawn the server process with command "dredd-worker-python"'
+      it 'should pass --hookfiles option as a array of arguments'
+
+      describe 'when the worker  is not installed', () ->
+        it 'should exit with 1'
+        it 'should write a hint how to install'
+

     describe 'when --language ./eny/other-command is giveb', () ->
       it 'should run this command given as language option'
@@ -15,6 +27,7 @@
     it 'should pipe spawned process stderr to the Dredd process stderr'

     it 'should pipe spawned process stdut to the Dredd process stdout'
+
     it 'should Dredd with status > 1 when spawned process ends with exit status > 0'

     it 'should connect to the server'


respect line length

respect line length

--- lib/assets/javascripts/twine.js.coffee
+++ lib/assets/javascripts/twine.js.coffee
@@ -333,5 +333,7 @@
     return teardown: ->
       $(node).off eventName, onEventHandler

-for eventName in ['click', 'dblclick', 'mouseenter', 'mouseleave', 'mouseover', 'mouseout', 'mousedown', 'mouseup', 'submit', 'dragenter', 'dragleave', 'dragover', 'drop', 'drag', 'change', 'keypress', 'keydown', 'keyup', 'input', 'error', 'done', 'success', 'fail', 'blur', 'focus', 'load', 'paste']
+for eventName in ['click', 'dblclick', 'mouseenter', 'mouseleave', 'mouseover', 'mouseout', 'mousedown', 'mouseup',
+  'submit', 'dragenter', 'dragleave', 'dragover', 'drop', 'drag', 'change', 'keypress', 'keydown', 'keyup', 'input',
+  'error', 'done', 'success', 'fail', 'blur', 'focus', 'load', 'paste']
   setupEventBinding(eventName)


no message

no message

--- lib/emulator/run-on-server-view.coffee
+++ lib/emulator/run-on-server-view.coffee
@@ -7,10 +7,6 @@
 {openFile} = require '../utils/dialog'

 fsmkdirs = Q.denodeify fs.mkdirs
-
-# placeholder
-PH_ROOT = 'click here to select root path'
-PH_INDEX = 'the index page'

 module.exports =
 class RunOnServerView extends View


Remove get/set from tests

Remove get/set from tests

--- bokehjs/test/models/formatters/func_tick_formatter.coffee
+++ bokehjs/test/models/formatters/func_tick_formatter.coffee
@@ -17,7 +17,7 @@

     it "should have values as function args", ->
       rng = new Range1d()
-      formatter.set('args', {foo: rng.ref()})
+      formatter.args = {foo: rng.ref()}
       func = new Function("tick", "foo", "require", "return 10")
       expect(formatter._make_func().toString()).to.be.equal(func.toString())

@@ -42,7 +42,7 @@
     it "should handle args appropriately", ->
       rng = new Range1d({start: 5, end: 10})
       formatter = new FuncTickFormatter({
-        code: "return foo.get('start') + foo.get('end') + tick"
+        code: "return foo.start + foo.end + tick"
         args: {foo: rng}
       })
       labels = formatter.doFormat([-10, -0.1, 0, 0.1, 10])


Use getter and setter for component name.


Forgot to comment the sugar console log out

--- source/coffee/sugar.coffee
+++ source/coffee/sugar.coffee
@@ -5,7 +5,7 @@

 exports.translate_sugar = (tokens) ->
   out_tokens = coffee_style_functions noparen_function_calls multiline_statements clean tokens
-  console.log (t.value or t.type for t in out_tokens).join ' '
+  #console.log (t.value or t.type for t in out_tokens).join ' '
   return out_tokens

 clean = (tokens) ->


Add plugin origin on created markers

Add plugin origin on created markers

--- lib/minimap-pigments-binding.coffee
+++ lib/minimap-pigments-binding.coffee
@@ -25,7 +25,7 @@
       @decorationsByMarkerId[m.id]?.destroy()

     for m in markers when m.color?.isValid() and m not in @displayedMarkers
-      decoration = @minimap.decorateMarker(m.marker, type: 'highlight', color: m.color.toCSS())
+      decoration = @minimap.decorateMarker(m.marker, type: 'highlight', color: m.color.toCSS(), plugin: 'pigments')

       @decorationsByMarkerId[m.id] = decoration
       @subscriptionsByMarkerId[m.id] = decoration.onDidDestroy =>


Handled single value requests

Handled single value requests

--- lib/test_generators/backbone_rest.coffee
+++ lib/test_generators/backbone_rest.coffee
@@ -37,7 +37,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(MODELS_JSON, res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = MODELS_JSON, actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested keys by single key', (done) ->
@@ -51,7 +51,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> _.pick(item, 'name')), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> _.pick(item, 'name')), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested keys by single key respecting whitelist (key included)', (done) ->
@@ -65,7 +65,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> _.pick(item, 'name')), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> _.pick(item, 'name')), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested keys by single key respecting whitelist (key excluded)', (done) ->
@@ -79,7 +79,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> []), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> []), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested keys by an array of keys', (done) ->
@@ -93,7 +93,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> _.pick(item, ['name', 'created_at'])), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> _.pick(item, ['name', 'created_at'])), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested keys by an array of keys respecting whitelist (keys included)', (done) ->
@@ -107,7 +107,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> _.pick(item, ['name', 'created_at'])), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> _.pick(item, ['name', 'created_at'])), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested keys by an array of keys respecting whitelist (key excluded)', (done) ->
@@ -121,7 +121,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> _.pick(item, ['created_at'])), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> _.pick(item, ['created_at'])), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested keys by an array of keys respecting whitelist (keys excluded)', (done) ->
@@ -135,7 +135,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> {}), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> {}), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested values by single key', (done) ->
@@ -149,7 +149,21 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> _.values(_.pick(item, 'name'))), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> item['name']), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
+            done()
+
+      it 'should select requested values by single key (in array)', (done) ->
+        app = express(); app.use(express.bodyParser())
+        controller = new RestController(app, {model_type: MODEL_TYPE, route: ROUTE})
+
+        request(app)
+          .get("/#{ROUTE}")
+          .query({$values: ['name']})
+          .set('Accept', 'application/json')
+          .end (err, res) ->
+            assert.ok(!err, "no errors: #{err}")
+            assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> item['name']), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested values by single key respecting whitelist (key included)', (done) ->
@@ -163,7 +177,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> _.values(_.pick(item, 'name'))), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> item['name']), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested values by single key respecting whitelist (key excluded)', (done) ->
@@ -177,7 +191,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> []), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> null), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested values by an array of keys', (done) ->
@@ -191,7 +205,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> _.values(_.pick(item, ['name', 'created_at']))), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> _.values(_.pick(item, ['name', 'created_at']))), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested values by an array of keys respecting whitelist (keys included)', (done) ->
@@ -205,7 +219,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> _.values(_.pick(item, ['name', 'created_at']))), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> _.values(_.pick(item, ['name', 'created_at']))), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested values by an array of keys respecting whitelist (key excluded)', (done) ->
@@ -219,7 +233,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> _.values(_.pick(item, ['name']))), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> _.values(_.pick(item, ['name']))), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should select requested values by an array of keys respecting whitelist (keys excluded)', (done) ->
@@ -233,7 +247,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.map(MODELS_JSON, (item) -> []), res.body, "models json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.map(MODELS_JSON, (item) -> []), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

     ######################################
@@ -251,7 +265,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(MODELS_JSON[0], res.body, "model json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = MODELS_JSON[0], actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

       it 'should find an existing model with whitelist', (done) ->
@@ -265,7 +279,7 @@
           .end (err, res) ->
             assert.ok(!err, "no errors: #{err}")
             assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
-            assert.deepEqual(_.pick(attributes, ['id', 'name', 'created_at']), res.body, "model json returned. Body: #{util.inspect(res.body)}")
+            assert.deepEqual(expected = _.pick(attributes, ['id', 'name', 'created_at']), actual = res.body, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
             done()

     ######################################


Prevent holding on to instance variables

--- src/trix/views/document_view.coffee
+++ src/trix/views/document_view.coffee
@@ -15,24 +15,28 @@
     @element.removeChild(@element.lastChild) while @element.lastChild

     unless @document.isEmpty()
+      previousBlock = null
+      previousListTagName = null
+      listElement = null
+
       @document.eachBlock (block, blockIndex) =>
         blockView = @findOrCreateCachedChildView(Trix.BlockView, block, {blockIndex})
         blockElement = blockView.render()
         {listTagName} = blockView.blockConfig

         if listTagName
-          if @listElement and listTagName is @previousListTagName
-            @listElement.appendChild(blockElement)
+          if listElement and listTagName is previousListTagName
+            listElement.appendChild(blockElement)
           else
-            @listElement = document.createElement(listTagName)
-            @listElement.appendChild(blockElement)
-            @element.appendChild(@listElement)
+            listElement = document.createElement(listTagName)
+            listElement.appendChild(blockElement)
+            @element.appendChild(listElement)
         else
-          delete @listElement
+          listElement = null
           @element.appendChild(blockElement)

-        @previousBlock = block
-        @previousListTagName = listTagName
+        previousBlock = block
+        previousListTagName = listTagName

     @didRender()
     @element


Fixed error logging

Fixed error logging

--- client/import.coffee
+++ client/import.coffee
@@ -148,7 +148,7 @@

   hash.update file.content, (error) ->
     if error
-      Notify.error "Crypto error: #{ error.toString() }", null, true
+      Notify.error "Crypto error: #{ error.toString?() or error }", null, true, error.stack
       ImportingFile.documents.update file._id,
         $set:
           state: 'errored'
@@ -201,7 +201,7 @@
             state: 'preprocessed'

   reader.onerror = (error) ->
-    Notify.error "FileReader error: #{ error.toString() }", null, true
+    Notify.error "FileReader error: #{ error.toString?() or error }", null, true, error.stack
     ImportingFile.documents.update document._id,
       $set:
         state: 'errored'


CredentialStatusView: Defer emitting StatusChanged event.

there was a strange here case let's discuss it more. /cc @gokmen

--- client/admin/lib/views/stacks/credentialstatusview.coffee
+++ client/admin/lib/views/stacks/credentialstatusview.coffee
@@ -87,7 +87,7 @@
     @setInfo()
     @link.updatePartial message or 'Credentials are not set'
     @icon.unsetClass 'verified'
-    @emit 'StatusChanged', 'not-verified'
+    kd.utils.defer => @emit 'StatusChanged', 'not-verified'

     @stalledView.show()


change default pageSize

change default pageSize

--- client/app/controllers/collection_index_controller.coffee
+++ client/app/controllers/collection_index_controller.coffee
@@ -2,7 +2,7 @@
 module.exports = Ember.ArrayController.extend
   queryParams: ['pageNum', 'pageSize']
   pageNum: 1
-  pageSize: 25
+  pageSize: 50

   acont: (->
     cont = @get 'content'


Fix bug in detection of empty ranges

Fix bug in detection of empty ranges

--- annotran/static/scripts/annotator/sidebar.coffee
+++ annotran/static/scripts/annotator/sidebar.coffee
@@ -258,13 +258,12 @@
       if isClaimed
         break
     regex = "^\\s*$";
-    console.log(range.start.data)
     if ((selection_box.bottom == 0 &&
         selection_box.height == 0 &&
         selection_box.left == 0 &&
         selection_box.right == 0 &&
         selection_box.top == 0 &&
-        selection_box.width == 0) || (range.start.data == '') || (range.start.data.match(regex)))
+        selection_box.width == 0) || (range.text() == '') || (range.text().match(regex)))
       alert("You cannot create a new translation here. No text selected.")
       return


fix bug

fix bug

--- app/assets/javascripts/me-add-to-playlist.coffee
+++ app/assets/javascripts/me-add-to-playlist.coffee
@@ -107,7 +107,7 @@
                     <input name='_method' type='hidden' value='patch' />

-                    "+response.marker.title+"
+                    "+response.marker.title+"

                     "+mejs.Utility.secondsToTimeCode(response.marker.start_time/1000)+"


Remove hardcoded model

Remove hardcoded model

--- app/assets/javascripts/models/active_page.coffee
+++ app/assets/javascripts/models/active_page.coffee
@@ -8,8 +8,8 @@
       uuids.push($(tag).data("k-uuid"))

     # map args for JS array seem to differ from jQuery array above
-    collection_attrs = uuids.map (uuid, i) ->
-      new App.LineItem({uuid: uuid}).assign_attributes_from_page().attributes
+    collection_attrs = uuids.map (uuid, i) =>
+      new @({uuid: uuid}).assign_attributes_from_page().attributes

   append_to_page: ->
     $template = $(@template)


return 0 if undefined

return 0 if undefined

--- src/scripts/modules/media/tabs/contents/contents.coffee
+++ src/scripts/modules/media/tabs/contents/contents.coffee
@@ -68,7 +68,11 @@
       booksIn: () ->
         @model?.get('booksContainingPage')
       numBooks:() ->
-        @model?.get('booksContainingPage')?.length
+        hits = @model?.get('booksContainingPage')?.length
+        if hits
+          hits
+        else
+          0
       pageId:() ->
         (window.location.href.split '/')[4]


First draft of named classes.

First draft of named classes.

--- nodes.coffee
+++ nodes.coffee
@@ -823,6 +823,7 @@
         prop   = new AssignNode(val, func)
       props.push prop

+    constructor.className = className.match /[\w\d\$_]+$/
     constructor.body.unshift literal "#{me} = this" if me
     construct = @idt() + (new AssignNode(@variable, constructor)).compile(merge o, {sharedScope: constScope}) + ';'
     props     = if !props.empty() then '\n' + props.compile(o)                     else ''
@@ -991,9 +992,12 @@
     params = (param.compile(o) for param in params)
     @body.makeReturn() unless empty
     (o.scope.parameter(param)) for param in params
-    code = if @body.expressions.length then "\n#{ @body.compileWithDeclarations(o) }\n" else ''
-    func = "function(#{ params.join(', ') }) {#{code}#{ code and @tab }}"
-    return "(#{utility 'bind'}(#{func}, #{@context}))" if @bound
+    o.indent = @idt 2 if @className
+    code  = if @body.expressions.length then "\n#{ @body.compileWithDeclarations(o) }\n" else ''
+    open  = if @className then "(function() {\n#{@idt(1)}return function #{@className}(" else "function("
+    close = if @className then "#{code and @idt(1)}};\n#{@tab}})()" else "#{code and @tab}}"
+    func  = "#{open}#{ params.join(', ') }) {#{code}#{close}"
+    return "#{utility 'bind'}(#{func}, #{@context})" if @bound
     if top then "(#{func})" else func

   topSensitive: YES


done converting nodes.coffee code generation to use string interpolation where appropriate

--- nodes.coffee
+++ nodes.coffee
@@ -336,18 +336,16 @@
     return @compile_splat(o) if @args[@args.length - 1] instanceof SplatNode
     args: (arg.compile(o) for arg in @args).join(', ')
     return @compile_super(args, o) if @variable is 'super'
-    # "$@prefix${@variable.compile(o)}($args)"
-    @prefix + @variable.compile(o) + '(' + args + ')'
+    "$@prefix${@variable.compile(o)}($args)"

   # Compile a call against the superclass's implementation of the current function.
   compile_super: (args, o) ->
     methname: o.scope.method.name
-    arg_part: if args.length then ', ' + args else ''
     meth: if o.scope.method.proto
-      o.scope.method.proto + '.__superClass__.' + methname
+      "${o.scope.method.proto}.__superClass__.$methname"
     else
-      methname + '.__superClass__.constructor'
-    meth + '.call(this' + arg_part + ')'
+      "$methname.__superClass__.constructor"
+    "$meth.call(this${ if args.length then ', ' else '' }$args)"

   # Compile a function call being passed variable arguments.
   compile_splat: (o) ->
@@ -356,12 +354,12 @@
     if obj.match(/\(/)
       temp: o.scope.free_variable()
       obj:  temp
-      meth: '(' + temp + ' = ' + @variable.source + ')' + @variable.last
+      meth: "($temp = ${ @variable.source })${ @variable.last }"
     args: for arg, i in @args
       code: arg.compile o
-      code: if arg instanceof SplatNode then code else '[' + code + ']'
-      if i is 0 then code else '.concat(' + code + ')'
-    @prefix + meth + '.apply(' + obj + ', ' + args.join('') + ')'
+      code: if arg instanceof SplatNode then code else "[$code]"
+      if i is 0 then code else ".concat($code)"
+    "$@prefix$meth.apply($obj, ${ args.join('') })"

 # Node to extend an object's prototype with an ancestor object.
@@ -414,7 +412,8 @@
     @soak_node: tag is 'soak'

   compile_node: (o) ->
-    '[' + @index.compile(o) + ']'
+    idx: @index.compile o
+    "[$idx]"

 # A range literal. Ranges can be used to extract portions (slices) of arrays,
@@ -427,22 +426,22 @@
     @exclusive: !!exclusive

   compile_variables: (o) ->
-    @indent:   o.indent
-    @from_var: o.scope.free_variable()
-    @to_var:   o.scope.free_variable()
-    @from_var + ' = ' + @from.compile(o) + '; ' + @to_var + ' = ' + @to.compile(o) + ";\n" + @idt()
+    @indent: o.indent
+    [@from_var, @to_var]: [o.scope.free_variable(), o.scope.free_variable()]
+    [from, to]:           [@from.compile(o), @to.compile(o)]
+    "$@from_var = $from; $@to_var = $to;\n${@idt()}"

   compile_node: (o) ->
     return    @compile_array(o) unless o.index
     idx:      del o, 'index'
     step:     del o, 'step'
-    vars:     idx + ' = ' + @from_var
+    vars:     "$idx = $@from_var"
     step:     if step then step.compile(o) else '1'
     equals:   if @exclusive then '' else '='
-    intro:    '(' + @from_var + ' <= ' + @to_var + ' ? ' + idx
-    compare:  intro + ' <' + equals + ' ' + @to_var + ' : ' + idx + ' >' + equals + ' ' + @to_var + ')'
-    incr:     intro + ' += ' + step + ' : ' + idx + ' -= ' + step + ')'
-    vars + '; ' + compare + '; ' + incr
+    intro:    "($@from_var <= $@to_var ? $idx"
+    compare:  "$intro <$equals $@to_var : $idx >$equals $@to_var)"
+    incr:     "$intro += $step : $idx -= $step)"
+    "$vars; $compare; $incr"

   # Expand the range into the equivalent array, if it's not being used as
   # part of a comprehension, slice, or splice.
@@ -468,7 +467,7 @@
     from:       @range.from.compile(o)
     to:         @range.to.compile(o)
     plus_part:  if @range.exclusive then '' else ' + 1'
-    ".slice(" + from + ', ' + to + plus_part + ')'
+    ".slice($from, $to$plus_part)"

 # An object literal.
@@ -493,7 +492,7 @@
       indent + prop.compile(o) + join
     props: props.join('')
     inner: if props then '\n' + props + '\n' + @idt() else ''
-    '{' + inner + '}'
+    "{$inner}"

 # A class literal, including optional superclass and constructor.
@@ -534,7 +533,7 @@
     props:     if props.empty() then '' else props.compile(o) + '\n'
     extension: if extension     then @idt() + extension.compile(o) + ';\n' else ''
     returns:   if ret           then '\n' + @idt() + 'return ' + @variable.compile(o) + ';' else ''
-    construct + extension + props + returns
+    "$construct$extension$props$returns"

 statement ClassNode

@@ -551,14 +550,14 @@
     objects: for obj, i in @objects
       code: obj.compile(o)
       if obj instanceof CommentNode
-        '\n' + code + '\n' + o.indent
+        "\n$code\n${o.indent}"
       else if i is @objects.length - 1
         code
       else
-        code + ', '
+        "$code, "
     objects: objects.join('')
-    ending: if objects.indexOf('\n') >= 0 then "\n" + @idt() + ']' else ']'
-    '[' + objects + ending
+    ending: if objects.indexOf('\n') >= 0 then "\n${@idt()}]" else ']'
+    "[$objects$ending"

 # A faux-node that is never created by the grammar, but is used during
@@ -618,12 +617,13 @@
     if @value instanceof CodeNode
       @value.name:  last  if last.match(IDENTIFIER)
       @value.proto: proto if proto
-    return name + ': ' + @value.compile(o) if @context is 'object'
-    o.scope.find(name) unless @is_value() and @variable.has_properties()
-    val: name + ' = ' + @value.compile(o)
-    return @idt() + val + ';' if stmt
-    val: '(' + val + ')' if not top or o.returns
-    val: @idt() + 'return ' + val if o.returns
+    val: @value.compile o
+    return "$name: $val" if @context is 'object'
+    o.scope.find name unless @is_value() and @variable.has_properties()
+    val: "$name = $val"
+    return "${@idt()}$val;" if stmt
+    val: "($val)" if not top or o.returns
+    val: "${@idt()}return $val" if o.returns
     val

   # Implementation of recursive pattern matching, when assigning array or
@@ -632,7 +632,7 @@
   compile_pattern_match: (o) ->
     val_var: o.scope.free_variable()
     value: if @value.is_statement() then ClosureNode.wrap(@value) else @value
-    assigns: [@idt() + val_var + ' = ' + value.compile(o) + ';']
+    assigns: ["${@idt()}$val_var = ${ value.compile(o) };"]
     o.top: true
     o.as_statement: true
     for obj, i in @variable.base.objects
@@ -646,7 +646,7 @@
         val: new ValueNode(literal(val_var), [new access_class(idx)])
       assigns.push(new AssignNode(obj, val).compile(o))
     code: assigns.join("\n")
-    code += '\n' + @idt() + 'return ' + @variable.compile(o) + ';' if o.returns
+    code += "\n${@idt()}return ${ @variable.compile(o) };" if o.returns
     code

   compile_splice: (o) ->
@@ -656,7 +656,8 @@
     plus:   if range.exclusive then '' else ' + 1'
     from:   range.from.compile(o)
     to:     range.to.compile(o) + ' - ' + from + plus
-    name + '.splice.apply(' + name + ', [' + from + ', ' + to + '].concat(' + @value.compile(o) + '))'
+    val:    @value.compile(o)
+    "$name.splice.apply($name, [$from, $to].concat($val))"

 # A function definition. The only node that creates a new Scope.
@@ -684,13 +685,13 @@
       @body.unshift(splat)
     params: (param.compile(o) for param in @params)
     (o.scope.parameter(param)) for param in params
-    code: if @body.expressions.length then '\n' + @body.compile_with_declarations(o) + '\n' else ''
+    code: if @body.expressions.length then "\n${ @body.compile_with_declarations(o) }\n" else ''
     name_part: if @name then ' ' + @name else ''
-    func: 'function' + (if @bound then '' else name_part) + '(' + params.join(', ') + ') {' + code + @idt(if @bound then 1 else 0) + '}'
-    func: '(' + func + ')' if top and not @bound
+    func: "function${ if @bound then '' else name_part }(${ params.join(', ') }) {$code${@idt(if @bound then 1 else 0)}}"
+    func: "($func)" if top and not @bound
     return func unless @bound
-    inner: '(function' + name_part + '() {\n' + @idt(2) + 'return __func.apply(__this, arguments);\n' + @idt(1) + '});'
-    '(function(__this) {\n' + @idt(1) + 'var __func = ' + func + ';\n' + @idt(1) + 'return ' + inner + '\n' + @idt() + '})(this)'
+    inner: "(function$name_part() {\n${@idt(2)}return __func.apply(__this, arguments);\n${@idt(1)}});"
+    "(function(__this) {\n${@idt(1)}var __func = $func;\n${@idt(1)}return $inner\n${@idt()}})(this)"

   top_sensitive: ->
     true
@@ -704,7 +705,8 @@

   toString: (idt) ->
     idt ||= ''
-    '\n' + idt + @type + (child.toString(idt + TAB) for child in @real_children()).join('')
+    children: (child.toString(idt + TAB) for child in @real_children()).join('')
+    "\n$idt$children"

 # A splat, either as a parameter to a function, an argument to a call,
@@ -722,10 +724,10 @@
   compile_param: (o) ->
     name: @name.compile(o)
     o.scope.find name
-    name + ' = Array.prototype.slice.call(arguments, ' + @index + ')'
+    "$name = Array.prototype.slice.call(arguments, $@index)"

   compile_value: (o, name, index) ->
-    "Array.prototype.slice.call(" + name + ', ' + index + ')'
+    "Array.prototype.slice.call($name, $index)"

 # A while loop, the only sort of low-level loop exposed by CoffeeScript. From
@@ -753,13 +755,13 @@
     set:        ''
     if not top
       rvar:     o.scope.free_variable()
-      set:      @idt() + rvar + ' = [];\n'
+      set:      "${@idt()}$rvar = [];\n"
       @body:    PushNode.wrap(rvar, @body) if @body
-    post:       if returns then '\n' + @idt() + 'return ' + rvar + ';' else ''
-    pre:        set + @idt() + 'while (' + cond + ')'
-    return pre + ' null;' + post if not @body
+    post:       if returns then "\n${@idt()}return $rvar;" else ''
+    pre:        "$set${@idt()}while ($cond)"
+    return      "$pre null;$post" if not @body
     @body:      Expressions.wrap([new IfNode(@filter, @body)]) if @filter
-    pre + ' {\n' + @body.compile(o) + '\n' + @idt() + '}' + post
+    "$pre {\n${ @body.compile(o) }\n${@idt()}}$post"

 statement WhileNode

@@ -801,24 +803,26 @@
     return @compile_assignment(o) if @ASSIGNMENT.indexOf(@operator) >= 0
     return @compile_unary(o)      if @is_unary()
     return @compile_existence(o)  if @operator is '?'
-    @first.compile(o) + ' ' + @operator + ' ' + @second.compile(o)
+    [@first.compile(o), @operator, @second.compile(o)].join ' '

   # Mimic Python's chained comparisons. See:
   # http://docs.python.org/reference/expressions.html#notin
   compile_chain: (o) ->
     shared: @first.unwrap().second
     [@first.second, shared]: shared.compile_reference(o) if shared instanceof CallNode
-    '(' + @first.compile(o) + ') && (' + shared.compile(o) + ' ' + @operator + ' ' + @second.compile(o) + ')'
+    [first, second, shared]: [@first.compile(o), @second.compile(o), shared.compile(o)]
+    "($first) && ($shared $@operator $second)"

   compile_assignment: (o) ->
     [first, second]: [@first.compile(o), @second.compile(o)]
     o.scope.find(first) if first.match(IDENTIFIER)
-    return first + ' = ' + ExistenceNode.compile_test(o, @first) + ' ? ' + first + ' : ' + second if @operator is '?='
-    first + ' = ' + first + ' ' + @operator.substr(0, 2) + ' ' + second
+    return "$first = ${ ExistenceNode.compile_test(o, @first) } ? $first : $second" if @operator is '?='
+    "$first = $first ${ @operator.substr(0, 2) } $second"

   compile_existence: (o) ->
     [first, second]: [@first.compile(o), @second.compile(o)]
-    ExistenceNode.compile_test(o, @first) + ' ? ' + first + ' : ' + second
+    test: ExistenceNode.compile_test(o, @first)
+    "$test ? $first : $second"

   compile_unary: (o) ->
     space: if @PREFIX_OPERATORS.indexOf(@operator) >= 0 then ' ' else ''
@@ -839,10 +843,11 @@
   compile_node: (o) ->
     o.indent:     @idt(1)
     o.top:        true
-    error_part:   if @error then ' (' + @error.compile(o) + ') ' else ' '
-    catch_part:   (@recovery or '') and ' catch' + error_part + '{\n' + @recovery.compile(o) + '\n' + @idt() + '}'
-    finally_part: (@ensure or '') and ' finally {\n' + @ensure.compile(merge(o, {returns: null})) + '\n' + @idt() + '}'
-    @idt() + 'try {\n' + @attempt.compile(o) + '\n' + @idt() + '}' + catch_part + finally_part
+    attempt_part: @attempt.compile(o)
+    error_part:   if @error then " (${ @error.compile(o) }) " else ' '
+    catch_part:   "${ (@recovery or '') and ' catch' }$error_part{\n${ @recovery.compile(o) }\n${@idt()}}"
+    finally_part: (@ensure or '') and ' finally {\n' + @ensure.compile(merge(o, {returns: null})) + "\n${@idt()}}"
+    "${@idt()}try {\n$attempt_part\n${@idt()}}$catch_part$finally_part"

 statement TryNode

@@ -855,7 +860,7 @@
     @children: [@expression: expression]

   compile_node: (o) ->
-    @idt() + 'throw ' + @expression.compile(o) + ';'
+    "${@idt()}throw ${@expression.compile(o)};"

 statement ThrowNode, true

@@ -874,7 +879,8 @@
   [first, second]: [variable, variable]
   if variable instanceof CallNode or (variable instanceof ValueNode and variable.has_properties())
     [first, second]: variable.compile_reference(o)
-  '(typeof ' + first.compile(o) + ' !== "undefined" && ' + second.compile(o) + ' !== null)'
+  [first, second]: [first.compile(o), second.compile(o)]
+  "(typeof $first !== \"undefined\" && $second !== null)"

 # An extra set of parentheses, specified explicitly in the source.
@@ -892,7 +898,7 @@
     return code if @is_statement()
     l:    code.length
     code: code.substr(o, l-1) if code.substr(l-1, 1) is ';'
-    '(' + code + ')'
+    "($code)"

 # The replacement for the for loop is an array comprehension (that compiles)
@@ -921,10 +927,10 @@
     range:          @source instanceof ValueNode and @source.base instanceof RangeNode and not @source.properties.length
     source:         if range then @source.base else @source
     scope:          o.scope
-    name:           @name and @name.compile(o)
-    index:          @index and @index.compile(o)
-    name_found:     name and scope.find(name)
-    index_found:    index and scope.find(index)
+    name:           @name and @name.compile o
+    index:          @index and @index.compile o
+    name_found:     name and scope.find name
+    index_found:    index and scope.find index
     body_dent:      @idt(1)
     rvar:           scope.free_variable() unless top_level
     svar:           scope.free_variable()
@@ -933,16 +939,17 @@
     body:           Expressions.wrap([@body])
     if range
       index_var:    scope.free_variable()
-      source_part:  source.compile_variables(o)
-      for_part:     index_var + ' = 0, ' + source.compile(merge(o, {index: ivar, step: @step})) + ', ' + index_var + '++'
+      source_part:  source.compile_variables o
+      for_part:     source.compile merge o, {index: ivar, step: @step}
+      for_part:     "$index_var = 0, $for_part, $index_var++"
     else
       index_var:    null
-      source_part:  svar + ' = ' + @source.compile(o) + ';\n' + @idt()
-      var_part:     body_dent + name + ' = ' + svar + '[' + ivar + '];\n' if name
+      source_part:  "$svar = ${ @source.compile(o) };\n${@idt()}"
+      var_part:     "$body_dent$name = $svar[$ivar];\n" if name
       if not @object
         lvar:       scope.free_variable()
-        step_part:  if @step then ivar + ' += ' + @step.compile(o) else ivar + '++'
-        for_part:   ivar + ' = 0, ' + lvar + ' = ' + svar + '.length; ' + ivar + ' < ' + lvar + '; ' + step_part
+        step_part:  if @step then "$ivar += ${ @step.compile(o) }" else "$ivar++"
+        for_part:   "$ivar = 0, $lvar = $svar.length; $ivar < $lvar; $step_part"
     set_result:     if rvar then @idt() + rvar + ' = []; ' else @idt()
     return_result:  rvar or ''
     body:           ClosureNode.wrap(body, true) if top_level and @contains (n) -> n instanceof CodeNode
@@ -955,12 +962,12 @@
       body:         Expressions.wrap([new IfNode(@filter, body)])
     if @object
       o.scope.assign('__hasProp', 'Object.prototype.hasOwnProperty', true)
-      for_part: ivar + ' in ' + svar + ') { if (__hasProp.call(' + svar + ', ' + ivar + ')'
-    return_result:  '\n' + @idt() + return_result + ';' unless top_level
+      for_part: "$ivar in $svar) { if (__hasProp.call($svar, $ivar)"
+    return_result:  "\n${@idt()}$return_result;" unless top_level
     body:           body.compile(merge(o, {indent: body_dent, top: true}))
-    vars:           if range then name else name + ', ' + ivar
+    vars:           if range then name else "$name, $ivar"
     close:          if @object then '}}\n' else '}\n'
-    set_result + source_part + 'for (' + for_part + ') {\n' + var_part + body + '\n' + @idt() + close + @idt() + return_result
+    "$set_result${source_part}for ($for_part) {\n$var_part$body\n${@idt()}$close${@idt()}$return_result"

 statement ForNode

@@ -1045,18 +1052,18 @@
     o.top:        true
     if_dent:      if child then '' else @idt()
     com_dent:     if child then @idt() else ''
-    prefix:       if @comment then @comment.compile(cond_o) + '\n' + com_dent else ''
+    prefix:       if @comment then "${ @comment.compile(cond_o) }\n$com_dent" else ''
     body:         Expressions.wrap([@body]).compile(o)
-    if_part:      prefix + if_dent + 'if (' + @compile_condition(cond_o) + ') {\n' + body + '\n' + @idt() + '}'
+    if_part:      "$prefix${if_dent}if (${ @compile_condition(cond_o) }) {\n$body\n${@idt()}}"
     return if_part unless @else_body
     else_part: if @is_chain()
       ' else ' + @else_body.compile(merge(o, {indent: @idt(), chain_child: true}))
     else
-      ' else {\n' + Expressions.wrap([@else_body]).compile(o) + '\n' + @idt() + '}'
-    if_part + else_part
+      " else {\n${ Expressions.wrap([@else_body]).compile(o) }\n${@idt()}}"
+    "$if_part$else_part"

   # Compile the IfNode into a ternary operator.
   compile_ternary: (o) ->
     if_part:    @condition.compile(o) + ' ? ' + @body.compile(o)
     else_part:  if @else_body then @else_body.compile(o) else 'null'
-    if_part + ' : ' + else_part
+    "$if_part : $else_part"


Making the spacing of symbols on function declaration consistent. No-space when single-line. Spaced when block. (StanAngeloff)

--- nodes.coffee
+++ nodes.coffee
@@ -209,7 +209,7 @@
     code: @compileWithDeclarations(o)
     code: code.replace(TRAILING_WHITESPACE, '')
     code: code.replace(DOUBLE_PARENS, '($1)')
-    if o.noWrap then code else "(function(){\n$code\n})();\n"
+    if o.noWrap then code else "(function() {\n$code\n})();\n"

   # Compile the expressions body for the contents of a function, with
   # declarations of all inner variables pushed up to the top.
@@ -459,7 +459,7 @@
       utility 'extends'
       """
       (function() {
-      ${@idt(1)}var ctor = function(){ };
+      ${@idt(1)}var ctor = function(){};
       ${@idt(1)}__extends(ctor, $meth);
       ${@idt(1)}return ${meth}.apply(new ctor, ${ @compileSplatArguments(o) });
       $@tab}).call(this)
@@ -590,7 +590,7 @@
       clause: "$@fromVar <= $@toVar ?"
       body:   "var $i = $@fromVar; $clause $i <$@equals $@toVar : $i >$@equals $@toVar; $clause $i += 1 : $i -= 1"
     post:   "{ ${result}.push($i) };\n${idt}return $result;\n$o.indent"
-    "(function(){${pre}\n${idt}for ($body)$post}).call(this)"
+    "(function() {${pre}\n${idt}for ($body)$post}).call(this)"

 #### SliceNode

@@ -1487,7 +1487,7 @@
   # [goog.inherits](http://closure-library.googlecode.com/svn/docs/closureGoogBase.js.source.html#line1206).
   extends:  """
             function(child, parent) {
-                var ctor = function(){ };
+                var ctor = function(){};
                 ctor.prototype = parent.prototype;
                 child.prototype = new ctor();
                 child.prototype.constructor = child;


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera_fade.coffee
+++ src/camera_fade.coffee
@@ -16,7 +16,7 @@
     duration: 30
     color: 'black'

-
+  fadeOut

   configureFade = (duration, color, alpha) ->
     I.flashDuration = duration


Give it more time as travis seems to struggle

--- src/spec/integration/import.spec.coffee
+++ src/spec/integration/import.spec.coffee
@@ -36,7 +36,7 @@
     .then -> done()
     .catch (err) -> done _.prettify(err)
     .done()
-  , 30000 # 30sec
+  , 40000 # 40sec

   describe '#import', ->

@@ -64,7 +64,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should import a product with prices', (done) ->
       csv =
@@ -91,7 +91,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should do nothing on 2nd import run', (done) ->
       csv =
@@ -112,7 +112,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should update changes on 2nd import run', (done) ->
       csv =
@@ -143,7 +143,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should handle all kind of attributes and constraints', (done) ->
       csv =
@@ -196,7 +196,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should handle multiple products', (done) ->
       p1 = TestHelpers.uniqueId 'name1-'
@@ -242,7 +242,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should handle set of enums', (done) ->
       csv =
@@ -282,7 +282,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should handle set of SameForAll enums with new variants', (done) ->
       csv =
@@ -337,7 +337,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should remove a variant and change an SameForAll attribute at the same time', (done) ->
       csv =
@@ -371,7 +371,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should not removeVariant if allowRemovalOfVariants is off', (done) ->
       csv =
@@ -404,7 +404,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should execute SameForAll attribute change before addVariant', (done) ->
       csv =
@@ -443,7 +443,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should do a partial update of product base attributes', (done) ->
       csv =
@@ -487,7 +487,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should do a partial update of localized attributes', (done) ->
       csv =
@@ -531,7 +531,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should do a partial update of custom attributes', (done) ->
       csv =
@@ -589,7 +589,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'partial update should not overwrite name, prices and images', (done) ->
       csv =
@@ -626,7 +626,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should do a full update of SEO attribute', (done) ->
       csv =
@@ -660,7 +660,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should do a full update of multi language SEO attribute', (done) ->
       csv =
@@ -693,7 +693,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should not update SEO attribute if not all 3 headers are present', (done) ->
@@ -727,7 +727,7 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec

     it 'should do a partial update of prices based on SKUs', (done) ->
       csv =
@@ -763,4 +763,4 @@
         done()
       .catch (err) -> done _.prettify(err)
       .done()
-    , 30000 # 30sec
+    , 40000 # 40sec


Simplified error messages to jsut cover the reason for failure. UI adds the rest

--- src/steroids/servers/BuildServer.coffee
+++ src/steroids/servers/BuildServer.coffee
@@ -222,7 +222,7 @@
       .then ->
         res.status(200).send "Success!"
       .catch (error)->
-        message = "Could not generate successfully. #{error.message}"
+        message = "#{error.message}"
         res.status(404).json {error: message}

     helper "get", "/__appgyver/emulators/:emulator/:action", (req, res) =>