:lipstick:

:lipstick:

--- src/packages/tabs/spec/tabs-spec.coffee
+++ src/packages/tabs/spec/tabs-spec.coffee
@@ -301,4 +301,3 @@

         expect(dragStartEvent.originalEvent.dataTransfer.getData("text/plain")).toEqual editSession1.getPath()
         expect(dragStartEvent.originalEvent.dataTransfer.getData("text/uri-list")).toEqual 'file://' + editSession1.getPath()
-


Adds two more standard fields

Adds two more standard fields

--- src/salesforce-standard-fields.coffee
+++ src/salesforce-standard-fields.coffee
@@ -11,7 +11,9 @@
   'lastmodifiedbyid'
   'systemmodstamp'
   'lastactivitydate'
-  'currencyisocode',
-  'ownerid',
+  'currencyisocode'
+  'ownerid'
   'recordtypeid'
+  'lastreferenceddate'
+  'lastvieweddate'
 ]


Improved username exists check helper.

Improved username exists check helper.

--- client/settings.coffee
+++ client/settings.coffee
@@ -66,7 +66,7 @@
     return # Make sure CoffeeScript does not return anything

 Template.settings.usernameExists = ->
-  !!Meteor.person().user?.username
+  !!Meteor.person?().user?.username

 Template.settingsUsername.messageOnField = (field, options) ->
   field = null unless options


Added currentScreen() method so that you can get the current screen context in the inspector at any time

--- client/src/main.coffee
+++ client/src/main.coffee
@@ -4,4 +4,6 @@
 $(document).ready(->
   Game.onDocumentReady()
   ScreenSystem.loadAllScreens(->Network.initialise())
-)+)
+
+currentScreen = -> ScreenSystem.getCurrentScreen()


List nodes to self on APT export

List nodes to self on APT export

--- src/scripts/services/converter.coffee
+++ src/scripts/services/converter.coffee
@@ -56,6 +56,10 @@
 					if edge.type is "tsEdge"
 						labels.push label for label in edge.labelsLeft when labels.indexOf(label) is -1 if edge.left >= 1
 						labels.push label for label in edge.labelsRight when labels.indexOf(label) is -1 if edge.right >= 1
+				for node in net.nodes
+					if node.type is "state"
+						labels.push label for label in node.labelsToSelf when labels.indexOf(label) is -1
+
 				rows.push label for label in labels
 				rows.push ""


Update edp.coffee

Update edp.coffee

--- data/points/edp.coffee
+++ data/points/edp.coffee
@@ -5,4 +5,5 @@
 relevance: [ "npm", "bower" ]
 desc: "EDP是一个企业级前端应用的开发平台，提供了常用的项目管理工具、包管理工具、调试工具、构建工具、脚手架、代码检测工具等一系列工具，并允许用户自定义自己的扩展。"
 reference:
-  "EDP Github": "https://github.com/ecomfe/edp"+  "EDP Github": "https://github.com/ecomfe/edp"
+  "ECOM包结构规范": "http://fe.baidu.com/doc/ecom/std/package.text"


end responses if 404

end responses if 404

--- src/steroids/servers/WebServer.coffee
+++ src/steroids/servers/WebServer.coffee
@@ -25,6 +25,7 @@

       unless fs.existsSync(fileDistPath)
         res.status(status = 404)
+        res.end()
       else
         res.status(status = 200).sendfile(fileDistPath)


Implement logic to show/hide the expand and shrink icons inside repeats

--- src/resources/forms/orbeon/newbuilder/resources/grid/action-icons.coffee
+++ src/resources/forms/orbeon/newbuilder/resources/grid/action-icons.coffee
@@ -27,7 +27,18 @@
     photo = '/apps/fr/style/images/silk/photo.png'
     $(gridTd).find(".xforms-output-output[src $= '#{spacer}'], .xforms-output-output[src $= '#{photo}']").length > 0
 relevanceRules =
-    'fb-expand-trigger':            (gridTd) -> gridTd.rowSpan <= $(gridTd).parent().nextAll('tr:not(.xforms-repeat-delimiter):not(.xforms-repeat-template):not(.xforms-repeat-begin-end):not(.xforms-group-begin-end)').length
+    'fb-expand-trigger':            (gridTd) ->
+                                        noDelimiter = ':not(.xforms-repeat-delimiter):not(.xforms-repeat-template):not(.xforms-repeat-begin-end):not(.xforms-group-begin-end)'
+                                        grid = $(gridTd).closest('.fr-grid')
+                                        if grid.hasClass('fr-norepeat')                                                             # Regular table
+                                            gridTd.rowSpan <= $(gridTd).parent().nextAll('tr' + noDelimiter).length                 #   Based on number of following non-internal rows
+                                        else if grid.hasClass('fr-repeat-multiple-rows')                                            # Repeat with multiple rows in each iteration
+                                            gridTr =$(gridTd).parent()                                                              #   Based on number of following row with the same parity
+                                            oddEvenClass = if gridTr.hasClass('yui-dt-even') then 'yui-dt-even' else 'yui-dt-odd'   #   Rows with a different parity belong to a different iteration
+                                            gridTd.rowSpan <= gridTr.next('.' + oddEvenClass).length
+                                        else if grid.hasClass('fr-repeat-single-row') then false                                    # Repeat with single row: no expension possible
+                                        else false                                                                                # Catch all, which shouldn't happen
+
     'fb-shrink-trigger':            (gridTd) -> gridTd.rowSpan >= 2
     'fb-delete-trigger':            isNotEmpty
     'fb-edit-details-trigger':      isNotEmpty


Add option to watch all modules, ignore node_modules by default.

--- src/master.coffee
+++ src/master.coffee
@@ -40,8 +40,12 @@
     @socketTimeout    = options.socketTimeout    ? 10000
     @watchForChanges  = options.watch            ? false

-    if @watchForChanges and not fs.watch
-      throw new Error 'watching for changes requires fs.watch'
+    if @watchForChanges
+      if not fs.watch
+        throw new Error 'watching for changes requires fs.watch'
+
+      unless options.watchAllModules
+        @nodeModulesRegex = new RegExp '^' + path.join (path.dirname @serverModule), 'node_modules'

     @runAs = options.runAs ?
       dropPrivileges: true
@@ -130,6 +134,9 @@

   # Watch files for changes
   watch: (filename) ->
+    # ignore node_modules unless options.watchAllModules
+    return if @nodeModulesRegex and @nodeModulesRegex.test filename
+
     @logger.log 'debug', "watching #{filename}"

     if @watched[filename]


More specs for dialogs.

More specs for dialogs.

--- spec/javascripts/app/services_spec.js.coffee
+++ spec/javascripts/app/services_spec.js.coffee
@@ -73,7 +73,10 @@
     beforeEach ->
       angular.module("mock", []).config ($provide) ->
         $provide.factory "dialogsHandler", ->
-          confirm: jasmine.createSpy("confirm")
+          confirm: (message, callback) ->
+            @callback = callback
+          confirmed: -> @callback(true)
+          disposed: -> @callback(false)

     beforeEach module("mock")

@@ -81,5 +84,30 @@
       expect(confirmationDialog).toBeDefined()

     it "calls the handler", inject (confirmationDialog, dialogsHandler) ->
+      spyOn(dialogsHandler, "confirm")
       confirmationDialog(message: "This is a test message")
       expect(dialogsHandler.confirm).toHaveBeenCalledWith("This is a test message", jasmine.any(Function))
+
+    describe "when the dialog was confirmed", ->
+      it "calls the given #onOk callback", inject (confirmationDialog, dialogsHandler) ->
+        # Given
+        onOk = jasmine.createSpy("#onOk callback")
+        confirmationDialog(onOk: onOk)
+
+        # When
+        dialogsHandler.confirmed()
+
+        # Then
+        expect(onOk).toHaveBeenCalled()
+
+    describe "when the dialog was disposed", ->
+      it "calls the given #onOk callback", inject (confirmationDialog, dialogsHandler) ->
+        # Given
+        onCancel= jasmine.createSpy("#onCancel callback")
+        confirmationDialog(onCancel: onCancel)
+
+        # When
+        dialogsHandler.disposed()
+
+        # Then
+        expect(onCancel).toHaveBeenCalled()


Fix edge case for undefined.

Fix edge case for undefined.

--- src/models.coffee
+++ src/models.coffee
@@ -318,7 +318,7 @@
                 return specifierText
             level = null
             for service in @get 'services'
-                continue unless selectedServices.find (selected) =>
+                continue unless selectedServices?.find (selected) =>
                     service.root == selected.get 'root'
                 if not level or service.level < level
                     specifierText = service.name[p13n.getLanguage()]


ComputeProvider: pass users through to provider's create method

--- workers/social/lib/social/models/computeproviders/computeprovider.coffee
+++ workers/social/lib/social/models/computeproviders/computeprovider.coffee
@@ -80,7 +80,7 @@

   , (client, options, callback)->

-    { provider, stack, label, provisioners } = options
+    { provider, stack, label, provisioners, users } = options
     { r: { group, user, account } } = client

     provider.create client, options, (err, machineData)->
@@ -94,7 +94,7 @@
       JMachine.create {
         provider : provider.slug
         label, meta, group, user
-        credential, provisioners
+        users, credential, provisioners
       }, (err, machine)->

         # TODO if any error occurs here which means user paid for


removing beforeAll since it seems to be failing in TravisCI

--- js/test/engine/KryptnosticEngine-test.coffee
+++ js/test/engine/KryptnosticEngine-test.coffee
@@ -129,18 +129,16 @@
       _objSharePair1  = undefined
       _objSharePair2  = undefined

-      beforeAll ->
-
-        # a new KryptnosticEngine will generate the private keys on initialization if they are not
-        # passed into the constructor
-        _engine1 = new KryptnosticEngine()
-
-        # we use .slice() because we want to initialize KryptnosticEngine with a fresh copy of
-        # the two keys to avoid potential bugs due to shared memory
-        _engine2 = new KryptnosticEngine({
-          fhePrivateKey    : _engine1.getPrivateKey().slice()
-          searchPrivateKey : _engine1.getSearchPrivateKey().slice()
-        })
+      # a new KryptnosticEngine will generate the private keys on initialization if they are not
+      # passed into the constructor
+      _engine1 = new KryptnosticEngine()
+
+      # we use .slice() because we want to initialize KryptnosticEngine with a fresh copy of
+      # the two keys to avoid potential bugs due to shared memory
+      _engine2 = new KryptnosticEngine({
+        fhePrivateKey    : _engine1.getPrivateKey().slice()
+        searchPrivateKey : _engine1.getSearchPrivateKey().slice()
+      })

       it 'should calculate the same private key', ->


Polished the mirror (events).

Polished the mirror (events).

--- lib/Watchers/Asset/mirror.coffee
+++ lib/Watchers/Asset/mirror.coffee
@@ -38,22 +38,28 @@
         @gazeAt @pool = (GetPool(root) for root in @root)

     gazeAt: (pool)->
-        minmatch = (path)-> (pattern)-> minimatch path, pattern
+        Q.all pool.map (pond)=>
+            d = Q.defer()
+            pond.on 'ready', -> d.resolve()
+            d.promise
+        .then =>
+            @emit 'ready'
         pool.forEach (pond)=>
             pond.on 'error', (err)=> @emit 'error', err
-            pond.on 'ready', => @emit 'ready'
             pond.on 'all', (eventName, path)=>
-                @pattern
-                .filter(minmatch(path))
-                .forEach (pattern)=>
+                if @toWatch path
                     @emit 'all', eventMap[eventName], path
-                    @emit eventMap[eventName], path
+                    # @emit eventMap[eventName], path
+                    # TODO wait on amasad/sane#21
             for k, v of eventMap
-                pond.on k, (path)=> @emit v, path
+                do (k, v)=>
+                    pond.on k, (path)=>
+                        if @toWatch pond.root + '/' + path
+                            @emit v, path
+            return
+        @

-    toWatch: -> (filepath)=>
-        # console.log "Checking #{filepath} against #{@pattern}"
-        # @pattern[@howMany] (pattern)->
+    toWatch: (filepath)=>
         @pattern.some (pattern)->
             if pattern instanceof RegExp
                 if pattern.test filepath
@@ -87,7 +93,7 @@
                 dir = pond.dirRegistery[dirname]
                 Object.keys(dir).forEach (file)=>
                     path = "#{dirname}/#{file}"
-                    if @toWatch() path
+                    if @toWatch path
                         filelist[path] = true

         cb null, filelist


Bugfixing -> Ask befor getting global Attributes or Methods

--- api/server/app/assets/metaModelEditor/ext/exportMetaModel/Exporter.coffee
+++ api/server/app/assets/metaModelEditor/ext/exportMetaModel/Exporter.coffee
@@ -88,31 +88,35 @@

   createAttributes: () ->
     attributes = []
-    for thisAttribute in mEnum.getMEnumContainer().attributes['m_attributes']
-      attributes.push
-        name: thisAttribute.name
-        upperBound: thisAttribute.upperBound
-        lowerBound: thisAttribute.lowerBound
-        default: thisAttribute.default
-        typ: thisAttribute.typ
-        expression: thisAttribute.expression
-        localUnique: thisAttribute.localUnique
-        globalUnique: thisAttribute.globalUnique
-        constant: thisAttribute.constant
-        ordered: thisAttribute.ordered
-        transient: thisAttribute.transient
-        singleAssignment: thisAttribute.singleAssignment
+
+    if (mEnum.getMEnumContainer().attributes.hasOwnProperty('m_attributes'))
+      for thisAttribute in mEnum.getMEnumContainer().attributes['m_attributes']
+        attributes.push
+          name: thisAttribute.name
+          upperBound: thisAttribute.upperBound
+          lowerBound: thisAttribute.lowerBound
+          default: thisAttribute.default
+          typ: thisAttribute.typ
+          expression: thisAttribute.expression
+          localUnique: thisAttribute.localUnique
+          globalUnique: thisAttribute.globalUnique
+          constant: thisAttribute.constant
+          ordered: thisAttribute.ordered
+          transient: thisAttribute.transient
+          singleAssignment: thisAttribute.singleAssignment

     attributes

   createMethods: () ->
     methods = []
-    for thisMethod in mEnum.getMEnumContainer().attributes['m_methods']
-      methods.push
-        name: thisMethod.name
-        parameters: thisMethod.parameters
-        description: thisMethod.description
-        returnType: thisMethod.returnType
-        code: thisMethod.code
+
+    if (mEnum.getMEnumContainer().attributes.hasOwnProperty('m_methods'))
+      for thisMethod in mEnum.getMEnumContainer().attributes['m_methods']
+        methods.push
+          name: thisMethod.name
+          parameters: thisMethod.parameters
+          description: thisMethod.description
+          returnType: thisMethod.returnType
+          code: thisMethod.code
     methods


made popover hide less twitchy. Destroy on mouseleave from #form instead of .form-component

--- app/assets/javascripts/backbone/apps/formbuilder/edit/edit_view.js.coffee
+++ app/assets/javascripts/backbone/apps/formbuilder/edit/edit_view.js.coffee
@@ -34,7 +34,6 @@
     events:
       'drop'              : 'drop'
       'click .field-edit' : 'showPopover'
-      'mouseleave'        : 'hidePopover'

     triggers:
       "click .field-delete" : "form:field:delete"
@@ -45,6 +44,7 @@
     showPopover: (e) ->
       e.preventDefault()
       e.stopPropagation()
+      $(".field-edit").popover('destroy')
       popoverView = new Edit.FieldSettings
         model: @model
       popoverView.render()
@@ -53,9 +53,6 @@
       @$(".field-edit").popover('show')
       @listenTo popoverView, "field:update", ->
         @trigger "field:updated", @model
-
-    hidePopover: (event) ->
-      $(".field-edit").popover('destroy')

   class Edit.FieldSettings extends App.Views.ItemView
@@ -82,9 +79,13 @@

     events:
       'update-sort' : 'updateSort'
+      'mouseleave'  : 'hidePopover'

     updateSort: (event, model, position) ->
       @trigger "form:component:sort", model, position
+
+    hidePopover: (event) ->
+      $(".field-edit").popover('destroy')

     onShow: ->
       $(@itemViewContainer).sortable


Fix spec; allCourses is now allValidCourses

--- test/course-listing-store.spec.coffee
+++ test/course-listing-store.spec.coffee
@@ -12,7 +12,7 @@

   it 'should load courses', ->
     expect(CourseListingStore.isLoaded()).to.be.true
-    names = _.pluck(CourseListingStore.allCourses(), 'name')
+    names = _.pluck(CourseListingStore.allValidCourses(), 'name')
     expect(names).to.deep.equal(_.pluck(COURSES, 'name'))

   it 'should clear the store and the course store on reset', ->


removed unused lines

removed unused lines

--- _assets/js/_keyboard.coffee
+++ _assets/js/_keyboard.coffee
@@ -1,21 +1,8 @@
-# results = $('#search-results')
-
-searchSubmit = () ->
-  btn = document.querySelector('.search-submit')
-  btn.click () ->
-    selected = document.querySelector('#search-results a.selected')
-    url = selected.getAttribute('href') if selected
-    window.open url, '_self'
-    return
-  return
-
 traverseUp = ->
-  # console.log 'up arrow pressed'
   $("#search-results a.selected").removeClass('selected').prev().addClass('selected')
   return

 traverseDown = ->
-  # console.log 'down arrow pressed'
   $("#search-results a.selected").removeClass('selected').next().addClass('selected')
   return


fix bug

fix bug

--- lib/carte/client/views/list.cjsx
+++ lib/carte/client/views/list.cjsx
@@ -55,8 +55,8 @@

Random

               {
                 if @props.cards.query.tags
-                  @props.cards.query.tags.split(',').map (tag)->
-
 {tag}

+                  @props.cards.query.tags.split(',').map (tag)=>
+
 {tag}

               }


./run chaosmonkey : restart every service randomly to test resilience

--- config/main.dev.coffee
+++ config/main.dev.coffee
@@ -519,6 +519,20 @@

       }

+      chaosmonkey () {
+
+        while [ 1==1 ]; do
+          for i in mongo redis etcd postgres
+            do
+              echo stopping $i
+              docker stop $i
+              echo starting $i
+              docker start $i
+              sleep 10
+            done
+        done
+      }
+
       function printconfig () {
         if [ "$2" == "" ]; then
           cat << EOF
@@ -564,6 +578,7 @@
         echo "  run buildservices      : to initialize and start services"
         echo "  run services           : to stop and restart services"
         echo "  run worker             : to list workers"
+        echo "  run chaosmonkey        : restart every service randomly to test resilience."
         echo "  run printconfig        : to print koding config environment variables (output in json via --json flag)"
         echo "  run worker [worker]    : to run a single worker"
         echo "  run help               : to show this list"
@@ -722,6 +737,10 @@
       elif [ "$1" == "help" ]; then
         printHelp

+      elif [ "$1" == "chaosmonkey" ]; then
+        chaosmonkey
+
+
       elif [ "$1" == "worker" ]; then

         if [ "$2" == "" ]; then


Agent pie: start/end angle pie transition work

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -414,7 +414,7 @@
             #.style('opacity', 0)
         pointers.exit().remove()
         pointers.transition()
-            .duration(1000)
+            .duration(2000)
             .attr('d', (d) ->
                 if d.cx > d.l
                     'M' + (d.l + 2) + ',' + d.b + 'L' + (d.r - 2) + ',' + d.b + ' ' + d.cx + ',' + d.cy


Agent pie testing

Agent pie testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -3,7 +3,7 @@
     @accessor 'data'

     onData: (data) ->
-        $(@node).fadeOut().fadeIn()
+        #$(@node).fadeOut().fadeIn()
         @update(data.data)

     update: (dataSet) ->
@@ -249,7 +249,7 @@
             return
         )
         .transition()
-            .duration(3000)
+            .duration(1000)
             .attr('x', (d) ->
                 d.x
             ).attr('y', (d) ->


Removed console.log calls

Removed console.log calls

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -17,8 +17,8 @@

         # Define the container
         @container = $(@node).parent()
-        console.log 'node',$(@node)
-        console.log 'container',@container
+        #console.log 'node',$(@node)
+        #console.log 'container',@container

         #
         # CONFIG ZONE
@@ -276,7 +276,7 @@
                 return

             if conflicts.length
-                console.log myInstanceDataId , ' ', d, ' conflicts with ', conflicts
+                #console.log myInstanceDataId , ' ', d, ' conflicts with ', conflicts
                 rightEdge = d3.max(conflicts, (d2) ->
                     d2.r
                 )
@@ -306,8 +306,8 @@
                     d.x = d.r - bbox.width / 2 - 2
                     d.l = d.r - bbox.width - 5

-            else
-                console.log 'no conflicts for ', myInstanceDataId, ' ', d
+            #else
+                #console.log 'no conflicts for ', myInstanceDataId, ' ', d

             ### add this label to the quadtree, so it will show up as a conflict
                for future labels.


Agent: reverting console log tests

Agent: reverting console log tests

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -17,8 +17,8 @@

         # Define the container
         @container = $(@node).parent()
-        console.log 'node',$(@node)
-        console.log 'container',@container
+        #console.log 'node',$(@node)
+        #console.log 'container',@container

         #
         # CONFIG ZONE


fetchDomains for FileTree.

fetchDomains for FileTree.

--- workers/social/lib/social/models/vm.coffee
+++ workers/social/lib/social/models/vm.coffee
@@ -26,7 +26,7 @@
     sharedMethods       :
       static            : [
                            'fetchVms','fetchVmsByContext','calculateUsage'
-                           'removeByName', 'someData'
+                           'removeByName', 'someData', 'fetchDomains'
                           ]
       instance          : []
     schema              :
@@ -229,6 +229,21 @@
     #     return callback err  if err
     #     callback null, [vm]

+  @fetchDomains = permit 'list all vms',
+    success:(client, vmName, callback)->
+      {delegate} = client.connection
+
+      delegate.fetchUser (err, user) ->
+        return callback err  if err
+
+        selector =
+          name   : vmName
+          users  : { $elemMatch: id: user.getId(), owner: yes }
+
+        JVM.one selector, {hostnameAlias:1}, (err, vm)->
+          return callback err, []  if err or not vm
+          callback null, vm.hostnameAlias or []
+
   @removeByName = permit 'delete vms',
     success:(client, vmName, callback)->
       {delegate} = client.connection


custom server port

custom server port

--- src/server.coffee
+++ src/server.coffee
@@ -35,4 +35,4 @@
   return

 # Application listens on port 3000
-app.listen 3000+app.listen 3001


Convert location name to lowercase for comparison

--- app/annotation/summary.cjsx
+++ app/annotation/summary.cjsx
@@ -7,10 +7,10 @@
 steps = require '../lib/steps'

 sites =
-  siteA: ["Guinea_FoutahDjalon", "Guinea_Sangaredi", "GuineaBissau_Boe_Part1", "GuineaBissau_Boe_Part2", "IvoryCoast_Azagny", "IvoryCoast_Djouroutou", "IvoryCoast_TaiE", "IvoryCoast_TaiR", "Liberia_EastNimba", "Liberia_Grebo_Sala_part1", "Liberia_Grebo_Sala_part2", "Liberia_Grebo_Tasla", "Liberia_Sapo", "Senegal_Kayan", "Liberia_Grebo_Part1"]
-  siteB: ["Nigeria_Gashaka"]
-  siteC: ["EquatorialGuinea_Nationwide"]
-  siteD: ["DRC_BiliUere", "Uganda_Budongo", "Uganda_Bwindi", "Uganda_Ngogo", "Tanzania_Ugalla"]
+  siteA: ["guinea_foutahdjalon", "guinea_sangaredi", "guineabissau_boe_part1", "guineabissau_boe_part2", "ivorycoast_azagny", "ivorycoast_djouroutou", "ivorycoast_taie", "ivorycoast_tair", "liberia_eastnimba", "liberia_grebo_sala_part1", "liberia_grebo_sala_part2", "liberia_grebo_tasla", "liberia_sapo", "senegal_kayan", "liberia_grebo_part1"]
+  siteB: ["nigeria_gashaka"]
+  siteC: ["equatorialguinea_nationwide"]
+  siteD: ["drc_biliuere", "uganda_budongo", "uganda_bwindi", "uganda_ngogo", "tanzania_ugalla"]

 # Note: group metadata does not exist in dev db, so buttons and location image will not work locally or on staging
 Summary = React.createClass
@@ -45,10 +45,10 @@
     locationName = @state.group.metadata.site

     siteLocation = switch
-      when sites.siteA.indexOf(locationName) > -1 then "site-a"
-      when sites.siteB.indexOf(locationName) > -1 then "site-b"
-      when sites.siteC.indexOf(locationName) > -1 then "site-c"
-      when sites.siteD.indexOf(locationName) > -1 then "site-d"
+      when sites.siteA.indexOf(locationName.toLowerCase()) > -1 then "site-a"
+      when sites.siteB.indexOf(locationName.toLowerCase()) > -1 then "site-b"
+      when sites.siteC.indexOf(locationName.toLowerCase()) > -1 then "site-c"
+      when sites.siteD.indexOf(locationName.toLowerCase()) > -1 then "site-d"

     @setState siteLocation: siteLocation


Check for new iPad User-Agent

Check for new iPad User-Agent

--- app/core/application.coffee
+++ app/core/application.coffee
@@ -46,7 +46,7 @@
 Application = initialize: ->
   Router = require('core/Router')
   @isProduction = -> document.location.href.search('https?://localhost:3000') is -1
-  @isIPadApp = webkit?.messageHandlers? and navigator.userAgent?.indexOf('iPhone OS') isnt -1
+  @isIPadApp = webkit?.messageHandlers? and navigator.userAgent?.indexOf('CodeCombat-iPad') isnt -1
   $('body').addClass 'ipad' if @isIPadApp
   @tracker = new Tracker()
   @facebookHandler = new FacebookHandler()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/sprite.coffee
+++ src/sprite.coffee
@@ -106,8 +106,9 @@
   @returns {Sprite} A sprite object
   ###
   Sprite.load = (url, loadedCallback) ->
-    if spriteCache[url]
-      loadedCallback.defer()
+    if sprite = spriteCache[url]
+
+      loadedCallback.defer(s)
       return

     img = new Image()


maintain view order when notifications update

--- app/js/views/threads.coffee
+++ app/js/views/threads.coffee
@@ -7,7 +7,7 @@
     'click #mark-all-read': 'read'

   initialize: ->
-    @listenTo @collection, 'add', @add
+    @listenTo @collection, 'add change', @add
     @listenTo @collection, 'reset', @addAll

     @listenToOnce @collection, 'sync', =>
@@ -18,6 +18,8 @@

     @listenTo @collection, 'request', @startPaginating
     @listenTo @collection, 'sync', @donePaginating
+
+    @views = {}

   render: ->
     @$el.html @template()
@@ -30,12 +32,13 @@
     @$list = @$('.notification-list')
     @

-  add: (notification) ->
-    view = new App.Views.Notification(model: notification).render()
+  add: (model) ->
+    # memoize view instances
+    view = @views[model.id] ||= new App.Views.Notification(model: model).render()

     # Maintain view order by inserting it the new element before the element
     # that is currently in its place.
-    sibling = @$list.children().eq(@collection.indexOf(notification))
+    sibling = @$list.children().eq(@collection.indexOf(model))
     if sibling.length
       sibling.before(view.el)
     else


Show all tools in project approved for

Show all tools in project approved for

...experimental tools

--- app/pages/lab/workflow.cjsx
+++ app/pages/lab/workflow.cjsx
@@ -32,6 +32,9 @@
     viewParams = {owner, name}
     viewQuery = workflow: @props.workflow.id, reload: @state.forceReloader
     @makeHref 'project-classify', viewParams, viewQuery
+
+  canUseTask: (project, task)->
+    task in project.experimental_tools

   render: ->
     window.editingWorkflow = @props.workflow
@@ -101,27 +104,22 @@
                       Drawing
                     </button>
                   </AutoSave>{' '}
-                  <PromiseRenderer promise={@props.project.get 'owner'}>{(owner) =>
-                    if owner.admin or owner.display_name is 'brian-testing'
-
-                        <AutoSave resource={@props.workflow}>
-                          <button type="submit" className="minor-button" onClick={@addNewTask.bind this, 'survey'} title="Survey tasks: the volunteer identifies objects (usually animals) in the image(s) by filtering by their visible charactaristics, then answers questions about them.">
-
-

-                            Survey
-                          </button>
-                        </AutoSave>{' '}
-                        <AutoSave resource={@props.workflow}>
-                          <button type="submit" className="minor-button" onClick={@addNewTask.bind this, 'crop'} title="Crop tasks: the volunteer draws a rectangle around an area of interest, and the view of the subject is approximately cropped to that area.">
-
-

-                            Crop
-                          </button>
-                        </AutoSave>
-
-                    else
-                      null
-                  }</PromiseRenderer>
+                  {if @canUseTask(@props.project, "survey")
+                    <AutoSave resource={@props.workflow}>
+                      <button type="submit" className="minor-button" onClick={@addNewTask.bind this, 'survey'} title="Survey tasks: the volunteer identifies objects (usually animals) in the image(s) by filtering by their visible charactaristics, then answers questions about them.">
+
+

+                        Survey
+                      </button>
+                    </AutoSave>}{' '}
+                  {if @canUseTask(@props.project, "crop")
+                    <AutoSave resource={@props.workflow}>
+                      <button type="submit" className="minor-button" onClick={@addNewTask.bind this, 'crop'} title="Crop tasks: the volunteer draws a rectangle around an area of interest, and the view of the subject is approximately cropped to that area.">
+
+

+                        Crop
+                      </button>
+                    </AutoSave>}
                 </TriggeredModalForm>


Assign the example subject set to the workflow

--- app/pages/lab/workflow.cjsx
+++ app/pages/lab/workflow.cjsx
@@ -9,7 +9,10 @@
 {Navigation} = require 'react-router'
 tasks = require '../../classifier/tasks'

-DEMO_SUBJECT_SET_ID = '1166'
+DEMO_SUBJECT_SET_ID = if process.env.NODE_ENV is 'production'
+  '6' # Cats
+else
+  '1166' # Ghosts

 EditWorkflowPage = React.createClass
   displayName: 'EditWorkflowPage'
@@ -136,7 +139,10 @@
           </tbody>
         </table>
         {if projectSubjectSets.length is 0
-          <button type="button" onClick={@addDemoSubjectSet}>Add an example subject set</button>}
+          <p>
+            This project has no subject sets.{' '}
+            <button type="button" onClick={@addDemoSubjectSet}>Add an example subject set</button>
+          </p>}
       </div>
     }</PromiseRenderer>

@@ -174,8 +180,10 @@

   addDemoSubjectSet: ->
     @props.project.addLink 'subject_sets', [DEMO_SUBJECT_SET_ID]
-      .then (subjectSet) =>
-        console.log 'ADDED', subjectSet
+      .then =>
+        @props.project.get 'subject_sets'
+      .then ([subjectSet]) =>
+        @props.workflow.addLink 'subject_sets', [subjectSet.id]

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


Small logger registration fix

Small logger registration fix

--- app/src/utils/logger.coffee
+++ app/src/utils/logger.coffee
@@ -91,8 +91,7 @@

   @getLoggerByTag: (tag) ->
     @_loggers ?= {}
-    unless @_logger[tag]?
-      @_logger[tag] = new @(tag)
+    new @(tag) unless @_logger[tag]?
     @_logger[tag]


Remove problematic period filter

Remove problematic period filter

--- src/desktop/components/commercial_filter/filters/period/period_map.coffee
+++ src/desktop/components/commercial_filter/filters/period/period_map.coffee
@@ -15,7 +15,6 @@
     'Late 19th Century',
     'Mid 19th Century',
     'Early 19th Century',
-    '18th Century & Earlier',
   ],
   displayPeriods: [
     '2010',


:memo: Give an example of a snippet scope

--- dot-atom/snippets.cson
+++ dot-atom/snippets.cson
@@ -13,7 +13,7 @@
 #     'prefix': 'log'
 #     'body': 'console.log $1'
 #
-# Each scope can only be declared once.
+# Each scope (e.g. '.source.coffee' above) can only be declared once.
 #
 # This file uses CoffeeScript Object Notation (CSON).
 # If you are unfamiliar with CSON, you can read more about it here:


chore(tests): move custom matcher outside of spec

--- test/unit/modules/resources_spec.coffee
+++ test/unit/modules/resources_spec.coffee
@@ -76,17 +76,17 @@
           expect(product.priceWithDiscount()).to.equal 78

     describe "#hasDiscount()", ->
+      # custom chai property for checking product's discount
+      chai.Assertion.addProperty "discount", ->
+        subject = @_obj
+
+        @assert subject.hasDiscount(),
+          "expected #\{this} to have discount",
+          "expected #\{this} to not have discount"
+
       product = null
       beforeEach inject (Products) ->
         product = new Products(discount: @discount)
-
-        # custom chai property for checking product's discount
-        chai.Assertion.addProperty "discount", ->
-          subject = @_obj
-
-          @assert subject.hasDiscount(),
-            "expected #\{this} to have discount",
-            "expected #\{this} to not have discount"

       it "is defined", ->
         expect(product.hasDiscount).to.not.be.undefined


some more random atom configness

some more random atom configness

--- data/.atom/config.cson
+++ data/.atom/config.cson
@@ -6,6 +6,7 @@
   'userId': 'f45f6f01061a25c864d112b6d1a2f7ac2ce4591d'
 'editor':
   'fontSize': 12
+  'invisibles': {}
 'core':
   'themes': [
     'hecs-dark-ui'


Delete an outdated test

Delete an outdated test

Change-Type: patch

--- tests/integration/models/os.spec.coffee
+++ tests/integration/models/os.spec.coffee
@@ -272,7 +272,6 @@
 					eventuallyExpectProperty(promise, 'appUpdatePollInterval').that.equals(configOptions.appUpdatePollInterval * 60 * 1000)
 					eventuallyExpectProperty(promise, 'wifiKey').that.equals(configOptions.wifiKey)
 					eventuallyExpectProperty(promise, 'wifiSsid').that.equals(configOptions.wifiSsid)
-					eventuallyExpectProperty(promise, 'version').that.equals(configOptions.version)
 					eventuallyExpectProperty(promise, 'files')
 						.that.has.property('network/network.config')
 						.that.includes("#{configOptions.ip}/#{configOptions.netmask}/#{configOptions.gateway}")


Focusing on the first form field

Focusing on the first form field

--- app/assets/javascripts/darkswarm/controllers/checkout_controller.js.coffee
+++ app/assets/javascripts/darkswarm/controllers/checkout_controller.js.coffee
@@ -27,9 +27,10 @@
     checkout.submit()

    $scope.scrollTo = (name)->
+      #$scope.userOpen = false
+      $("#order_email").focus()
       $location.hash(name);
       $anchorScroll();
-      $scope.userOpen = false

   $scope.initialize()


Updated micro copy and changed position of clear and print links

--- app/assets/javascripts/jobs_list/views/bookmarked_jobs_list_view.js.coffee
+++ app/assets/javascripts/jobs_list/views/bookmarked_jobs_list_view.js.coffee
@@ -7,14 +7,14 @@
     @model.bind 'add', => this.render()
     @model.bind 'remove', => this.render()

-    $(@el).append('
Jobs List
')
-    $(@el).append('
Print
')
+    $(@el).append('
Jobs list
')

     @list = $('
').appendTo(@el)

     $(@el).append('
Save jobs here by clicking "Add to jobs list" on a job.')
-    $(@el).append('
Copy about clearing the list on public computers.
')
-    $(@el).append('
Clear List
')
+    $(@el).append('
Print list
')
+    $(@el).append('
Clear list
')
+    $(@el).append('
Clear this list when you’ve finished if this is a public computer.
')

     $(window).bind 'resize', => this.setHeight()


EDSC-70: Avoid panning and zooming by small amounts when selecting granules

--- app/assets/javascripts/modules/map/leaflet-plugins/granule_layer.js.coffee
+++ app/assets/javascripts/modules/map/leaflet-plugins/granule_layer.js.coffee
@@ -385,8 +385,12 @@
       @_granuleStickyLayer = @_layerForGranule(granule, true)
       if @_granuleStickyLayer?
         @_granuleStickyLayer.onAdd(@_map)
+
         @_restoreBounds ?= @_map.getBounds()
-        @_map.fitBounds(@_granuleFocusLayer.getBounds())
+        bounds = @_granuleFocusLayer.getBounds()
+        # Avoid zooming and panning tiny amounts
+        unless @_map.getBounds().contains(bounds)
+          @_map.fitBounds(bounds.pad(0.2))

       @_loadResults(@_results)


fixed perms-request for the first embed and on edit

--- client/app/Applications/Activity.kdapplication/widgets/statuswidget.coffee
+++ client/app/Applications/Activity.kdapplication/widgets/statuswidget.coffee
@@ -18,7 +18,7 @@

     # saves the URL of the previous request to avoid
     # multiple embed calls for one URL
-    @previousURL = []
+    @previousURL = ""

     # prevents multiple calls to embed.ly functionality
     # at the same time
@@ -174,7 +174,7 @@

           @embedBox.embedLinks.setLinks firstUrl

-          unless @previousURL is firstUrl
+          unless (@previousURL in firstUrl)
             @embedBox.embedUrl firstUrl?[0], {
               maxWidth: 525
             }, (embedData)=>
@@ -183,7 +183,9 @@
               @embedLinks?.linkList?.items?[0]?.setFavicon embedData.favicon_url

               @requestEmbedLock = off
-              @previousURL = firstUrl
+              @previousURL = firstUrl?[0]
+          else
+            @requestEmbedLock = off
         else
           @requestEmbedLock = off
       ,50


Render links in new tab

Render links in new tab

--- angular/core/services/render_service.coffee
+++ angular/core/services/render_service.coffee
@@ -1,6 +1,8 @@
 angular.module('loomioApp').factory 'render', ->
   createRenderer: ->
     renderer = new marked.Renderer()
+    renderer.link = (href, title, text) ->
+      "#{text}"
     renderer.paragraph = @cook('p')
     renderer.listitem  = @cook('li')
     renderer.tablecell = @cook('td')


Reverted order of is_quebec and category_id params

Change-Id: I6191126d1de6c066ea23b9b42be1d249fc3e5b40

--- app/assets/javascripts/comparison.js.coffee
+++ app/assets/javascripts/comparison.js.coffee
@@ -82,7 +82,7 @@
     is_quebec = "true"
   else
     is_quebec = "false"
-
+
   return false if skus.length < 1

   # To figure out the width that we need, start with $('#opt_savedproducts').length probably
@@ -93,7 +93,7 @@
   else
     width = 566

-  opt.applySilkScreen '/comparison/' + skus.join(",") + "?category_id=" + opt_category_id + "&is_quebec=" + is_quebec, null, width, 580, ->
+  opt.applySilkScreen '/comparison/' + skus.join(",") + "?is_quebec=" + is_quebec + "&category_id=" + opt_category_id, null, width, 580, ->
     # Jquery 1.5 would finish all the requests before building the comparison matrix once
     # With 1.4.2 we can't do that. Keep code for later.
     # $.when.apply(this,reqs).done();


on login, if setup_group flag present, user redirected to group setup page

--- app/components/group-page/group-page.coffee
+++ app/components/group-page/group-page.coffee
@@ -1,4 +1,9 @@
 module.exports =
+  onEnter: ($location, Toast) ->
+    if $location.search().setup_group
+      $location.url($location.path())
+      $location.path('/setup_group')
+      Toast.hide()
   resolve:
     userValidated: ($auth) ->
       $auth.validateUser()


Breadcrumbs bug fixes.

Breadcrumbs bug fixes.

--- app/scripts/components/BsBreadcrumbs.coffee
+++ app/scripts/components/BsBreadcrumbs.coffee
@@ -4,22 +4,7 @@
 Bootstrap.BsBreadcrumbsItem = Bootstrap.ItemView.extend(
     tagName: ['li']
     classNameBindings: ["isActive:active"]
-    template: Ember.Handlebars.compile '''
-        <i {{bindAttr class='view.content.icon'}}></i>
-        {{#unless view.isActive}}
-            {{#if view.content.model}}
-                {{#link-to view.content.route model.id}}
-                    {{view.content.name}}
-                {{/link-to}}
-            {{else}}
-                {{#link-to view.content.route}}
-                    {{view.content.name}}
-                {{/link-to}}
-            {{/if}}
-        {{else}}
-            {{view.content.name}}
-        {{/unless}}
-    '''
+    template: Ember.Handlebars.compile '{{#unless view.isActive}}{{#if view.content.model}}{{#link-to view.content.route model.id}}{{view.content.name}}{{/link-to}}{{else}}{{#link-to view.content.route}}{{view.content.name}}{{/link-to}}{{/if}}{{else}}{{view.content.name}}{{/unless}}'

     isActive: (->
         @get('content.active')
@@ -37,6 +22,7 @@
     content: []
     itemViewClass: Bootstrap.BsBreadcrumbsItem
     nameDictionary: undefined
+    dictionaryNamePrefix: 'breadcrumbs'

     actions:
         currentPathDidChange: ->
@@ -54,8 +40,8 @@
                 routeName = route.handler.routeName
                 if route.handler.breadcrumbs?.name
                     displayName = route.handler.breadcrumbs.name
-                else if @get('nameDictionary')?[routeName]
-                    displayName = @get('nameDictionary')[routeName]
+                else if @get('nameDictionary')?["#{@dictionaryNamePrefix}.#{routeName}"]
+                    displayName = @get('nameDictionary')["#{@dictionaryNamePrefix}.#{routeName}"]
                 else
                     displayName = route.handler.routeName.split('.').pop()
                     displayName = displayName[0].toUpperCase() + displayName[1..-1].toLowerCase()
@@ -65,7 +51,7 @@
                     name: displayName
                     model: null

-                crumb.set('icon', 'icon-home home-icon') if @get('content').length is 0
+                crumb.set('icon', 'fa fa-home home-icon') if @get('content').length is 0

                 if route.isDynamic
                     crumb.setProperties


Updates deb pack cmd to use the correct CHANGELOG

--- tasks/pack.coffee
+++ tasks/pack.coffee
@@ -105,9 +105,9 @@
         '--after-remove'
         './build/resources/linux/after-remove.sh'
         '--deb-changelog'
-        './CHANGELOG.md'
+        './CHANGELOG.deb'
         '--rpm-changelog'
-        './CHANGELOG.md'
+        './CHANGELOG.rpm'
         '--depends'
         'libappindicator1'
         '--license'


Up initial member load size

Up initial member load size

--- lineman/app/components/memberships_page/memberships_page_controller.coffee
+++ lineman/app/components/memberships_page/memberships_page_controller.coffee
@@ -4,7 +4,7 @@
   @init = (group) =>
     if group and !@group?
       @group      = group
-      Records.memberships.fetchByGroup(@group.key, per: 25)
+      Records.memberships.fetchByGroup(@group.key, per: 100)

   @setMemberships = =>
     Records.memberships.fetchByNameFragment @fragment, @group.key if @fragment


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/color.coffee
+++ test/color.coffee
@@ -84,7 +84,7 @@
   equals color.b(), 85

 test "Color should parse arrays", ->
-  color = Color("Fuzzy Wuzzy Brown")
+  color = Color([1, 24, 101])
   equals color.r(), 196
   equals color.g(), 86
   equals color.b(), 85


Implemented hotkeys

Implemented hotkeys

--- def/de/menu_win32.cson
+++ def/de/menu_win32.cson
@@ -54,8 +54,8 @@
         value: "Rückgängig(&U)"
       "&Redo":
         value: "Wiederhe&rstellen"
-      "C&ut":
-        value: "Ausschneiden(&U)"
+      "Cu&t":
+        value: "Ausschneiden(&T)"
       "&Copy":
         value: "Kopieren (&C)"
       "Copy Pat&h":


test: more edge cases

test: more edge cases

--- test/index.coffee
+++ test/index.coffee
@@ -78,6 +78,16 @@
   ]
 ,
   on: 'a'
+  left: BASE_LEFT.concat {a: 'null', b: 5}
+  right: BASE_RIGHT.concat {a: 'null', b: 6}
+  expected: [
+    [{a: 'null', b: 5}, {a: 'null', b: 6}]
+    [{a: 1, b: 2}, {a: 1, b: 3}]
+    [{a: 2, b: 3}, {a: 2, b: 4}]
+    [{a: 3, b: 4}, {a: 3, b: 5}]
+  ]
+,
+  on: 'a'
   left: BASE_LEFT.concat {b: 5}
   right: BASE_RIGHT.concat {b: 6}
   expected: [
@@ -99,6 +109,25 @@
     [null, {a: null, b: 6}]
     [null, {a: null, b: 7}]
   ]
+,
+  on: 'a'
+  left: BASE_LEFT
+  right: []
+  expected: [
+    [{a: 1, b: 2}, null]
+    [{a: 2, b: 3}, null]
+    [{a: 3, b: 4}, null]
+  ]
+,
+  on: 'a'
+  left: []
+  right: []
+  expected: []
+,
+  on: 'a'
+  left: BASE_LEFT.concat {a: '3'}
+  right: BASE_RIGHT
+  expected: _.zip(BASE_LEFT, BASE_RIGHT).concat [[{a: '3'}, null]]
 ]

 # For consistency, sort pairs by the values of the keys of the pairs, in alphabetical order


Added first mixer unit test

Added first mixer unit test

--- test/mixer.coffee
+++ test/mixer.coffee
@@ -0,0 +1,8 @@
+require 'udefine/global'
+mixer = require '../dist/udefine'
+{expect} = require 'chai'
+
+describe 'mixer', ->
+  it 'empty parameters', ->
+    result = mixer()
+    expect(result).to.be('undefined')


add comments to starting_after_and_ending_before test

--- test/query.coffee
+++ test/query.coffee
@@ -123,12 +123,14 @@
       before_students = []
       async.waterfall [
         (cb_wf) =>
+          # get the last 2 students
           @clever.Student.find().limit(2).ending_before('last').exec (err, students) =>
             before_students = students
             assert.equal students.length, 2
             assert (students[0] instanceof @clever.Student), "Incorrect type on student object"
             cb_wf()
         (cb_wf) =>
+          # get the students after the second to last student
           @clever.Student.find().starting_after(before_students[0].get 'id').exec (err, students) =>
             assert.equal students.length, 1
             assert.equal students[0].get('id'), before_students[1].get('id')


Remove unnecessary code; proper setup/teardown.

--- test/queue.coffee
+++ test/queue.coffee
@@ -1,15 +1,6 @@
-# This used to be the whole set of tests - now some of the ancillary parts of
-# livedb have been pulled out. These tests should probably be split out into
-# multiple files.
-
-livedb = require '../lib'
 assert = require 'assert'
-Q = require 'q'
-inProcessDriver = require '../lib/inprocessdriver'
 TestDriver = require './testdriver'
-
-textType = require('ot-text').type
-{createClient, setup, teardown, stripTs, calls} = require './util'
+{createClient, setup, teardown, calls} = require './util'

 describe 'queue', ->
   beforeEach setup
@@ -17,41 +8,33 @@
   beforeEach ->
     @cName = '_test'
     @docName2 = 'id1'
+    @testClient = createClient @db, (db) -> new TestDriver db
+    @testClient.driver.redis.select(15)
+    @testClient.driver.redis.flushdb()

   afterEach teardown

   it 'queues consecutive operations when they are not commited', calls 3, (done) -> @create =>
-    # TODO noansknv Assert all operations submitted.
-    client = createClient @db, (db) -> new TestDriver db
-
-    # TODO noansknv use consistently #15 in redis
-    client.driver.redis.flushdb()
-
-    # TODO noansknv: Refactor this monstrocity
-    @create2 @docName2
+    @createDoc @docName2

     # A submits 's1A' then 's2A', delay happens and it doesn't get sent to redis.
     # B submits 's1B' and is sent to redis immediately. 's2A' is sent to redis and
     # transformation is needed for 's1A' but per-useragent seq for A is wrong and
     # client is informed that 'Op already submitted'.
-    client.client.submit @cName, @docName, {v:1, op:['s1A'], seq:1, src: 'A', redisSubmitDelay: 50}, (err) ->
+    @testClient.client.submit @cName, @docName, {v:1, op:['s1A'], seq:1, src: 'A', redisSubmitDelay: 50}, (err) ->
       throw new Error err if err
       done()

-    client.client.submit @cName, @docName2, {v:1, op:['s2A'], seq:2, src: 'A', redisSubmitDelay: 10}, (err) ->
+    @testClient.client.submit @cName, @docName2, {v:1, op:['s2A'], seq:2, src: 'A', redisSubmitDelay: 10}, (err) ->
       throw new Error err if err
       done()

-    client.client.submit @cName, @docName, {v:1, op:['s1B'], seq:1, src: 'B'}, (err) =>
+    @testClient.client.submit @cName, @docName, {v:1, op:['s1B'], seq:1, src: 'B'}, (err) ->
       throw new Error err if err
       done()

-  it 'queues up operations per-client until the front of the queue is acknowledged', calls 2, (done) -> @create =>
-    client = createClient @db, (db) -> new TestDriver db
-    driver = client.driver
-
-    # TODO noansknv use consistently #15 in redis
-    driver.redis.flushdb()
+  it 'queues up operations per-client until the front of the queue is submitted to driver', calls 2, (done) -> @create =>
+    driver = @testClient.driver

     op1 =
       cName: @cName
@@ -73,11 +56,11 @@

     assert.equal driver.opList, undefined

-    client.client.submit @cName, @docName, {v:1, op: ['op1'], seq:1, src:'A', redisSubmitDelay:50}, (err) =>
+    @testClient.client.submit @cName, @docName, {v:1, op: ['op1'], seq:1, src:'A', redisSubmitDelay:50}, (err) ->
       throw new Error err if err
       done()

-    client.client.submit @cName, @docName, {v:2, op: ['op2'], seq:2, src:'A', redisSubmitDelay:0}, (err) =>
+    @testClient.client.submit @cName, @docName, {v:2, op: ['op2'], seq:2, src:'A', redisSubmitDelay:0}, (err) ->
       throw new Error err if err
       operationAssert driver.opList, [op1, op2]
       done()


js state machine

js state machine

--- test/state.coffee
+++ test/state.coffee
@@ -1,5 +1,5 @@
 test "State", ->
-  callback = Callback{}, "Test Machine", ->
+  callback = Callback {}, "Test Machine", ->
     console.log "testing"

   equals callback, ! null, "callback shouldn't be null"


preserve original callback signature for addFile

--- services/web/app/coffee/Features/Project/ProjectEntityUpdateHandler.coffee
+++ services/web/app/coffee/Features/Project/ProjectEntityUpdateHandler.coffee
@@ -178,7 +178,7 @@
 				]
 				DocumentUpdaterHandler.updateProjectStructure project_id, userId, {newFiles}, (error) ->
 					return callback(error) if error?
-					callback(null, fileRef, folder_id, result?.path?.fileSystem, fileStoreUrl)
+					callback(null, fileRef, folder_id)

 	replaceFile: wrapWithLock
 		beforeLock: (next) ->


Minor renaming for /:collection/:document

--- test/suite.coffee
+++ test/suite.coffee
@@ -69,6 +69,6 @@
   describe '/:collection', ->
     require './collection-spec.coffee'

-  describe ':collection/:document', ->
+  describe '/:collection/:document', ->
     require './document-spec.coffee'


set the minZoom level to something more sane

--- src/scripts/controllers/mapController.coffee
+++ src/scripts/controllers/mapController.coffee
@@ -27,6 +27,7 @@
     @scope.defaults =
       scrollWheelZoom: true
       zoom: 10
+      minZoom: 2
     @scope.tiles = maps.threedr_default

 class BoundsFactory


Book: deprecated

Book: deprecated

--- client/Main/includes.coffee
+++ client/Main/includes.coffee
@@ -181,16 +181,16 @@

   # BOOK
-  "book/embedded/tableofcontents.coffee",
-  "book/embedded/updatewidget.coffee",
-  "book/embedded/topics.coffee",
-  "book/embedded/startbutton.coffee",
-  "book/embedded/developbutton.coffee",
-  "book/embedded/socialshare.coffee",
-  "book/bookdata.coffee",
-  "book/pointerview.coffee",
-  "book/bookview.coffee",
-  "book/bookpage.coffee",
+  # "book/embedded/tableofcontents.coffee",
+  # "book/embedded/updatewidget.coffee",
+  # "book/embedded/topics.coffee",
+  # "book/embedded/startbutton.coffee",
+  # "book/embedded/developbutton.coffee",
+  # "book/embedded/socialshare.coffee",
+  # "book/bookdata.coffee",
+  # "book/pointerview.coffee",
+  # "book/bookview.coffee",
+  # "book/bookpage.coffee",

   #maintabs


Split pane and move tab when drop event is emitted

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -1669,6 +1669,26 @@
     @targetTabView = null  # Reset

+  handleTabDropToRegion: (direction, ideView) ->
+
+    ideView.emit 'IDETabDropped'
+
+    if direction is 'right' or direction is 'left'
+      type = 'vertical'
+    else
+      type = 'horizontal'
+
+    @setActiveTabView ideView.tabView
+    @splitTabView { type }
+
+    if direction is 'top' or direction is 'left'
+      target = ideView.parent
+    else
+      target = @activeTabView.parent.parent
+
+    @handleTabDropped null, target, null
+
+
   moveTabToPanel: (tabView, targetPanel, index) ->

     return unless tabView.parent?


ide: emit onboarding event

ide: emit onboarding event

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -943,8 +943,13 @@
       else
         @addInitialViews()

+      { mainView, onboardingController } = kd.singletons
+
       data = { machine, workspace: @workspaceData }
-      kd.singletons.mainView.activitySidebar.selectWorkspace data
+      mainView.activitySidebar.selectWorkspace data
+
+      onboardingController.emit "OnboardingRequested", "IDE"
+
       @emit 'IDEReady'


Paragraph detection inside sections.

Paragraph detection inside sections.

--- client/lib/annotator.coffee
+++ client/lib/annotator.coffee
@@ -57,9 +57,10 @@
   setTextContent: (pageNumber, textContent) =>
     @_pages[pageNumber - 1].textContent = textContent

-  _dy: (pageNumber, i) =>
-    page = @_pages[pageNumber - 1]
-    page.textSegments[i + 1].top - page.textSegments[i].top
+  _dy: (pageNumber, i, j) =>
+    j ?= i + 1
+    page = @_pages[pageNumber - 1]
+    page.textSegments[j].top - page.textSegments[i].top

   _computeLineHeight: (pageNumber) =>
     page = @_pages[pageNumber - 1]
@@ -199,17 +200,20 @@

     left + (right - left) * SECTION_INDENT_THRESHOLD

-  _splitParagraphs: (pageNumber, segments, sectionIndentThreshold) =>
-    page = @_pages[pageNumber - 1]
-
-    s = start
+  _splitParagraphs: (pageNumber, segmentsIndices, sectionIndentThreshold) =>
+    page = @_pages[pageNumber - 1]
+
+    s = 0
     paragraphs = []
-    for segment, i in page.textSegments[start...end - 1]
-      if Math.abs(@_dy pageNumber, i) < page.lineHeight * SPLIT_PARAGRAPH_THRESHOLD and segment.left > sectionIndentThreshold
-        paragraphs.push [s, i + 1]
-        s = i + 1
-
-    paragraphs.push [s, end]
+    for j in [1...segmentsIndices.length]
+      segment = page.textSegments[segmentsIndices[j]]
+
+      if @_dy(pageNumber, segmentsIndices[j - 1], segmentsIndices[j]) > page.lineHeight * SPLIT_PARAGRAPH_THRESHOLD and segment.left > sectionIndentThreshold
+        paragraphs.push segmentsIndices[s...j]
+        s = j
+
+    paragraphs.push segmentsIndices[s..segmentsIndices.length]
+    console.log paragraphs
     paragraphs

   _processParagraph: (pageNumber, segmentsIndices) =>
@@ -452,7 +456,7 @@
     @_computeLineHeight pageNumber

     for segmentsIndices in @_splitSections pageNumber
-      @_processParagraph pageNumber, segmentsIndices
+      @_processSection pageNumber, segmentsIndices

     # For debugging
     @_showParagraphs pageNumber


several performance improvements

several performance improvements

--- client/routes/router.coffee
+++ client/routes/router.coffee
@@ -8,7 +8,7 @@
 			return [Meteor.subscribe('userData'), RoomManager.init()]

 	onBeforeAction: ->
-		Session.set('flexOpened', false)
+		Session.setDefault('flexOpened', false)
 		Session.set('openedRoom', null)
 		this.next()

@@ -76,10 +76,7 @@
 		unless ChatRoom.find(@params._id).count()
 			Router.go 'home'

-		Session.set('flexOpened', false)
 		Session.set('openedRoom', this.params._id)
-
-		# zera a showUserInfo pra garantir que vai estar com a listagem do grupo aberta
 		Session.set('showUserInfo', null)

 		this.next()


Match test suite name to module name

Match test suite name to module name

--- test/tests.coffee
+++ test/tests.coffee
@@ -22,7 +22,7 @@
   fn

-describe 'ReactComponentPlugin', ->
+describe 'gsap-react-plugin', ->
   component = null

   assertStartState = (expected) ->


Fix unit test.

Fix unit test.

--- test/types.coffee
+++ test/types.coffee
@@ -7,16 +7,16 @@
 suite 'no setup:', ->
   test 'require does not throw', ->
     assert.doesNotThrow ->
-      require 'types'
+      require module

   test 'require returns object', ->
-    assert.isObject require('types')
+    assert.isObject require(module)

 suite 'require:', ->
   types = null

   setup ->
-    types = require 'types'
+    types = require module

   teardown ->
     types = null


Activity: fixed activity routes for itself and for its sub-routes

--- client/Social/Activity/AppController.coffee
+++ client/Social/Activity/AppController.coffee
@@ -2,7 +2,14 @@

   KD.registerAppClass this,
     name         : "Activity"
-    route        : "/:name?/Activity/:slug?"
+    routes       :
+      "/:name?/Activity/:slug?" : ({params:{name, slug}, query})->
+        {router, appManager} = KD.singletons
+
+        unless slug
+        then router.openSection 'Activity', name, query
+        else router.createContentDisplayHandler('Activity') arguments...
+
     searchRoute  : "/Activity?q=:text:"
     hiddenHandle : yes


Remove caching of workspace concept forms

This was causing an issue when re-showing the views in the main
region. Event handlers were not being rebound so none of the
buttons worked. This seems like an inconsistency in Marionette since
regions close views, but do not attempt to re-render the view when
shown again.

--- coffee/cilantro/ui/concept/workspace.coffee
+++ coffee/cilantro/ui/concept/workspace.coffee
@@ -70,7 +70,6 @@
                 @emptyView = @options.emptyView

             @subscribe c.CONCEPT_FOCUS, @showItem
-            @itemsViews = {}

         showItem: (model) =>
             @ui.mainTab.tab('show')
@@ -78,12 +77,6 @@
             model = @_ensureModel(model)

             if @currentView and model.id is @currentView.model.id
-                return
-
-            # Initialize a ConceptForm view if not already present.
-            # And the corresponding history item
-            if (view = @itemsViews[model.id])?
-                @setCurrentView(view)
                 return

             # Determine if this is registered as a custom concept
@@ -100,10 +93,7 @@

         createView: (itemViewClass, options) =>
             view = new itemViewClass(options)
-
-            @itemsViews[options.model.id] = view
             @history.currentView.collection.add(options.model)
-
             @setCurrentView(view)

         setCurrentView: (view) ->


Always clear recently read timer when switching to something else.

--- app/assets/javascripts/_site.js.coffee
+++ app/assets/javascripts/_site.js.coffee
@@ -140,7 +140,6 @@
   updateReadCount: (id, entry, target) ->
     if entry.read == false
       $.post $(target).data('mark-as-read-path')
-      clearTimeout feedbin.recentlyReadTimer
       feedbin.recentlyReadTimer = setTimeout ( ->
         $.post $(target).data('recently-read-path')
       ), 10000
@@ -625,6 +624,7 @@

     usePreloadContent: ->
       $(document).on 'ajax:beforeSend', '[data-behavior~=open_item]', (event, xhr) ->
+        clearTimeout feedbin.recentlyReadTimer
         id = $(@).parents('li').data('entry-id')
         entry = feedbin.entries[id]
         if entry


Don't select any share item by default.

Don't select any share item by default.

--- app/assets/javascripts/_site.js.coffee
+++ app/assets/javascripts/_site.js.coffee
@@ -375,7 +375,6 @@

       $(document).on 'click', '[data-behavior~=toggle_share_menu]', (event) ->
         $(".dropdown-wrap li").removeClass('selected')
-        $(".dropdown-wrap li:first-child").addClass('selected')
         parent = $(@).closest('.dropdown-wrap')
         if parent.hasClass('open')
           parent.removeClass('open')
@@ -383,6 +382,10 @@
           parent.addClass('open')
           return false
         event.preventDefault()
+
+      $(document).on 'mouseover', '.dropdown-wrap li', (event) ->
+        console.log 'hover'
+        $('.dropdown-wrap li').not(@).removeClass('selected')

     drawer: ->
       $(document).on 'click', '[data-behavior~=toggle_drawer]', (event) =>


Fixed radix and is/== problems

Fixed radix and is/== problems

--- app/assets/javascripts/dhaka.js.coffee
+++ app/assets/javascripts/dhaka.js.coffee
@@ -38,10 +38,10 @@
   $('#debug').click -> $(this).fadeOut()
   $('.currency').numeric { negative: false }
   $('.time-ago').attr('title', '').timeago()
-  returning = switch parseInt($.cookie 'visit')
+  returning = switch parseInt($.cookie('visit'), 10)
     when 1 then false
     else true
-  if $("body").attr('id') == "listings" and $("body").attr('class') == "index" and returning == false
+  if $("body").attr('id') is "listings" and $("body").attr('class') is "index" and returning is false
     $.get '/welcome', (data) ->
       $.fancybox content: data


Set token to 64 characters

Set token to 64 characters

--- app/assets/javascripts/polls.js.coffee
+++ app/assets/javascripts/polls.js.coffee
@@ -1,7 +1,11 @@
 App.Polls =
   generateToken: ->
-    rand = Math.random().toString(36).substr(2) # remove `0.`
-    token = rand + rand # to make it longer
+    token = ''
+    for n in [0..5]
+      rand = Math.random().toString(36).substr(2) # remove `0.`
+      token = token + rand;
+
+    token = token.substring(0, 64)
     return token

   replaceToken: ->


Default coffeescript added

Default coffeescript added

--- app/assets/javascripts/sites.js.coffee
+++ app/assets/javascripts/sites.js.coffee
@@ -1,3 +1,19 @@
-# 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://jashkenas.github.com/coffee-script/
+jQuery ->
+  $(".datepicker").datepicker
+    showOtherMonths: true
+    selectOtherMonths: true
+    changeMonth: true
+    changeYear: true
+
+  $("#ui-datepicker-div").hide()
+
+  $(document).on('click', ".pagination a, .page a, .next a, .prev a", () ->
+    $.get(this.href, null, null, "script")
+    false
+  )
+
+  $(document).on("click", ".per_page a", () ->
+    object_class = $(this).data('object')
+    $.get($("#"+object_class+"_search").attr("action"), $("#"+object_class+"_search").serialize() + "&"+object_class+"_per_page="+ $(this).data('count'), null, "script")
+    false
+  )


KDListViewController: Make sure there is a noItemWidget before changing their states

--- components/list/KDListViewController.coffee
+++ components/list/KDListViewController.coffee
@@ -103,8 +103,8 @@
     {noItemFoundWidget} = @getOptions()
     @getListView().addSubView @noItemView = noItemFoundWidget

-  showNoItemWidget:-> @noItemView.show() if @itemsOrdered.length is 0
-  hideNoItemWidget:-> @noItemView.hide()
+  showNoItemWidget:-> @noItemView?.show() if @itemsOrdered.length is 0
+  hideNoItemWidget:-> @noItemView?.hide()

   # regressed, will put back whenever i'm here again. - SY
   showNoMoreItemWidget:->


prevent loading backlog without projectId

--- app/coffee/modules/backlog/main.coffee
+++ app/coffee/modules/backlog/main.coffee
@@ -63,7 +63,7 @@
         bindMethods(@)

         @.page = 1
-        @.disablePagination = false
+        @.disablePagination = true
         @scope.userstories = []

         @scope.sectionName = @translate.instant("BACKLOG.SECTION_NAME")
@@ -77,6 +77,8 @@

         # On Success
         promise.then =>
+            @.disablePagination = false
+
             title = @translate.instant("BACKLOG.PAGE_TITLE", {projectName: @scope.project.name})
             description = @translate.instant("BACKLOG.PAGE_DESCRIPTION", {
                 projectName: @scope.project.name,
@@ -264,6 +266,8 @@
           @.page = page

     loadUserstories: (resetPagination = false, pageSize) ->
+        return null if !@scope.projectId
+
         @.loadingUserstories = true
         @.disablePagination = true
         @scope.httpParams = @.getUrlFilters()


chore: removing log outs

chore: removing log outs

--- app/controllers/game_controller.coffee
+++ app/controllers/game_controller.coffee
@@ -5,8 +5,6 @@
   addGame: (home, away) ->
     newGame = @addNewGame(home, away)
     @set('pendingGame', newGame)
-    console.log "Setting pending game..."
-    console.log @get('pendingGame')
     @checkCurrent()
   removeGame: (game) ->
     game.delete()
@@ -24,24 +22,17 @@
     # Check for a current game
     @get('store').fetch('currentGame').then ((currentGame) =>
         if currentGame.content.length > 0
-          console.log "There's a game!"
           @set('currentGame', currentGame)
         else
           @newGame()
           @set('currentGame', false)
     ), (error) =>
-      console.log "No games.."
       @set('currentGame', false)
   newGame: ->
-    console.log "do I get called?"
     if !@get('currentGame') && @get('pendingGame')
       @setCurrentGame()
     else
-      console.log "current:"
-      console.log @get('currentGame')
-      console.log "pending:"
-      console.log @get('pendingGame')
-
+      console.log "No games to add?"
   setCurrentGame: ->
     pendingGame = @get('pendingGame')
     @set('pendingGame', false)


Make backward-compatible

Make backward-compatible

--- components/ParseJson.coffee
+++ components/ParseJson.coffee
@@ -3,7 +3,7 @@

 class ParseJson extends noflo.Component
   constructor: ->
-    @try = true
+    @try = false

     @inPorts =
       in: new noflo.Port()
@@ -12,7 +12,7 @@
       out: new noflo.Port()

     @inPorts.in.on "data", (data) =>
-      @try = false if data is "false"
+      @try = true if data is "true"

     @inPorts.in.on "begingroup", (group) =>
       @outPorts.out.beginGroup group


fix version (this is not btsx)

fix version (this is not btsx)

--- app/js/controllers/unlockwallet.coffee
+++ app/js/controllers/unlockwallet.coffee
@@ -23,7 +23,7 @@
       if (Info.info.client_version)
         cancel()
         $scope.client_version = Info.info.client_version
-        if $scope.client_version != "v0.4.15-a"
+        if $scope.client_version != "testnet"
             $scope.update_available = true


things learned when reading documentation.  Use d3 shuffle algorithm.

--- app/scripts/alchemy/defaultConf.coffee
+++ app/scripts/alchemy/defaultConf.coffee
@@ -1,16 +1,3 @@
-# algorithm to randomly shuffle an array
-fisherYates = (arr) ->
-    i = arr.length;
-    if i == 0 then return false
-
-    while --i
-        j = Math.floor(Math.random() * (i+1))
-        tempi = arr[i]
-        tempj = arr[j]
-        arr[i] = tempj
-        arr[j] = tempi
-    return arr
-
 defaults =
     afterLoad: 'drawingComplete'
     alpha: .5
@@ -30,7 +17,7 @@
     removeNodes: false # allow the removal of nodes with controls
     fixRootNodes: true # root nodes are not dragable by default
     # node style settings
-    colours: fisherYates(["#DD79FF", "#FFFC00",
+    colours: d3.shuffle(["#DD79FF", "#FFFC00",
                          "#00FF30", "#5168FF",
                          "#00C0FF", "#FF004B",
                          "#00CDCD", "#f83f00",


Fix handling of empty file names in ProviderInterface.matchesExtension() Empty file names can be created by the Document Store

--- src/code/providers/provider-interface.coffee
+++ src/code/providers/provider-interface.coffee
@@ -173,6 +173,7 @@
     defaultComponent

   matchesExtension: (name) ->
+    return false if not name
     if CloudMetadata.ReadableExtensions? and CloudMetadata.ReadableExtensions.length > 0
       for extension in CloudMetadata.ReadableExtensions
         return true if name.substr(-extension.length) is extension


- Fix logic, make new items work in public feed

--- client/landing/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Activity.kdapplication/AppController.coffee
@@ -332,7 +332,7 @@

   newActivityArrived:(activity)->
     unless @isMine activity
-      if (@_state is 'private' and @isInFollowing activity) or @_state isnt 'public'
+      if (@_state is 'private' and @isInFollowing activity) or @_state is 'public'
         view = @addHiddenItem activity, 0
         @activityHeader.newActivityArrived()
     else


filetree: Fixed "Open terminal from here"

--- client/landing/app/MainApp/filetree/controllers/findertreecontroller.coffee
+++ client/landing/app/MainApp/filetree/controllers/findertreecontroller.coffee
@@ -446,9 +446,9 @@

   openTerminalFromHere: (nodeView) ->
     appManager.open "WebTerm", (appInstance) =>
-      path        = nodeView.getData().path
-      webTermView = KD.getSingleton('mainView').mainTabView.getActivePane().mainView
-      #TODO: webTermView != appInstance.getView() so should simplify the line above
+      path          = nodeView.getData().path
+      appManager    = @getSingleton "appManager"
+      {webTermView} = appManager.getFrontApp().getView().tabView.getActivePane().getOptions()

       webTermView.on "WebTermConnected", (server) =>
         server.input "cd #{path}\n"


Add ability to choose a random sourceVariant for multiple options for starter code

--- app/views/play/level/tome/Spell.coffee
+++ app/views/play/level/tome/Spell.coffee
@@ -41,7 +41,10 @@
     p = programmableMethod
     @commentI18N = p.i18n
     @commentContext = p.context
-    @languages = p.languages ? {}
+    if p.sourceVariants
+      @languages = _.clone _.sample p.sourceVariants
+    else
+      @languages = p.languages ? {}
     @languages.javascript ?= p.source
     @name = p.name
     @permissions = read: p.permissions?.read ? [], readwrite: p.permissions?.readwrite ? ['humans']  # teams


Viewport: Add store/load_debug_camera.

Viewport: Add store/load_debug_camera.

--- engine/viewport.coffee
+++ engine/viewport.coffee
@@ -1,4 +1,4 @@
-{vec2, vec3} = require 'vmath'
+{vec2, vec3, quat} = require 'vmath'
 {DebugCamera} = require './debug_camera'

 # A viewport is a portion of the screen/canvas associated with a camera,
@@ -182,6 +182,20 @@
             @debug_camera_behaviour = null
             return true
         return false
+
+    store_debug_camera: (name) ->
+        if not @debug_camera_behaviour?
+            throw Error "There is no debug camera."
+        if not name?
+            throw Error "Name argument is mandatory."
+        {position, rotation} = @debug_camera
+        localStorage[name] = JSON.stringify {position, rotation}
+
+    load_debug_camera: (name) ->
+        @enable_debug_camera()
+        {position, rotation} = JSON.parse localStorage[name]
+        vec3.set @debug_camera.position, position...
+        quat.set @debug_camera.rotation, rotation...

     get_viewport_coordinates: (x, y) ->
         x -= @left


Disable `removeTrailingWhitespace` in .atom/config.cson.

Avoid accidental whitespace changes in commits.

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -134,3 +134,5 @@
   "vim-mode": {}
   welcome:
     showOnStartup: false
+  whitespace:
+    removeTrailingWhitespace: false


Updated Atom settings.

Updated Atom settings.

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -51,13 +51,21 @@
       "find-and-replace": true
   core:
     disabledPackages: [
+      "term"
+      "atom-jshint"
+      "file-icons"
       "themed-settings"
       "symbols-view"
+    ]
+    themes: [
+      "seti-ui"
+      "seti-monokai"
     ]
   editor:
     invisibles: {}
     fontSize: 14
     showInvisibles: true
+    softWrapHangingIndent: 4
   "autocomplete-plus": {}
   "open-in":
     applications: "SourceTree,Terminal,Finder,WebStorm"


Remove unused handleSwipe method

Remove unused handleSwipe method

--- apps/home/client/hero_unit_view.coffee
+++ apps/home/client/hero_unit_view.coffee
@@ -41,9 +41,6 @@
   setInterval: =>
     clearInterval @interval
     @interval = setInterval @nextHeroUnit, @pauseLength
-
-  handleSwipe: (e, direction) ->
-    console.log('swiped', direction)

   setBodyClass: =>
     if @$window.scrollTop() + @$mainHeader.height() <= @$heroUnitsContainer.height()


update config

update config

--- config/main.kodingme.coffee
+++ config/main.kodingme.coffee
@@ -187,14 +187,14 @@
       logApiUri: "#{customDomain.public}:4030/xhr"
       suppressLogs: no
       broker    :
-        servicesEndpoint: "#{customDomain.public_}:#{customDomain.port}/-/services/broker"
+        servicesEndpoint: "#{customDomain.public}:#{customDomain.port}/-/services/broker"
       premiumBroker:
-        servicesEndpoint: "#{customDomain.public_}:#{customDomain.port}/-/services/premiumBroker"
+        servicesEndpoint: "#{customDomain.public}:#{customDomain.port}/-/services/premiumBroker"
       brokerKite:
-        servicesEndpoint: "#{customDomain.public_}:#{customDomain.port}/-/services/brokerKite"
+        servicesEndpoint: "#{customDomain.public}:#{customDomain.port}/-/services/brokerKite"
         brokerExchange: 'brokerKite'
       premiumBrokerKite:
-        servicesEndpoint: "#{customDomain.public_}:#{customDomain.port}/-/services/premiumBrokerKite"
+        servicesEndpoint: "#{customDomain.public}:#{customDomain.port}/-/services/premiumBrokerKite"
         brokerExchange: 'premiumBrokerKite'
       apiUri    : "#{customDomain.public}"
       version   : version
@@ -250,7 +250,7 @@
     webProtocol       : 'http:'
     authExchange      : authExchange
     authAllExchange   : authAllExchange
-    failoverUri       : "#{customDomain.public}"
+    failoverUri       : customDomain.public_
   premiumBroker       :
     name              : "premiumBroker"
     serviceGenericName: "broker"
@@ -261,7 +261,7 @@
     webProtocol       : 'http:'
     authExchange      : authExchange
     authAllExchange   : authAllExchange
-    failoverUri       : "#{customDomain.public}"
+    failoverUri       : customDomain.public_
   brokerKite          :
     name              : "brokerKite"
     serviceGenericName: "brokerKite"
@@ -272,7 +272,7 @@
     webProtocol       : 'http:'
     authExchange      : authExchange
     authAllExchange   : authAllExchange
-    failoverUri       : "#{customDomain.public}"
+    failoverUri       : customDomain.public_
   premiumBrokerKite   :
     name              : "premiumBrokerKite"
     serviceGenericName: "brokerKite"
@@ -283,7 +283,7 @@
     webProtocol       : 'http:'
     authExchange      : authExchange
     authAllExchange   : authAllExchange
-    failoverUri       : "#{customDomain.public}"
+    failoverUri       : customDomain.public_
   kites:
     disconnectTimeout: 3e3
     vhost       : 'kite'


use module serve-static in example server

--- examples/server.coffee
+++ examples/server.coffee
@@ -2,6 +2,7 @@
 {Duplex} = require 'stream'
 browserChannel = require('browserchannel').server
 connect = require 'connect'
+serveStatic = require 'serve-static'
 argv = require('optimist').argv
 livedb = require 'livedb'
 livedbMongo = require 'livedb-mongo'
@@ -11,11 +12,10 @@

 sharejs = require '../lib'

-webserver = connect(
-  #  connect.logger()
-  connect.static "#{__dirname}/public"
-  connect.static sharejs.scriptsDir
-)
+webserver = connect()
+
+webserver.use serveStatic "#{__dirname}/public"
+webserver.use serveStatic sharejs.scriptsDir

 #backend = livedb.client livedb.memory()
 backend = livedb.client livedbMongo('localhost:27017/test?auto_reconnect', safe:false)


Config: use protocolless version

Config: use protocolless version

--- config/main.kodingme.coffee
+++ config/main.kodingme.coffee
@@ -204,7 +204,7 @@
       uploadsUriForGroup: 'https://koding-groups.s3.amazonaws.com'
       sourceUri : "#{customDomain.public}:3526"
       newkontrol:
-        url     : "ws://#{customDomain.public}:4000/kontrol"
+        url     : "ws://#{customDomain.public_}:4000/kontrol"
       fileFetchTimeout: 15 * 1000 # seconds
       externalProfiles  :
         github          :


updating ops url

updating ops url

--- assets/coffeescript/pupil_store.coffee
+++ assets/coffeescript/pupil_store.coffee
@@ -486,7 +486,7 @@
           $("textarea[id='cartObject']").val(JSON.stringify(orders))
           formData = $(form).serialize()

-          ops_url = "https://script.google.com/macros/s/AKfycbyPEqIjIfyWR09vPhd5HcP7jB9KIjng0YzEwo2tjWOk8aEscM4/exec"
+          ops_url = "https://script.google.com/macros/s/AKfycbx8LH0V-1gd_JSCbQItjtGlTQCNhNpWwFVd7IkW0E_uzmQj1pWP/exec"
           prod_url = "https://script.google.com/macros/s/AKfycbz6VPh0yqNOmAChtPa9C1Ot9dk_JwHWj_vWPIZlPzr4YodmTvs/exec"
           url = ops_url


Add resetData, unload and removeFromCache to Travis.Model

--- assets/scripts/lib/travis/model.coffee
+++ assets/scripts/lib/travis/model.coffee
@@ -145,3 +145,25 @@
     !!@_referenceForId(id).record

   camelizeKeys: true
+
+  # TODO: the functions below will be added to Ember Model, remove them when that
+  # happens
+  resetData: ->
+    @_idToReference = null
+    @sideloadedData = null
+    @recordCache = null
+    @recordArrays = null
+    @_currentBatchIds = null
+    @_hasManyArrays = null
+    @_findAllRecordArray = null
+
+  unload: (record) ->
+    @removeFromRecordArrays(record)
+    primaryKey = record.get(get(this, 'primaryKey'))
+    @removeFromCache(primaryKey)
+
+  removeFromCache: (key) ->
+    if @sideloadedData && @sideloadedData[key]
+      delete this.sideloadedData[key]
+    if @recordCache && @recordCache[key]
+      delete this.recordCache[key]


Fix #2357 "Invalid XML response causes JS error"

--- src/resources-packaged/ops/javascript/orbeon/xforms/LoadingIndicator.coffee
+++ src/resources-packaged/ops/javascript/orbeon/xforms/LoadingIndicator.coffee
@@ -38,7 +38,7 @@
         # Extract whether this is an upload from the object passed to the callback
         # This, because we only want the loading indicator to show for Ajax request, not uploads,
         # for which we have a different way of indicating the upload is in progress.
-        isUpload = (argument) -> _.isBoolean(argument.isUpload) and argument.isUpload
+        isUpload = (argument) -> ! (_.isUndefined(argument)) and _.isBoolean(argument.isUpload) and argument.isUpload

         # When an Ajax call starts, we might want to show the indicator
         Connect.startEvent.subscribe (type, args) =>


user page: stop loading member data on change tab

--- app/assets/javascripts/members.js.coffee
+++ app/assets/javascripts/members.js.coffee
@@ -1,11 +1,16 @@
 window.App.Members =
   first_time: true,
+  requests_pool: [],

   init: ->
     $("#tab_loader").show()

-    $(".members_tabs a").bind "ajax:complete", (request) ->
+    $(".members_tabs a").bind "ajax:complete", (event, request) ->
       $("#tab_loader").hide()
+
+    $(".members_tabs a").bind "ajax:beforeSend", (event, request) ->
+      window.App.Members.abort_requests()
+      window.App.Members.requests_pool.push(request)

     $(document).on "click", ".members_tabs a", ->
       $("#tab_loader, #activity_loader, #cards_loader").show()
@@ -27,6 +32,14 @@

       window.App.Members.first_time = false

+  abort_requests: ->
+    console.log window.App.Members.requests_pool
+    $.each window.App.Members.requests_pool, (idx, request) ->
+      if request.readyState != 4
+        request.abort()
+
+    window.App.Members.requests_pool = []
+
   save_state: (a_selector)->
     state = { tab_id: a_selector.prop("id"), path: a_selector.prop("href") }
     if window.App.Members.first_time
@@ -39,6 +52,8 @@
       url: url
       method: "GET"
       async: true
+      beforeSend: (request)->
+        window.App.Members.requests_pool.push(request)
     )

   get_activity: (url) ->
@@ -46,6 +61,8 @@
       url: url
       method: "GET"
       async: true
+      beforeSend: (request)->
+        window.App.Members.requests_pool.push(request)
     ).done ->
       $("#tab_loader").hide()
       $("#activity_loader").hide()
@@ -55,6 +72,8 @@
       url: url
       method: "GET"
       async: true
+      beforeSend: (request)->
+        window.App.Members.requests_pool.push(request)
     ).done ->
       $("#tab_loader").hide()
       $("#cards_loader").hide()


My list page refreshes when remove item from sidebar

--- app/assets/javascripts/welcome.js.coffee
+++ app/assets/javascripts/welcome.js.coffee
@@ -30,7 +30,6 @@
   $locationProvider.html5Mode(true);
 ])

-
 # ng-controller for My Wish Lists
 App.controller("MyWishListController", ["$scope", "$http", "$routeParams", ($scope, $http, $routeParams) ->

@@ -111,6 +110,10 @@
         console.log "comments retrieve error"

+  $scope.$on( "reloadList", ->
+    $scope.getMyList()
+  )
+
   $scope.getCurrentUser()

   ])
@@ -255,6 +258,7 @@
       .success (data) ->
         console.log "Item destroyed"
         $scope.loadWishList()
+        $scope.$broadcast("reloadList")
       .error (data) ->
         console.log "data error"


Implement league admins route

Implement league admins route

--- app/controllers/league_controller.coffee
+++ app/controllers/league_controller.coffee
@@ -79,14 +79,22 @@
   router.patch ['/:leagueId*'], requireWrite

   router.get '/:leagueId', (request, response) ->
-    findLeague(request.league.id).then (league) ->
-      response.json(league)
+    findLeague(request.league.id)
+      .then (league) ->
+        response.json(league)
+      .catch (error) -> response.status(500).json(error: error)

   router.patch '/:leagueId', (request, response) ->
     request.league.set('public', request.body['public'])
     request.league.save()
       .then ->
         response.json(request.league)
+      .catch (error) -> response.status(500).json(error: error)
+
+  router.get '/:leagueId/admins', (request, response) ->
+    request.league.getAdmins(where: {write: true})
+      .then (admins) ->
+        response.json(admins)
       .catch (error) -> response.status(500).json(error: error)

   router.post '/:leagueId/admins', (request, response) ->


PrivateMessage: Fix wrong channel object reference problem

--- client/Main/socialapicontroller.coffee
+++ client/Main/socialapicontroller.coffee
@@ -200,9 +200,9 @@
     {socialapi} = KD.singletons

     getCurrentGroup (group)->
-      for socialApiChannel in socialApiChannels
+      socialApiChannels.forEach (socialApiChannel) ->
         channelName = generateChannelName socialApiChannel
-        continue  if socialapi.openedChannels[channelName]
+        return  if socialapi.openedChannels[channelName]
         socialapi.cacheItem socialApiChannel
         socialapi.openedChannels[channelName] = {} # placeholder to avoid duplicate registration


[Queue] remove unused imports

[Queue] remove unused imports

--- client/apps/queue/client/client.coffee
+++ client/apps/queue/client/client.coffee
@@ -1,9 +1,6 @@
 Backbone = require 'backbone'
 _ = require 'underscore'
 React = require 'react'
-{ Provider } = require 'react-redux'
-{ createReduxStore } = require '../../../lib/createReduxStore.js'
-
 { div, nav, a, h1 } = React.DOM
 Article = require '../../../models/article.coffee'
 FilterSearch = React.createFactory require '../../../components/filter_search/index.coffee'


Change list to remove tomatoes citation

Change list to remove tomatoes citation

--- js/lesson_plans.coffee
+++ js/lesson_plans.coffee
@@ -74,8 +74,8 @@
       startingText: "* Calculus, A professor, Has no hair, Often wears green\n* Castafiore, An opera singer, Has white hair, Is possibly mentally unwell"
       renderedAnswer: "
\n
Calculus
\n
A professor
\n
Has no hair
\n
Often wears green
\n
\n
\n
Castafiore
\n
An opera singer
\n
Has white hair
\n
Is possibly mentally unwell
\n
\n
\n
"
     4:
-      startingText: "1. Cut the cheese\n  * Make sure that the cheese is cut into little triangles.\n\n2. Slice the tomatoes\n  * Be careful when holding the knife.\n  * For more help on tomato slicing, see Thomas Jefferson's seminal essay \"[Tom Ate Those](http://en.wikipedia.org/wiki/Tomato#cite_note-the_tomato_in_America-4)\""
-      renderedAnswer: "
\n

Cut the cheese
\n
Make sure that the cheese is cut into little triangles.
\n
\n

Slice the tomatoes
\n
Be careful when holding the knife.
\n
For more help on tomato slicing, see Thomas Jefferson's seminal essay \"Tom Ate Those\"
\n
\n
"
+      startingText: "1. Cut the cheese\n  * Make sure that the cheese is cut into little triangles.\n\n2. Slice the tomatoes\n  * Be careful when holding the knife.\n  * For more help on tomato slicing, see Thomas Jefferson's seminal essay **Tom Ate Those**."
+      renderedAnswer: "
\n

Cut the cheese
\n
Make sure that the cheese is cut into little triangles.
\n
\n

Slice the tomatoes
\n
Be careful when holding the knife.
\n
For more help on tomato slicing, see Thomas Jefferson's seminal essay Tom Ate Those.
\n
\n
"

   7:
     0:


Avoid creating additional strings when normalizing the search key.

--- frontend/search.coffee
+++ frontend/search.coffee
@@ -16,16 +16,23 @@
   TITLE: " #{Identifier.TITLE}:"
   ARTIST: " #{Identifier.ARTIST}:"

+IdentifierStrRaw =
+  ALBUM: "#{Identifier.ALBUM}:"
+  TITLE: "#{Identifier.TITLE}:"
+  ARTIST: "#{Identifier.ARTIST}:"
+
 normalizeKey = (value) ->
   normalized = value
-  normalized = normalized.replace /\s+/g, '-'
-  normalized = normalized.replace /-+/g, '-'
+  normalized = normalized.replace /[\s\-]+/g, '-'

   normalized = normalized.toLowerCase()

-  normalized = normalized.replace "album:", "#{Identifier.ALBUM}:"
-  normalized = normalized.replace "title:", "#{Identifier.TITLE}:"
-  normalized = normalized.replace "artist:", "#{Identifier.ARTIST}:"
+  if normalized.indexOf("title:") != -1
+    normalized = normalized.replace "title:", IdentifierStrRaw.TITLE
+  if normalized.indexOf("album:") != -1
+    normalized = normalized.replace "album:", IdentifierStrRaw.ALBUM
+  if normalized.indexOf("artist:") != -1
+    normalized = normalized.replace "artist:", IdentifierStrRaw.ARTIST

   return normalized


add album

add album

--- app/frontend/scripts/templates.js.coffee
+++ app/frontend/scripts/templates.js.coffee
@@ -66,7 +66,7 @@
   {{/queued}}

   {{#queued}}
-    remove from queue
+    add to queue
   {{/queued}}

   {{^queued}}


Remove unneccessary JSON.stringify.

Remove unneccessary JSON.stringify.

--- app/static/script/directive/chart.coffee
+++ app/static/script/directive/chart.coffee
@@ -56,7 +56,7 @@
         scope.chart.src = "/data/ds140-bauxi-clean.csv"

       scope.test = ->
-        request_data = JSON.stringify
+        request_data =
           'years': _.map(scope.chart.data, (row) -> parseInt(row[scope.chart.index]))
           'data': _.map(scope.chart.data, (row) -> parseFloat(row['World production']))


added up-down default keys

added up-down default keys

--- keymaps/php-debug.cson
+++ keymaps/php-debug.cson
@@ -38,3 +38,5 @@
 'atom-workspace .php-debug-console atom-text-editor':
   'alt-up': 'php-debug:navigatePreviousConsoleCommand'
   'alt-down': 'php-debug:navigateNextConsoleCommand'
+  'up': 'php-debug:navigatePreviousConsoleCommand'
+  'down': 'php-debug:navigateNextConsoleCommand'


handling case where spaces retrigger 1209 bug

--- jsapp/xlform_model_view/view.choices.coffee
+++ jsapp/xlform_model_view/view.choices.coffee
@@ -155,6 +155,10 @@
       if lis.length == 1
         lis.find('.js-remove-option').addClass('hidden')
     saveValue: (nval)->
+      # if new value has no non-space characters, it is invalid
+      unless "#{nval}".match /\S/
+        nval = false
+
       if nval
         @model.set("label", nval, silent: true)
         other_names = @options.cl.getNames()


Support moving up/down in tree view with k/j keys

--- keymaps/tree-view.cson
+++ keymaps/tree-view.cson
@@ -12,6 +12,8 @@
   'a': 'tree-view:add'
   'delete': 'tree-view:remove'
   'backspace': 'tree-view:remove'
+  'k': 'core:move-up'
+  'j': 'core:move-down'

 '.tree-view-dialog .mini.editor':
   'enter': 'core:confirm'


Read LICENSE.md as UTF8

Read LICENSE.md as UTF8

--- build/tasks/generate-license-task.coffee
+++ build/tasks/generate-license-task.coffee
@@ -26,7 +26,7 @@
 getLicenseText = (dependencyLicenses) ->
   {keys} = require 'underscore-plus'
   text = """
-    #{fs.readFileSync('LICENSE.md')}
+    #{fs.readFileSync('LICENSE.md', 'utf8')}

     This application bundles the following third-party packages in accordance
     with the following licenses:\n\n


Use indexOf instead of match

Use indexOf instead of match

--- lib/assets/javascripts/turbolinks.js.coffee
+++ lib/assets/javascripts/turbolinks.js.coffee
@@ -250,7 +250,7 @@
 # By forcing Firefox to trigger hashchange, the rest of the code can rely on more
 # consistent behavior across browsers.
 manuallyTriggerHashChangeForFirefox = ->
-  if navigator.userAgent.match(/Firefox/) and !(url = (new ComponentUrl)).hasNoHash()
+  if navigator.userAgent.indexOf('Firefox') != -1 and !(url = (new ComponentUrl)).hasNoHash()
     window.history.replaceState currentState, '', url.withoutHash()
     document.location.hash = url.hash


Fixes for IE 9

Fixes for IE 9

--- lib/assets/javascripts/turbolinks.js.coffee
+++ lib/assets/javascripts/turbolinks.js.coffee
@@ -142,7 +142,8 @@
       nodesToBeKept.push(findNodesMatchingKeys(document.body, options.keep)...) if options.keep
       swapNodes(targetBody, nodesToBeKept, keep: true)

-    existingBody = document.documentElement.replaceChild(targetBody, document.body)
+    existingBody = document.body
+    document.body = targetBody
     onNodeRemoved(existingBody)
     CSRFToken.update csrfToken if csrfToken?
     setAutofocusElement()
@@ -172,10 +173,11 @@
     if targetNode = targetBody.querySelector('[id="'+nodeId+'"]')
       if options.keep
         existingNode.parentNode.insertBefore(existingNode.cloneNode(true), existingNode)
-        targetBody.ownerDocument.adoptNode(existingNode)
+        existingNode = targetNode.ownerDocument.adoptNode(existingNode)
         targetNode.parentNode.replaceChild(existingNode, targetNode)
       else
         targetNode = targetNode.cloneNode(true)
+        targetNode = existingNode.ownerDocument.importNode(targetNode, true)
         existingNode.parentNode.replaceChild(targetNode, existingNode)
         onNodeRemoved(existingNode)
   return


Remove a debugger

Remove a debugger

--- demo_server/src/server/sequence.coffee
+++ demo_server/src/server/sequence.coffee
@@ -26,7 +26,6 @@
     orderBy: (orderbys) ->
         new RDBArray @asArray().sort (a,b) ->
             for ob in orderbys
-                debugger
                 if ob.asc
                     if a[ob.attr].gt(b[ob.attr]) then return true
                 else


Add automatically rewritten / reformatted .atom/config.cson.

Atom apparently rewrites this file automatically, causing manual
indentation to be lost.

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -38,19 +38,19 @@
   "tree-view": {}
   "autocomplete-plus": {}
   "file-types":
-    "^Baskfile$":         "source.shell"
-    "^.amethyst":         "source.js"
-    "^.gitignore":        "source.git-config"
-    "^.gvimrc.after":     "source.viml"
-    "^.profile$":         "source.shell"
-    "^.shared_env.*":     "source.shell"
-    "^.spacemacs$":       "source.lisp"
-    ".*.sshconfig":       "source.ssh-config"
-    "^.vimrc.before$":    "source.viml"
-    "^.vimrc.after$":     "source.viml"
-    ".zsh-theme$":        "source.shell"
-    "^.zshenv.local.*$":  "source.shell"
-    "^.zshrc.local.*$":   "source.shell"
+    "^Baskfile$": "source.shell"
+    "^.amethyst": "source.js"
+    "^.gitignore": "source.git-config"
+    "^.gvimrc.after": "source.viml"
+    "^.profile$": "source.shell"
+    "^.shared_env.*": "source.shell"
+    "^.spacemacs$": "source.lisp"
+    ".*.sshconfig": "source.ssh-config"
+    "^.vimrc.before$": "source.viml"
+    "^.vimrc.after$": "source.viml"
+    ".zsh-theme$": "source.shell"
+    "^.zshenv.local.*$": "source.shell"
+    "^.zshrc.local.*$": "source.shell"
   "fuzzy-finder":
     ignoredNames: [
       "usr"


Update Atom

Update Atom

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -31,6 +31,7 @@
       "git-log"
       "auto-detect-indentation"
       "minimap"
+      "whitespace"
     ]
     audioBeep: false
   "spell-check":
@@ -81,10 +82,7 @@
     intervalMinutes: 60
   "autocomplete-plus":
     includeCompletionsFromAllBuffers: true
-  whitespace:
-    removeTrailingWhitespace: false
-    ignoreWhitespaceOnCurrentLine: false
-    ensureSingleTrailingNewline: false
+  whitespace: {}
   jsformat:
     format_on_save: false
   linter:


:bug: Prevent errors when reading variables from context

--- lib/tasks/scan-buffer-colors-handler.coffee
+++ lib/tasks/scan-buffer-colors-handler.coffee
@@ -22,6 +22,9 @@
         [d,d,name] = match
         baseColor = context.readColor(name)
         @colorExpression = name
+
+        return @invalid = true unless baseColor?
+
         @rgba = baseColor.rgba

   scan: ->


Fix client unit tests

Fix client unit tests

--- client/tests/casper/unit/activity.coffee
+++ client/tests/casper/unit/activity.coffee
@@ -19,7 +19,7 @@
     if not Array.isArray(options)
         options = [ options ]
     casper.evaluate (options) ->
-        Activity = require '../utils/activity_utils'
+        Activity = require 'utils/activity_utils'
         window.testActivity = []
         if not Array.isArray(options)
             options = [ options ]
@@ -59,7 +59,7 @@
     casper.then ->
         test.comment "Search all contacts"
         casper.evaluate ->
-            Activity = require '../utils/activity_utils'
+            Activity = require 'utils/activity_utils'
             options =
                 name: 'search'
                 data:
@@ -90,7 +90,7 @@
     casper.then ->
         test.comment "Should return an error on wrong activity name"
         casper.evaluate ->
-            Activity = require '../utils/activity_utils'
+            Activity = require 'utils/activity_utils'
             options =
                 name: 'cozy'
                 data:
@@ -110,7 +110,7 @@
     casper.then ->
         test.comment "Should return an error on wrong activity type"
         casper.evaluate ->
-            Activity = require '../utils/activity_utils'
+            Activity = require 'utils/activity_utils'
             options =
                 name: 'search'
                 data:
@@ -177,7 +177,7 @@
             options = toDelete.map (e) -> getOptions 'delete', 'id', e
             doActivity options, (res) ->
                 casper.evaluate ->
-                    Activity = require '../utils/activity_utils'
+                    Activity = require 'utils/activity_utils'
                     options =
                         name: 'search'
                         data:


sort default -> false

sort default -> false

--- lib/atom-ternjs.coffee
+++ lib/atom-ternjs.coffee
@@ -38,7 +38,7 @@
       title: 'Sort'
       description: 'Determines whether the result set will be sorted.'
       type: 'boolean'
-      default: true
+      default: false
     caseInsensitive:
       title: 'Case-insensitive'
       description: 'Whether to use a case-insensitive compare between the current word and potential completions.'


Remove unused dependencies

Remove unused dependencies

--- lib/actions/app.coffee
+++ lib/actions/app.coffee
@@ -1,6 +1,4 @@
 _ = require('lodash')
-cliff = require('cliff')
-server = require('../server/server')
 device = require('../device/device')
 table = require('../table/table')
 applicationModel = require('../models/application')


Some fixes and refactoring

Some fixes and refactoring

--- lib/drive/drive.coffee
+++ lib/drive/drive.coffee
@@ -6,6 +6,7 @@
 progressStream = require('progress-stream')

 IS_WINDOWS = os.platform() is 'win32'
+DISK_IO_FLAGS = 'rs+'

 exports.rescanDrives = (callback) ->
 	return callback() if not IS_WINDOWS
@@ -22,7 +23,7 @@
 	async.waterfall([

 		(callback) ->
-			fs.open(devicePath, 'rs+', null, callback)
+			fs.open(devicePath, DISK_IO_FLAGS, null, callback)

 		(fd, callback) ->
 			buffer = new Buffer(bufferSize)
@@ -48,12 +49,10 @@
 	if not IS_WINDOWS and not fs.existsSync(devicePath)
 		return callback(new Error("Invalid device: #{devicePath}"))

-	imageFileStream = fs.createReadStream(imagePath)
+	imageFileSize = fs.statSync(imagePath).size

-	deviceFileStream = fs.createWriteStream(devicePath, flags: 'rs+')
-	deviceFileStream.on('error', callback)
-
-	imageFileSize = fs.statSync(imagePath).size
+	if imageFileSize is 0
+		return callback(new Error("Invalid OS image: #{imagePath}. The image is 0 bytes."))

 	progress = progressStream
 		length: imageFileSize
@@ -71,6 +70,10 @@
 			exports.rescanDrives(callback)

 		(callback) ->
+			deviceFileStream = fs.createWriteStream(devicePath, flags: DISK_IO_FLAGS)
+			deviceFileStream.on('error', callback)
+
+			imageFileStream = fs.createReadStream(imagePath)
 			imageFileStream
 				.pipe(progress)
 				.pipe(deviceFileStream)


Remove unused requires

Remove unused requires

--- lib/linter-less.coffee
+++ lib/linter-less.coffee
@@ -1,9 +1,6 @@
-linterPath = atom.packages.getLoadedPackage("linter").path
-Linter = require "#{linterPath}/lib/linter"
 fs = require "fs"
 path = require "path"
 less = require 'less'
-{Range} = require 'atom'

 LinterLess =


:fire: Remove redundant argument in linter-plus

--- lib/linter-plus.coffee
+++ lib/linter-plus.coffee
@@ -66,7 +66,7 @@
   setMessages: (linter, messages) ->
     @messages.set(linter, messages)

-  deleteMessages: (linter, messages) ->
+  deleteMessages: (linter) ->
     @messages.delete(linter)

   getMessages: ->


add important as possible priority

add important as possible priority

--- lib/phabricator.coffee
+++ lib/phabricator.coffee
@@ -45,6 +45,7 @@
     'low': 25,
     'normal': 50,
     'high': 80,
+    'important': 80,
     'urgent': 80,
     'wish': 0
   }


fix(indent): fixed indent agaiiin

fix(indent): fixed indent agaiiin

--- vue/src/shared/services/group_service.coffee
+++ vue/src/shared/services/group_service.coffee
@@ -16,11 +16,11 @@
       icon: 'mdi-email'
       canPerform: ->
         AbilityService.canChangeGroupVolume(group)
-        perform: ->
-          openModal
-            component: 'ChangeVolumeForm'
-            props:
-              model: membership
+      perform: ->
+        openModal
+          component: 'ChangeVolumeForm'
+          props:
+            model: membership

     edit_group:
       name: 'group_page.options.edit_group'


Making default form work.

Making default form work.

--- lib/star_record.coffee
+++ lib/star_record.coffee
@@ -21,9 +21,9 @@

   fieldsFor: (formName) ->
-    console.log "Form name: #{formName}  fields: #{@forms[formName].fields}"
+    console.log "Form name: #{formName} "
     if formName == 'default'
-      if not @forms[formName]?
+      if not @forms? or not @forms[formName]?
         console.log "For #{formName} Returning fields: #{@fields}"
         return @fields


bug fix for textobject.edge from vL mode

--- lib/text-object.coffee
+++ lib/text-object.coffee
@@ -78,8 +78,7 @@
     {mode, submode} = @vimState
     if settings.get('keepColumOnSelectLinewiseTextObject')
       if @getOperator().instanceof('Select') and @wise is 'linewise' and submode isnt 'linewise'
-        unless @instanceof('Edge')
-          @activateVisualLinwiseMode = -> @vimState.modeManager.activate('visual', 'linewise')
+        @activateVisualLinwiseMode = -> @vimState.modeManager.activate('visual', 'linewise')

     selectResults = []
     @countTimes =>
@@ -951,9 +950,7 @@
     if startScreenPoint? and endScreenPoint?
       screenRange = new Range(startScreenPoint, endScreenPoint)
       range = @editor.bufferRangeForScreenRange(screenRange)
-      getRangeByTranslatePointAndClip(@editor, range, 'end', 'forward')
-    else
-      null
+      getBufferRangeForRowRange(@editor, [range.start.row, range.end.row])

 class AEdge extends Edge
   @extend()