Check if valid JSON format on coordinates field

--- app/assets/javascripts/areas.js.coffee
+++ app/assets/javascripts/areas.js.coffee
@@ -43,6 +43,7 @@

 findAreaCoordinates = ->
   return window.areaCoordinates if window.areaCoordinates?
-  return JSON.parse($('#area_coordinates').val()) if $('#area_coordinates').length > 0 && $('#area_coordinates').val() != ''

-  return false
+  try
+    return JSON.parse($('#area_coordinates').val()) if $('#area_coordinates').length > 0
+  false


remove unecessary file

remove unecessary file

--- app/assets/javascripts/codes.js.coffee
+++ app/assets/javascripts/codes.js.coffee
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/


removed unused file

removed unused file

--- app/assets/javascripts/comments.coffee
+++ app/assets/javascripts/comments.coffee
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/


working on heroku deploy error

working on heroku deploy error

--- app/assets/javascripts/contacts.coffee
+++ app/assets/javascripts/contacts.coffee
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/


Care the link to get complex deal form

Care the link to get complex deal form

--- app/assets/javascripts/deals.js.coffee
+++ app/assets/javascripts/deals.js.coffee
@@ -77,8 +77,10 @@

   # a.edit_click
   $(document).on('click', 'a.edit_deal', (event)->
+    $tr = $(@).closest('tr')
+    if $tr.hasClass('edit_deal_row')
+      $tr = $tr.prev()
     $('.edit_deal_row').remove()
-    $tr = $(@).closest('tr')
     while !$tr.hasClass('last_entry')
       $tr = $tr.next()
     $tr.after("

")


added some additional fixed

added some additional fixed

--- app/assets/javascripts/users.js.coffee
+++ app/assets/javascripts/users.js.coffee
@@ -17,18 +17,35 @@
 $ ->
   isVisible = false
   clickedAway = false
-
   $('.comment-user-name').popover(
     html: true,
     placement: 'top',
     trigger: 'manual'
-  ).click((e)->
+  )
+  $('.comment-user-name').click((e)->
     if isVisible
-      $(this).popover('hide')
-      isVisible = false
-      clickedAway = false
+      console.log("isVisible")
+      if not $(this).hasClass('popover-visible')
+        console.log("there is a popup visible and but not this one")
+        $('.comment-user-name').popover('hide')
+        $('.comment-user-name').removeClass('popover-visible')
+        console.log("remove all popups1")
+        $(this).popover('toggle')
+        console.log("show this popup and add class visible")
+        $(this).addClass('popover-visible')
+        isVisible = true
+        clickedAway = false
+      else
+        console.log("clicked popup was visible")
+        $('.comment-user-name').popover('hide')
+        $('.comment-user-name').removeClass('popover-visible')
+        console.log("remove all popups2")
+        isVisible = false
+        clickedAway = false
     else
+      console.log("non-visible, showing popover")
       $(this).popover('show')
+      $(this).addClass('popover-visible')
       clickedAway = false
       isVisible = true
     e.preventDefault()
@@ -36,8 +53,13 @@

   $(document).click((e)->
     if(isVisible & clickedAway)
-      $('.comment-user-name').popover('hide')
-      isVisible = clickedAway = false
+      console.log("visible and clickedAway - hiding popover")
+      #$('.comment-user-name').popover('hide')
+      #$('.comment-user-name').removeClass('popover-visible')
+      isVisible = false
+      clickedAway = false
     else
+      console.log("clickedAway = true")
+      console.log("-------------------")
       clickedAway = true
   )


add connection to database to controller

--- app/controllers/data_controller.coffee
+++ app/controllers/data_controller.coffee
@@ -1,4 +1,11 @@
 load 'application'
+
+cradle = require "cradle"
+
+connection = new cradle.Connection
+    cache: true,
+    raw: false
+db = connection.database("cozy")

 action 'exist', ->


Add 'deepwater' as a valid model type, behaves like 'deeplearning'

--- src/ext/components/model-output.coffee
+++ src/ext/components/model-output.coffee
@@ -298,7 +298,7 @@
             if confusionMatrix = output.cross_validation_metrics?.cm?.table
               renderMultinomialConfusionMatrix 'Cross Validation Metrics - Confusion Matrix', confusionMatrix

-      when 'deeplearning'
+      when 'deeplearning', 'deepwater'
         if table = _.inspect 'output - Scoring History', _model
           if table.schema['validation_logloss'] and table.schema['training_logloss']
             renderPlot 'Scoring History - logloss', no, _.plot (g) ->


fixed spelling of "diaeresis" in help-urls.coffee

--- docs/help-urls.coffee
+++ docs/help-urls.coffee
@@ -201,9 +201,9 @@
   '⍪': 'lang/symbols/comma-bar'
   ',': 'lang/symbols/comma'
   '⊥': 'lang/symbols/decode-symbol'
-  '¨': 'lang/symbols/dieresis'
-  '⍣': 'lang/symbols/dieresisstar'
-  '⍨': 'lang/symbols/dieresis-tilde'
+  '¨': 'lang/symbols/diaeresis'
+  '⍣': 'lang/symbols/diaeresisstar'
+  '⍨': 'lang/symbols/diaeresis-tilde'
   '÷': 'lang/symbols/divide-sign'
   '⌹': 'lang/symbols/domino'
   '.': 'lang/symbols/dot'


[accounts] fixed 1st time account register.  New accounts were registering as delegates.

--- app/js/controllers/registration.coffee
+++ app/js/controllers/registration.coffee
@@ -37,7 +37,7 @@
     $modalInstance.dismiss "cancel"

   $scope.ok = ->  # $scope.payWith is not in modal's scope FFS!!!
-    payrate = if $scope.m.delegate then $scope.m.payrate else 255
+    payrate = if $scope.m.delegate then $scope.m.payrate else -1
     if $scope.account.private_data?.gui_data?.website
         website= $scope.account.private_data.gui_data.website
     else


Prevent Publications page crashing on staging (#3932)

--- app/pages/about/publications-page.cjsx
+++ app/pages/about/publications-page.cjsx
@@ -66,7 +66,7 @@

                 {for projectListing in projects
                   project = @state.projects[projectListing.slug]
-

+

                         {if project then project.display_name else projectListing.name}


fun with coffeescript

fun with coffeescript

--- app/scripts/alchemy/defaultConf.coffee
+++ app/scripts/alchemy/defaultConf.coffee
@@ -5,7 +5,7 @@

     # Layout
     graphWidth: d3.select(".alchemy").node().parentElement.clientWidth
-    graphHeight: () ->
+    graphHeight: do () ->
         if d3.select(".alchemy").node().parentElement.nodeName == "BODY"
             return window.innerHeight
         else


Fix an issue in the client example logging.

--- example/client.coffee
+++ example/client.coffee
@@ -5,10 +5,10 @@
   handle = client.submitTask "Reverse", "hello world"

   handle.on "submit", ->
-    console.log "Submitted: %s", handle.id
+    console.log "Submitted: %s", @id

   handle.on "complete", (data) ->
-    console.log "Completed: %s (%s)", handle.id, data
+    console.log "Completed: %s (%s)", @id, data

   handle.on "error", (error) ->
-    console.error "Failed: %s (%s)", handle.id, error
+    console.error "Failed: %s (%s)", @id, error


Lower timeout in CI.

Lower timeout in CI.

--- test/util.coffee
+++ test/util.coffee
@@ -37,5 +37,5 @@

 TIMEOUT = 5000
 if process.env.TRAVIS
-  TIMEOUT = TIMEOUT * 10
+  TIMEOUT = TIMEOUT * 3
 exports.TIMEOUT = TIMEOUT


Added name to Player class

Added name to Player class

--- player.coffee
+++ player.coffee
@@ -18,7 +18,7 @@

   class Player

-    constructor: (pos) ->
+    constructor: (@name, pos) ->
       @positions = []
       @positions.push(pos)
       @current_line = []


renamed variable "execQueue" to "pending"

--- client/ide.coffee
+++ client/ide.coffee
@@ -20,7 +20,7 @@
   """

   isDead = 0
-  execQueue = [] # pending lines to execute: AtInputPrompt consumes one item from the queue, HadError empties it
+  pending = [] # pending lines to execute: AtInputPrompt consumes one item from the queue, HadError empties it

   # "wins" maps window ids, as they appear in the RIDE protocol, to window information objects that have the following properties:
   #   widget: a session or an editor
@@ -31,7 +31,7 @@
       autocomplete: (s, i) -> D.socket.emit 'Autocomplete', line: s, pos: i, token: 0
       exec: (lines, trace) ->
         if lines && lines.length
-          if !trace then execQueue = lines[1..]
+          if !trace then pending = lines[1..]
           D.socket.emit 'Execute', {trace, text: lines[0] + '\n'}
         return

@@ -83,9 +83,9 @@
     .on 'AppendSessionOutput', ({result}) -> session.add result
     .on 'NotAtInputPrompt', -> session.noPrompt()
     .on 'AtInputPrompt', ({why}) ->
-      if execQueue.length then D.socket.emit 'Execute', trace: 0, text: execQueue.shift() + '\n' else session.prompt why
+      if pending.length then D.socket.emit 'Execute', trace: 0, text: pending.shift() + '\n' else session.prompt why
       return
-    .on 'HadError', -> execQueue.splice 0, execQueue.length; return
+    .on 'HadError', -> pending.splice 0, pending.length; return
     .on 'FocusWindow', ({win}) -> $("#wintab#{win} a").click(); wins[win].widget.focus(); return
     .on 'WindowTypeChanged', ({win, tracer}) -> wins[win].widget.setDebugger tracer
     .on 'autocomplete', (token, skip, options) -> wins[token].widget.autocomplete skip, options


kbd icon links to Prefs>Keys; added "..." to tooltip

--- client/ide.coffee
+++ client/ide.coffee
@@ -105,7 +105,7 @@
     @unblock = -> (while mq.length then handle mq.shift()); blocked = 0; return

     # language bar
-    $('.lbar-prefs').click -> prefsUI.showDialog 'glyphs'; return
+    $('.lbar-prefs').click -> prefsUI.showDialog 'keys'; return
     $tip = $ '.lbar-tip'; $tipDesc = $ '.lbar-tip-desc'; $tipText = $ '.lbar-tip-text'; $tipTriangle = $ '.lbar-tip-triangle'
     ttid = null # tooltip timeout id
     requestTooltip = (e, desc, text) -> # e: element
@@ -136,7 +136,7 @@
           pad = Array(Math.max 0, 25 - desc.length).join ' '
           ks = h[code] || defaults
           s += "#{code}: #{desc}:#{pad} #{ks[ks.length - 1] || 'none'}\n"
-        requestTooltip e, 'Keyboard Shortcuts', s
+        requestTooltip e, 'Keyboard Shortcuts', s + '...'
         return

     @layout = @$ide.layout


Adding single comments describing different approaches.

--- src/polvo/core/optimizer/loader.coffee
+++ src/polvo/core/optimizer/loader.coffee
@@ -90,11 +90,13 @@
       var refresher = io.connect("http://localhost");
       refresher.on("refresh", function(data)
       {
+        var el;
+
+        // refresh approach for javascript and templates
         if(data.file_type == 'javascript' || data.file_type == 'template' )
           return location.reload();

-        var el;
-
+        // refresh approach for styles
         if(data.file_type == 'style') {
           el = document.getElementById( data.file_id );
           el.parentNode.removeChild( el );


Make sure the super type of a member exists

--- src/rules/mson-member-type-name.coffee
+++ src/rules/mson-member-type-name.coffee
@@ -30,7 +30,7 @@
           superType = member.content.valueDefinition.typeDefinition.typeSpecification.name

           # If super type is a valid symbol
-          if typeof superType is 'object' and superType?.literal
+          if typeof superType is 'object' and superType?.literal and @dataStructures[superType.literal]
             @expandMember superType.literal, @dataStructures[superType.literal]

             superTypeBaseName = @dataStructures[superType.literal].typeDefinition.typeSpecification.name


Updated mailchimp dependency to 1.1.0

Updated mailchimp dependency to 1.1.0

the npm package added URLEncodings to body in version 0.9.6

--- src/scripts/mailchimp-subscribe.coffee
+++ src/scripts/mailchimp-subscribe.coffee
@@ -2,7 +2,7 @@
 #   Add email to Mailchimp list
 #
 # Dependencies:
-#   "mailchimp": "0.9.5"
+#   "mailchimp": "1.1.0"
 #
 # Configuration:
 #   MAILCHIMP_API_KEY


Add some german umlauts into spec.

Add some german umlauts into spec.

--- src/spec/integration/impex.spec.coffee
+++ src/spec/integration/impex.spec.coffee
@@ -69,7 +69,7 @@
     p1 =
       """
       #{@productType.name},myProduct1,my-slug1,1,sku1,FR-EUR 999;CHF 1099,some Text,foo
-      ,,,2,sku2,EUR 799,some other Text,foo,t1;t2;t3
+      ,,,2,sku2,EUR 799,some other Text,foo,t1;t2;t3;Üß
       """
     p2 =
       """


WIP s3client specs

WIP s3client specs

--- src/spec/services/s3client.spec.coffee
+++ src/spec/services/s3client.spec.coffee
@@ -1,4 +1,5 @@
 _ = require 'underscore'
+Promise = require 'bluebird'
 S3Client = require '../../lib/services/s3client'

 CREDENTIALS =
@@ -13,6 +14,7 @@

   it 'should initialize with credentials', ->
     expect(@s3client).toBeDefined()
+    expect(@s3client._ee).toBeDefined()
     expect(@s3client._knoxClient).toBeDefined()

   _.each ['key', 'secret', 'bucket'], (key) ->
@@ -21,3 +23,40 @@
       delete opt[key]
       client = -> new S3Client opt
       expect(client).toThrow new Error("Missing AWS '#{key}'")
+
+  it 'should use event emitter', (done) ->
+    @s3client.on 'foo', (foo) ->
+      expect(foo).toBe 'bar'
+      done()
+    @s3client.emit 'foo', 'bar'
+
+  describe ':: list', ->
+
+    it 'should call underlying function', ->
+      spyOn(@s3client._knoxClient, 'listAsync')
+      @s3client.list prefix: 'foo'
+      expect(@s3client._knoxClient.listAsync).toHaveBeenCalledWith prefix: 'foo'
+
+  describe ':: filteredList', ->
+
+    beforeEach ->
+      spyOn(@s3client._knoxClient, 'listAsync').andReturn new Promise (resolve, reject) ->
+        resolve
+          Contents: [{Size: 1, Key: 'foo'}, {Size: 0, Key: 'bar'}]
+
+    it 'should filter list without folders', (done) ->
+      @s3client.filteredList prefix: 'foo', null, true
+      .then (filtered) ->
+        expect(filtered.length).toBe 1
+        expect(filtered[0].Key).toBe 'foo'
+        done()
+      .catch (err) -> done(err)
+
+    it 'should filter list with folders', (done) ->
+      @s3client.filteredList prefix: 'foo', null, false
+      .then (filtered) ->
+        expect(filtered.length).toBe 2
+        expect(filtered[0].Key).toBe 'foo'
+        expect(filtered[1].Key).toBe 'bar'
+        done()
+      .catch (err) -> done(err)


more tests for Model

more tests for Model

--- test/Bacon.JQuery.Bindings.Spec.coffee
+++ test/Bacon.JQuery.Bindings.Spec.coffee
@@ -18,11 +18,20 @@
     b.set("wat")
     b.set("asdf")
     expect(values).to.deep.equal(["wat", "asdf"])
+  it "handles undefined like any other value", ->
+    b = bjb.Model()
+    values = collect(b)
+    b.set("wat")
+    b.set(undefined)
+    expect(values).to.deep.equal(["wat", undefined])

 describe "Model initial value", ->
   it "is sent", ->
     cylinders = bjb.Model(12)
     expect(collect(cylinders)).to.deep.equal([12])
+  it "handles undefined like any other value", ->
+    cylinders = bjb.Model(undefined)
+    expect(collect(cylinders)).to.deep.equal([undefined])
   it "can be omitted", ->
     cylinders = bjb.Model()
     expect(collect(cylinders)).to.deep.equal([])


Tweak

Tweak

--- test/spec/core/view-model.tests.coffee
+++ test/spec/core/view-model.tests.coffee
@@ -947,6 +947,7 @@
     assert.equal(kb.statistics.registeredStatsString('all released'), 'all released', "Cleanup: stats"); kb.statistics = null
     done()

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


fixing contributor scenario for clicking a point

Former-commit-id: 287cf64ebf3ed018e0dd99b0d22fc08cb1b531ee [formerly e3a8a7587231a507637e8bb10f76e52cac300c83] [formerly fb7cc3fa40c5e83f2b5e4043f757e19e7aefe80d [formerly 42bc91dcb5e78f9e90b6334a6fb88f5897221912]] [formerly 76ac3bab91355bd8c5c47260ec3d69c21b841af3 [formerly 66e0534dda688af56a16bd579caa5a643032dc5d] [formerly 44aaaf6410dc217b320820c9d926bfdc1d0f7b0a [formerly 44aaaf6410dc217b320820c9d926bfdc1d0f7b0a [formerly 2d9de452a454b06fc9041f77913fc9893478dd78]]]]
Former-commit-id: 048a51988313792d2516f6c55c47f962d69ca633 [formerly 1bc362b16b801cbbf5f62e8e5fd777dfe0b40177] [formerly 63a39818b7854d0d1f99f4d01e110006bb515bb9 [formerly 8e23d63fc896fe80e283c8f7b25d471174bc4b64]]
Former-commit-id: 99dfd9bd8453fbef9a7c02003c3386207a0d6cec [formerly 6f1c36b498691bd5d19e43e4a44fe9795f55f0e8]
Former-commit-id: 5f98eb3f997d50ec76f5876492c700b535b60909
Former-commit-id: eb8240626a3a77a178223b7051ed50451507f8e5

--- test/tests/contributor_scenario.coffee
+++ test/tests/contributor_scenario.coffee
@@ -62,7 +62,7 @@
       anonymous : true
       nutshell : 'Secretly I am in favor of this for the simple fact that it will benefit me and me alone'
       details : ''
-  included_points : [3472, 3492, 3539]
+    included_points : [ [3472, true], [3492, false], [3539, false]]

 testCraftingOpinion = (test, opinion, state_suffix) ->

@@ -100,29 +100,28 @@

   # include some points
   casper.then ->
-    use_drag_and_drop = false #drag and drop is not yet working
+    use_drag_and_drop = false #drag and drop is not yet working in casper
     casper.HTMLStep 'including some points' + state_suffix
-    _.each opinion.included_points, (point_id) ->
+    _.each opinion.included_points, (point) ->
+      [point_id, is_pro] = point
       casper.then ->
         draggable = "[role='point'][data-id='#{point_id}']"
         target = ".add_point_drop_target"

         # expand points if draggable isn't currently visible
         if !casper.exists draggable
+          points_col = if is_pro then '.pros_by_community' else '.cons_by_community'
           casper.then ->
-            for points_col in ['.pros_by_community', '.cons_by_community']
-              casper.click "#{points_col} [action='expand-toggle']"
-              if casper.exists draggable
-                break
-
-        casper.then ->
+            casper.click "#{points_col} [action='expand-toggle']"
+
+        casper.wait 50, ->
           if use_drag_and_drop
             casper.dragAndDrop draggable, target
           else
             # include by opening point
-            casper.click draggable
+            casper.click draggable + ' .point_content'
             casper.waitUntilVisible draggable + '.open_point', ->
-              casper.thenClick draggable + '.open_point' + ' [action="point-include"]', ->
+              casper.click draggable + '.open_point' + ' [action="point-include"]'

         casper.wait 1000, ->   #waitUntilVisible ".opinion_region #{draggable}", ->
           # test.assertVisible ".opinion_region #{draggable}", 'point has been included'
@@ -162,7 +161,8 @@
     points_col = if point.is_pro then '.pros_on_decision_board' else '.cons_on_decision_board'
     @assertSelectorHasText "#{points_col} .point_nutshell", point.nutshell, 'Point has been saved'

-  _.each opinion.included_points, (point_id) =>
+  _.each opinion.included_points, (point) =>
+    [point_id, is_pro] = point
     @assertVisible ".opinion_region [role='point'][data-id='#{point_id}']", 'point has been included'

   slider_base_pos = casper.getElementBounds '.noUi-base'
@@ -198,8 +198,7 @@
           anonymous : true
           nutshell : 'Secretly I am in favor of this for the simple fact that it will benefit me and me alone'
           details : ''
-      included_points : [3472, 3492, 3539]
-
+      included_points : [ [3472, true], [3492, false], [3539, false]]

     state_suffix = if is_logged_in then ' when logged in' else ' when logged out'


Add minimize/maxmize to AtomWindow

Add minimize/maxmize to AtomWindow

--- src/browser/atom-window.coffee
+++ src/browser/atom-window.coffee
@@ -138,6 +138,10 @@

   getSize: -> @browserWindow.getSize()

+  minimize: -> @browserWindow.minimize()
+
+  maximize: -> @browserWindow.maximize()
+
   handlesAtomCommands: ->
     not @isSpecWindow() and @isWebViewFocused()


Removed provider name from saving message

--- src/code/views/app-view.coffee
+++ src/code/views/app-view.coffee
@@ -34,7 +34,7 @@
   componentWillMount: ->
     @props.client.listen (event) =>
       fileStatus = if event.state.saving
-        {message: "Saving all changes to #{event.state.saving.provider.displayName}...", type: 'info'}
+        {message: "Saving...", type: 'info'}
       else if event.state.saved
         {message: "All changes saved to #{event.state.metadata.provider.displayName}", type: 'info'}
       else if event.state.dirty


Move toggle to left so it doesn't overflow when split

--- src/components/mpq-toggle.cjsx
+++ src/components/mpq-toggle.cjsx
@@ -46,7 +46,7 @@
         </BS.Popover>
       <BS.OverlayTrigger
         ref="overlay"
-        placement="top"
+        placement="left"
         trigger="click"
         overlay={warning}
       >


Removing confusing error message on non-error.

--- file-converter.coffee
+++ file-converter.coffee
@@ -175,7 +175,7 @@
                                 callback {data: ["Go to #{location}", 302], headers: {"location": location}}

         _conversionDone: (err, cacheInstance, tempname) =>
-                @log.debug "Conversion finished. Error: #{err}"
+                @log.debug "Conversion finished."
                 @_createResponse err, cacheInstance, tempname, (responseParams) =>
                         @log.debug "Sending response to clients: #{tempname}."
                         for response in @_ongoingConversions[cacheInstance.getKey()]


new mutablePush method for List. I'll use it later.

--- fizzylogo_List.coffee
+++ fizzylogo_List.coffee
@@ -70,6 +70,11 @@
       copy.cursorEnd++
       copy

+    toBeReturned.mutablePush = (theItemToPush) ->
+      @value.jsArrayPush theItemToPush
+      @cursorEnd++
+      @
+
     toBeReturned.elementAt = (theElementNumber) ->
       if @value[@cursorStart + theElementNumber]?
         @value[@cursorStart + theElementNumber]


use current host for status images

use current host for status images

--- assets/scripts/app/helpers/urls.coffee
+++ assets/scripts/app/helpers/urls.coffee
@@ -33,7 +33,7 @@
     "http://github.com/#{slug}/admin/hooks#travis_minibucket"

   statusImage: (slug, branch) ->
-    "https://secure.travis-ci.org/#{slug}.png" + if branch then "?branch=#{branch}" else ''
+    "#{location.protocol}//#{location.host}/#{slug}.png" + if branch then "?branch=#{branch}" else ''

   email: (email) ->
     "mailto:#{email}"


devilry_file_upload.FileUpload: Support pause and resume.

--- src/devilry_file_upload.coffee
+++ src/devilry_file_upload.coffee
@@ -311,7 +311,10 @@
         @form.htmlElement.submit()

     upload: ->
-        @fireEvent('start', @)
+        abort = @fireEvent('start', @)
+        if abort
+            console.log 'aborted'
+            return
         if browserInfo.supportsXhrFileUpload()
             @uploadXHR()
         else
@@ -330,6 +333,9 @@
             filename = filepath.split('/').pop().split('\\').pop()
             filenames.push(filename)
         return filenames
+
+    hasMultipleFiles: ->
+        return @getFilenames().length > 1

     getFileInfo: ->
         fileinfo = []
@@ -402,7 +408,17 @@
     getCurrentFileFieldElement: ->
         return @_getCurrentFileField()?.htmlElement

+    pause: ->
+        @paused = true
+        @fireEvent('pause', @)
+
+    resume: ->
+        @paused = false
+        @fireEvent('resume', @)
+
     upload: (files) ->
+        if @paused
+            throw "Can not upload while paused."
         old = @current
         helper = new AsyncFileUploader({
             formElement: @getCurrentFormElement()
@@ -424,7 +440,11 @@
         @fireEvent('fieldChange', @)

     _onUploadStart: (args...) =>
-        @fireEvent('uploadStart', @, args...)
+        abort = @fireEvent('uploadStart', @, args...)
+        if abort
+            return new ObservableResult({
+                abort: true
+            })

     _setupDragEvents: ->
         @dropTargetElement.on('dragover', @_onDragOver)


Handle the difference between atom-shell binaries

--- tasks/build-task.coffee
+++ tasks/build-task.coffee
@@ -12,6 +12,11 @@
     rm shellAppDir
     mkdir path.dirname(buildDir)
     cp 'atom-shell/Atom.app', shellAppDir
+
+    if process.platform is 'darwin'
+      cp 'atom-shell/Atom.app', shellAppDir
+    else if process.platform is 'win32'
+      cp 'atom-shell/', shellAppDir

     mkdir appDir


Hide help dialog when clicking outside of it

--- pages/help_dialog.coffee
+++ pages/help_dialog.coffee
@@ -19,6 +19,10 @@
       false)
     @dialogElement.getElementsByClassName("toggleAdvancedCommands")[0].addEventListener("click",
       HelpDialog.toggleAdvancedCommands, false)
+
+    document.documentElement.addEventListener "click", (event) =>
+      @hide() unless @dialogElement.contains event.target
+    , false

   isReady: -> true


Add the real number of primaries/secondaries in server/index

--- admin/static/coffee/servers/index.coffee
+++ admin/static/coffee/servers/index.coffee
@@ -23,8 +23,8 @@
             #TODO Replace later with server_status
             query = r.db(system_db).table('server_config').merge( (server) ->
                 id: server("uuid")
-                primary_count: 0
-                secondary_count: 0
+                primary_count: r.db(system_db).table('table_config').concatMap( (table) -> table("shards") ).filter( (shard) -> shard("directors").nth(0).eq(server("name")) ).count()
+                secondary_count: r.db(system_db).table('table_config').concatMap( (table) -> table("shards") ).filter( (shard) -> shard("replicas").nth(0).eq(server("name")) ).count()
                 status:
                     reachable: true
                     last_seen: $.timeago(new Date())


gentle clicks

gentle clicks

--- vue/tests/e2e/helpers/pageHelper.coffee
+++ vue/tests/e2e/helpers/pageHelper.coffee
@@ -31,7 +31,9 @@

   click: (selector, pause) ->
     @waitFor(selector)
+    test.pause(200)
     test.click(selector)
+    test.pause(200)
     test.pause(pause) if pause

   scrollTo: (selector, callback, wait) ->
@@ -83,7 +85,7 @@
     test.expect.element(selector).text.to.contain(value)

   expectFlash: (value, wait) ->
-    test.pause(1000)
+    test.pause(1200)
     selector = '.flash-root__message'
     @waitFor(selector, wait)
     test.expect.element(selector).text.to.contain(value)


Add php to hooks-worker-client

Add php to hooks-worker-client

--- src/hooks-worker-client.coffee
+++ src/hooks-worker-client.coffee
@@ -37,6 +37,14 @@
     console.log "$ pip install dredd_hooks"
     hooks.processExit 1

+else if language == 'php'
+  handlerCommand = 'dredd-hooks-php'
+  unless which.which handlerCommand
+    console.log "PHP hooks handler server command not found: #{handlerCommand}"
+    console.log "Install php hooks handler by running:"
+    console.log "$ composer require ddelnano/dredd-hooks-php:~1.0.0 --dev"
+    hooks.processExit 1
+
 else if language == 'nodejs'
   throw new Error 'Hooks handler should not be used for nodejs. Use Dredds\' native node hooks instead'
 else


Does this fix protractor spec?

Does this fix protractor spec?

--- angular/test/protractor/poll_spec.coffee
+++ angular/test/protractor/poll_spec.coffee
@@ -11,8 +11,8 @@
       page.fillIn ".poll-#{_.kebabCase(poll_type)}-form__details", "Some details for #{poll_type}"
       optionsFn() if optionsFn?
       page.click ".poll-#{_.kebabCase(poll_type)}-form__submit"
-      page.expectText '.poll-common-summary-panel__title', "A new #{poll_type}"
-      page.expectText '.poll-common-summary-panel__details', "Some details for #{poll_type}"
+      page.expectText '.poll-common-summary-panel', "A new #{poll_type}"
+      page.expectText '.poll-common-summary-panel', "Some details for #{poll_type}"

   describe 'start, vote for each poll type', ->
     it 'starts a proposal', startPollTest('proposal')