Add rest of CLI options.

Add rest of CLI options.

--- src/cli.coffee
+++ src/cli.coffee
@@ -16,7 +16,7 @@
     -t, --timeout <ms>              set test-case timeout in milliseconds [2000]
     --check-leaks                   check for global variable leaks
     --compilers <ext>:<module>,...  specify compiler to use for a given extension
-    --globals <names>               allow the given comma-delimited global [names]
+    --globals <names>,...           allow the given comma-delimited global [names]
     --recursive                     include sub directories
   """
   process.exit 0
@@ -49,8 +49,14 @@
       opts.host = args.shift()
     when '-p', '--port'
       opts.port = parseInt args.shift(), 10
+    when '--check-leaks'
+      opts.checkLeaks = true
     when '--compilers'
       opts.compilers = args.shift().split ','
+    when '--globals'
+      opts.globals = args.shift().split ','
+    when '--recursive'
+      opts.recursive = true
     else
       opts.files.push opt


Adjusted maxBuffer sent to exec for large repos

--- src/git.coffee
+++ src/git.coffee
@@ -14,7 +14,7 @@
     args    ?= []
     args     = args.join " " if args instanceof Array
     bash     = "#{git_options.bin || Git.bin} #{command} #{options} #{args}"
-    exec bash, {cwd: git_dir, encoding:'binary'}, callback
+    exec bash, {cwd: git_dir, encoding:'binary', maxBuffer: 5000 * 1024}, callback
     return bash

   # Public: Passthrough for raw git commands


Enable network auto-reconnect and channel auto-rejoin

Closes #93

--- src/irc.coffee
+++ src/irc.coffee
@@ -180,11 +180,13 @@
       port: options.port
       stripColors: true
       secure: options.usessl
+      sasl: options.usesasl
       selfSigned: options.fakessl
       certExpired: options.certExpired
       floodProtection: @unfloodProtection(options.unflood),
       floodProtectionDelay: @unfloodProtectionDelay(options.unflood),
-      sasl: options.usesasl
+      autoRejoin: true
+      retryCount: Infinity

     client_options['channels'] = options.rooms unless options.nickpass


Remove property name, body from options. Remove trailing spaces

--- src/ivy.coffee
+++ src/ivy.coffee
@@ -37,6 +37,9 @@

     if not name
       throw new Error "Cannot determine task name. Please pass it explicitly through options."
+    else
+      delete options.name
+      delete options.body

     @taskRegistry[name] = {
       func
@@ -99,10 +102,9 @@

   resumeCaller: (name, args) ->
-    @taskRegistry[name].funcCb.apply @taskRegistry[name].funcCb, args
+    @taskRegistry[name].funcCb.apply @taskRegistry[name].funcCb, args

-
-  ###
+  ###
   # Producer: Main "start it all" API: Calling "delayed/remote" functions as if they were local
   ###


Add some transparency to the tile layer, cleaner formatting.

--- src/map.coffee
+++ src/map.coffee
@@ -6,21 +6,24 @@
     crs = new L.Proj.CRS.TMS crs_name, proj_def, bounds,
         resolutions: [256, 128, 64, 32, 16, 8, 4, 2, 1, 0.5, 0.25, 0.125, 0.0625]

-    layer_name = "hel:orto2013"
-    layer_fmt = "jpg"
-    orto_layer = new L.Proj.TileLayer.TMS "http://geoserver.hel.fi/geoserver/gwc/service/tms/1.0.0/#{layer_name}@ETRS-GK25@#{layer_fmt}/{z}/{x}/{y}.#{layer_fmt}", crs,
+    geoserver_url = (layer_name, layer_fmt) ->
+        "http://geoserver.hel.fi/geoserver/gwc/service/tms/1.0.0/#{layer_name}@ETRS-GK25@#{layer_fmt}/{z}/{x}/{y}.#{layer_fmt}"
+
+    orto_layer = new L.Proj.TileLayer.TMS geoserver_url("hel:orto2013", "jpg"), crs,
         maxZoom: 11
         minZoom: 2
         continuousWorld: true
         tms: false

-    layer_name = "hel:Opaskartta"
-    layer_fmt = "gif"
-    map_layer = new L.Proj.TileLayer.TMS "http://geoserver.hel.fi/geoserver/gwc/service/tms/1.0.0/#{layer_name}@ETRS-GK25@#{layer_fmt}/{z}/{x}/{y}.#{layer_fmt}", crs,
+    guide_map_url = geoserver_url("hel:Opaskartta", "gif")
+    guide_map_options =
         maxZoom: 12
         minZoom: 2
         continuousWorld: true
         tms: false
+
+    map_layer = new L.Proj.TileLayer.TMS guide_map_url, crs, guide_map_options
+    map_layer.setOpacity 0.8

     map = new L.Map 'map',
         crs: crs


Fix style.

Fix style.

--- src/map.coffee
+++ src/map.coffee
@@ -135,16 +135,16 @@
                 service_collection.add @selected_services.last()
             markers = cluster.getAllChildMarkers()
             _.each markers, (marker) =>
-                if marker.unit?
-                    if not @selected_services.isEmpty()
-                        service = @selected_services.find (s) =>
-                            s.get('root') in marker.unit.get('root_services')
-                    else
-                        service = new models.Service
-                            id: marker.unit.get('root_services')[0]
-                            root: marker.unit.get('root_services')[0]
-
-                    service_collection.add service
+                unless marker.unit?
+                    return
+                unless @selected_services.isEmpty()
+                    service = @selected_services.find (s) =>
+                        s.get('root') in marker.unit.get('root_services')
+                else
+                    service = new models.Service
+                        id: marker.unit.get('root_services')[0]
+                        root: marker.unit.get('root_services')[0]
+                service_collection.add service

             colors_ = service_collection.map (service) =>
                 colors.service_color(service)


Fixing iteration.

Fixing iteration.

Fixes #3.

--- direct.coffee
+++ direct.coffee
@@ -20,7 +20,7 @@

     cursor = @_getCollection().find(selector, options)

-    nextObject = blocking(cursor, cursor.nextObject)
+    nextObject = blocking(cursor, cursor.next or cursor.nextObject)

     while document = nextObject()
       eachCallback document


scope

scope

--- app.coffee
+++ app.coffee
@@ -29,7 +29,14 @@
 app.post '/ringonce', (req, res) ->
   twiml = new twilio.TwimlResponse()
   if req.body['DialCallStatus'] == 'completed'
-    twiml.redirect '/gather'
+    twiml = new twilio.TwimlResponse()
+    twiml
+    .say 'Doorbell Yolk!'
+    .gather
+      action: '/keyin'
+      numDigits: 4
+    , () ->
+      @.say 'yolk, please enter your code'
   else
     twiml
     .say 'Trying YOLK again.'


Oh yeah, and also fix the bouncing. (adamp)

--- app.coffee
+++ app.coffee
@@ -13,13 +13,20 @@
   kimono.getData().success (data) ->
     $scope.programs = data.results.collection1

-.controller 'eachThumb', ($scope, $rootScope) ->
+.controller 'eachThumb', ($scope, $rootScope, $timeout) ->
   $scope.isopen = false
   $rootScope.$on 'toggle', (evt, idx, rowCompare) ->
     if idx is $scope.$index
       $scope.isopen = !$scope.isopen
     else
-      $scope.isopen = false
+      if rowCompare isnt 0
+        $scope.isopen = false
+      else
+        $timeout ()->
+          $scope.isopen = false
+          return
+        , 500
+

 .controller 'inlineClicker', ($scope, inlineService) ->
   $scope.fire = (idx) ->


Move package name and package version check

The checks would fire the “versionsCallback” which would also get (re)fired in the “end” event handler.

--- app.coffee
+++ app.coffee
@@ -323,22 +323,8 @@
 										time: versionFileStat.mtime

 									listeners =
-										'startElement: package': (data) ->
-											if data.$.name isnt path.basename packageFolder
-												debug "Boom"
-												callback "package name does not match folder in #{versionFile} (#{data.$.name} isnt #{path.basename packageFolder})"
-												return
-
-											# we discovered the root node, save package name
-											packageData.package = data.$.name
-										'text: package > packageinformation > version':  (data) ->
-											if (data.$text.toLowerCase().replace /[ ]/g, '_') isnt path.basename versionFile, '.tar'
-												debug "Boom"
-												callback "version number does not match filename in #{versionFile} (#{data.$text} isnt #{path.basename versionFile, '.tar'})"
-												return
-
-											# save package version
-											packageData.version = data.$text
+										'startElement: package': (data) -> packageData.package = data.$.name
+										'text: package > packageinformation > version':  (data) -> packageData.version = data.$text
 										'text: package > packageinformation > license': (data) -> packageData.license = data.$text
 										'text: package > packageinformation > isapplication': (data) -> packageData.isapplication = data.$text
 										'text: package > packageinformation > packagename': (data) ->
@@ -375,8 +361,15 @@
 											unless packageData.package?
 												callback "Package name missing in #{versionFile}"
 												return
+											if packageData.package isnt path.basename packageFolder
+												callback "package name does not match folder in #{versionFile} (#{packageData.package} isnt #{path.basename packageFolder})"
+												return
 											unless packageData.version?
 												callback "Version missing in #{versionFile}"
+												return
+											if (packageData.version.toLowerCase().replace /[ ]/g, '_') isnt path.basename versionFile, '.tar'
+												debug "Boom"
+												callback "version number does not match filename in #{versionFile} (#{packageData.version} isnt #{path.basename versionFile, '.tar'})"
 												return

 											callback null, packageData


fixed tests

fixed tests

--- spec/Create.spec.coffee
+++ spec/Create.spec.coffee
@@ -73,6 +73,7 @@
       @testHelper.createProjectSync()
       @wwwPath = path.join @testHelper.testAppPath, "www"
       @configPath = path.join @testHelper.testAppPath, "config"
+      @appPath = @testHelper.testAppPath

     it "has www/index.html with salutation", ->
       indexHTMLPath = path.join @wwwPath, "index.html"
@@ -86,8 +87,8 @@
       contents = fs.readFileSync(applicationCoffeePath).toString()
       expect( contents ).toMatch(/steroids.config.name = \"My New Application\"/)

-    it "has config/bower.json with dependency to steroids.js", ->
-      bowerJsonPath = path.join @configPath, "bower.json"
+    it "has bower.json with dependency to steroids.js", ->
+      bowerJsonPath = path.join @appPath, "bower.json"

       contents = fs.readFileSync(bowerJsonPath).toString()
       expect( contents ).toMatch(/\"steroids-js\": \"/)
@@ -98,11 +99,11 @@
       contents = fs.readFileSync(configXmlPath).toString()
       expect( contents ).toMatch(/DisallowOverscroll/)

-    it "has www/config.android.xml with key with value org.apache.cordova.GeoBroker", ->
+    it "has www/config.android.xml with key with element </widget>", ->
       configXmlPath = path.join @wwwPath, "config.android.xml"

       contents = fs.readFileSync(configXmlPath).toString()
-      expect( contents ).toMatch(/org.apache.cordova.GeoBroker/)
+      expect( contents ).toMatch(/\<\/widget\>/)

     it "does not have a folder named app", ->
       appPath = path.join @testHelper.testAppPath, "app"


:bug: Fix config specs

:bug: Fix config specs

--- spec/config-spec.coffee
+++ spec/config-spec.coffee
@@ -1,9 +1,13 @@
 describe 'Linter Config', ->
   linter = null
   {getLinter, getMessage} = require('./common')
+  Path = require('path')
   CP = require('child_process')
   FS = require('fs')
   Helpers = require('../lib/helpers')
+
+  TempDir = require('os').tmpdir()
+
   beforeEach ->
     waitsForPromise ->
       atom.packages.activatePackage('linter').then ->
@@ -34,8 +38,8 @@
       expect(linter.views.bottomContainer.status.count).toBe(1)
   describe 'ignoreVCSIgnoredFiles', ->
     it 'ignores the file if its ignored by the VCS', ->
-      filePath = "/tmp/linter_test_file"
-      FS.writeFileSync(filePath, "'use strict'\n")
+      filePath = Path.join(TempDir, 'linter_spec_ignored_vcs.min.js')
+      FS.writeFileSync(filePath, 'Hello Dolly')

       atom.config.set('linter.ignoreVCSIgnoredFiles', true)
       linterProvider = getLinter()
@@ -55,8 +59,8 @@

   describe 'ignoreMatchedFiles', ->
     it 'ignores the file if it matches pattern', ->
-      filePath = '/tmp/linter_spec_test.min.js'
-      FS.writeFileSync(filePath, "'use strict'\n")
+      filePath = Path.join(TempDir, 'linter_spec_ignored_match.min.js')
+      FS.writeFileSync(filePath, 'Hello Dolly')

       atom.config.set('linter.ignoreMatchedFiles', '/**/*.min.{js,css}')
       linterProvider = getLinter()


Ensure that .get calls before .requestLoad return .set properties

--- spec/config-spec.coffee
+++ spec/config-spec.coffee
@@ -1753,7 +1753,6 @@
   fdescribe "when .set/.unset is called prior to .loadUserConfig", ->
     beforeEach ->
       atom.config.settingsLoaded = false
-
       fs.writeFileSync atom.config.configFilePath, """
         '*':
           foo:
@@ -1762,20 +1761,23 @@
             ray: 'me'
       """

-    it "ensures that all settings are loaded correctly", ->
-      atom.config.unset('foo.bar')
+    it "ensures that early set and unset calls are replayed after the config is loaded from disk", ->
+      atom.config.unset 'foo.bar'
+      atom.config.set 'foo.qux', 'boo'
+
+      expect(atom.config.get('foo.bar')).toBeUndefined()
+      expect(atom.config.get('foo.qux')).toBe 'boo'
+      expect(atom.config.get('do.ray')).toBeUndefined()
+
+      advanceClock 100
       expect(atom.config.save).not.toHaveBeenCalled()
-      atom.config.set('foo.qux', 'boo')
-      expect(atom.config.save).not.toHaveBeenCalled()
-      expect(atom.config.get('foo.qux')).toBeUndefined()
-      expect(atom.config.get('do.ray')).toBeUndefined()

       atom.config.loadUserConfig()
+
       advanceClock 100
-
       waitsFor -> atom.config.save.callCount > 0

       runs ->
         expect(atom.config.get('foo.bar')).toBeUndefined()
-        expect(atom.config.get('foo.qux')).toBe('boo')
-        expect(atom.config.get('do.ray')).toBe('me')
+        expect(atom.config.get('foo.qux')).toBe 'boo'
+        expect(atom.config.get('do.ray')).toBe 'me'


added pawn, basic stupid movement

added pawn, basic stupid movement

--- maze.coffee
+++ maze.coffee
@@ -71,6 +71,25 @@
     # of .floorBelow, .floorAbove and .floorHere - but jQuery is not a great
     # help in manipulating CCS classes. >:-(

+    # make invisible grid on which the pawn moves
+    @grid = $('

').css({
+        width: @width
+        height: @height
+        position: 'relative',
+        top: @top
+        left: @left
+        zIndex: 10
+    })
+    @div.append(@grid)
+
+    # make pawn
+    @pawn = $('').css({
+       position: 'relative'
+       top: @y * 71
+       left: @x * 71
+    })
+    @grid.append(@pawn)
+
     # draw floors
     for z in [0...@maze.dimensions[2]]
       floor = $('<canvas></canvas>').attr({
@@ -104,17 +123,26 @@
         floor.addClass('floorAbove')

     # attach key event handlers
-    # TODO this should only work when  player is in legal position
     # TODO arrow keys
     $(document).keyup((event) =>
       if event.which == 82 # R key
         @go_up()
       else if event.which == 70 # F key
         @go_down()
+      else if event.which == 37 # Left key
+        @go_left()
+      else if event.which == 38 # Up key
+        @go_forward()
+      else if event.which == 39 # Right key
+        @go_right()
+      else if event.which == 40 # Down key
+        @go_backward()
     )

+  # TODO synchronize all movements!
+  # TODO restrict movement according to walls and floors
+
   go_up: ->
-    # TODO wait until previous animation is finished
     if @z + 1 >= @maze.dimensions[2]
       return
     @floors[@z].switchClass('floorHere', 'floorBelow', {duration: 1500})
@@ -122,13 +150,42 @@
     @floors[@z].switchClass('floorAbove', 'floorHere', {duration: 1500})

   go_down: ->
-    # TODO wait until previous animation is finished
     if @z - 1 < 0
       return
     @floors[@z].switchClass('floorHere', 'floorAbove', {duration: 1500})
     @z -= 1
     @floors[@z].switchClass('floorBelow', 'floorHere', {duration: 1500})

+  go_backward: ->
+    if @y + 1 >= @maze.dimensions[1]
+      return
+    @y += 1
+    @move_pawn()
+
+  go_forward: ->
+    if @y - 1 < 0
+      return
+    @y -= 1
+    @move_pawn()
+
+  go_right: ->
+    if @x + 1 >= @maze.dimensions[0]
+      return
+    @x += 1
+    @move_pawn()
+
+  go_left: ->
+    if @x - 1 < 0
+      return
+    @x -= 1
+    @move_pawn()
+
+  move_pawn: ->
+    @pawn.animate({
+        top: @y * 71
+        left: @x * 71
+    })
+
 root = exports ? this
 root.Maze = Maze
 root.MazeUI3D = MazeUI3D


Fix auth shutdown to correct idle time (30 days)

--- packages/rocketchat-tutum/startup.coffee
+++ packages/rocketchat-tutum/startup.coffee
@@ -14,7 +14,7 @@
 	client.rpush("frontend:#{process.env.TUTUM_CLIENT_HOST}", process.env.TUTUM_CLIENT_NAME)
 	client.rpush("frontend:#{process.env.TUTUM_CLIENT_HOST}", "http://#{process.env.TUTUM_IP_ADDRESS.split('/')[0]}:3000")

-	day = 3600000
+	day = 86400000

 	inactiveDays = 30


teams: integrations: show feedback afgter integration

--- client/admin/lib/views/integrations/adminintegrationdetailsview.coffee
+++ client/admin/lib/views/integrations/adminintegrationdetailsview.coffee
@@ -182,8 +182,9 @@

     integrationHelpers.update options, (err) =>
       return kd.warn err  if err
-
       @settingsForm.buttons.Save.hideLoader()
+      new kd.NotificationView title : 'Integration is successfully saved!'
+      kd.singletons.router.handleRoute '/Admin/Integrations'

   regenerateToken: ->


minor function symbol tweaks + cleanup

minor function symbol tweaks + cleanup

--- app/coffee/metamenu.coffee
+++ app/coffee/metamenu.coffee
@@ -87,8 +87,7 @@
     @initScrolling()
     @initTheme()

-    @$attachment = @$currentMenuPanel.find('.attachment')
-
+    @$attachment = @$currentMenuPanel.find('.attachment')
     @$attachment.find('input').change (event) =>
       $('body').removeClass('fixed, scroll')
       $('body').css('background-attachment', $(event.currentTarget).val())
@@ -166,7 +165,7 @@
   initTheme: =>
     # for new/edit entry
     if $('#entry_view_preference_attributes_theme').attr('id')?
-      $('#light, #dark').click (event) =>
+      $('#light, #dark').click (event) ->
         @newTheme = $(event.currentTarget).attr('id')
         log(@newTheme)
         $('#body').removeClass('dark light').addClass(@newTheme)
@@ -193,7 +192,7 @@
         bedsheet_id: @bedsheetId if @bedsheetId?
         scrolling: @scrolling if @scrolling?
         theme: @theme if @theme?
-        success: (data, status, xhr) =>
+        success: (data, status, xhr) ->
           success = true
      }

@@ -206,7 +205,7 @@
           bedsheet_id: @bedsheetId if @bedsheetId?
           scrolling: @scrolling if @scrolling?
           theme: @theme if @theme?
-          success: (data, status, xhr) =>
+          success: (data, status, xhr) ->
             success = true
        }


Remove the unloadBaseStylesheets()

Remove the unloadBaseStylesheets()

It is no longer necessary. We now replace the contents of the style tags

--- src/atom.coffee
+++ src/atom.coffee
@@ -12,7 +12,6 @@
 ThemeManager = require 'theme-manager'

 window.atom =
-  baseStylesheetPaths: []
   loadedPackages: {}
   activePackages: {}
   packageStates: {}
@@ -143,15 +142,8 @@
     @reloadBaseStylesheets()

   reloadBaseStylesheets: ->
-    @unloadBaseStylesheets()
-    @baseStylesheetPaths.push(requireStylesheet('atom'))
-    if nativeStylesheetPath = fsUtils.resolveOnLoadPath(process.platform, ['css', 'less'])
-      requireStylesheet(nativeStylesheetPath)
-      @baseStylesheetPaths.push(nativeStylesheetPath)
-
-  unloadBaseStylesheets: ->
-    removeStylesheet(sheet) for sheet in @baseStylesheetPaths
-    @baseStylesheetPaths = []
+    requireStylesheet('atom')
+    requireStylesheet(nativeStylesheetPath) if nativeStylesheetPath = fsUtils.resolveOnLoadPath(process.platform, ['css', 'less'])

   open: (options) ->
     ipc.sendChannel('open', options)


移除 setVersion ，因爲版本資訊主要是傳給 Track Server 判斷目前這筆 Track Data 是屬於哪個版本的 trm 送過來，應該依據 trm 確實的版號，故目前調整成會以實際狀況送，而不是讓 tracking code 設定。

--- src/trm.coffee
+++ src/trm.coffee
@@ -46,7 +46,7 @@
       adGroupId: aid || 0
       referer: document.referrer || ""
       id: uuid
-      version: @.version || VERSION || ""
+      version: VERSION || ""
     }

     # if console
@@ -97,9 +97,6 @@
   initial: (id, aid) ->
     @.id = id
     @.aid = aid
-
-  setVersion: (version) ->
-    @.version = version

   _protocol: (url) ->
     protocol = if window.location.protocol is "https:" then "https:" else "http:"


Small stats fix

Small stats fix

--- app/scripts/results.coffee
+++ app/scripts/results.coffee
@@ -870,14 +870,12 @@

         @showPreloader()
         @proxy.makeRequest(cqp, ((args...) => @onProgress(args...))
-        ).done( ([data, wordArray, columns, dataset, summarizedData, searchParams]) =>
+        ).done( ([data, columns, searchParams]) =>
             safeApply @s, () =>
                 @hidePreloader()
-            @savedData = data
-            @savedSummarizedData = summarizedData
-            @savedWordArray = wordArray
+            @data = data
             @searchParams = searchParams
-            @renderResult columns, dataset
+            @renderResult columns, data
         ).fail (textStatus, err) =>
             c.log "fail", arguments
             c.log "stats fail", @s.$parent.loading, _.map @proxy.pendingRequests, (item) -> item.readyState


Minor fix to make attributes appear correctly in sidebar.

--- app/scripts/widgets.coffee
+++ app/scripts/widgets.coffee
@@ -181,7 +181,7 @@
                         showAll.css "display", "none"
                         showOne.css "display", "inline"
                         _.map lis, (li) ->
-
+
                             li.css "display", "list-item"

                     showOne.click () ->
@@ -255,8 +255,8 @@

         else
             if attrs.translationKey
-                if loc_data["en"][attrs.translationKey + value]
-                    return output.append ""
+                if loc_data["is-is"][attrs.translationKey + attrs.dataset[value]]
+                    return output.append ""
                 else
                     return output.append "#{value}"
             else


fix dashboard race condition

fix dashboard race condition

--- lineman/app/components/dashboard_page/dashboard_page_controller.coffee
+++ lineman/app/components/dashboard_page/dashboard_page_controller.coffee
@@ -61,7 +61,9 @@
   @setFilter = (filter = 'show_all') =>
     @filter = filter
     @refresh()
+
   @setFilter()
+  $scope.$on 'currentUserMembershipsLoaded', => @setFilter()
   $scope.$on 'homePageClicked', => @setFilter()
   $scope.$on 'starToggled', @refresh


OHM-277: Correct metadata API http status's

--- src/api/metadata.coffee
+++ src/api/metadata.coffee
@@ -42,8 +42,11 @@
     for key of collections
       exportObject[key] = yield collections[key].find().exec()
     this.body = [exportObject]
+    this.status = 200
   catch e
     utils.logAndSetResponse this, 500, "Could not fetch specified metadata via the API #{e}", 'error'
+    this.body = e.message
+    this.status = 400

 # API endpoint that inserts metadata from import
@@ -58,6 +61,7 @@
     insertObject = this.request.body

     for key of insertObject
+      return throw new Error "Invalid Import Object" if key not of collections
       insertDocuments = insertObject[key]
       for doc in insertDocuments
         try
@@ -84,8 +88,11 @@
           }

     this.body = returnObject
+    this.status = 201
   catch e
     utils.logAndSetResponse this, 500, "Could not fetch all users via the API #{e}", 'error'
+    this.body = e.message
+    this.status = 400

 # API endpoint that updates metadata from import
@@ -100,6 +107,7 @@
     updateObject = this.request.body

     for key of updateObject
+      return throw new Error "Invalid Import Object" if key not of collections
       updateDocuments = updateObject[key]
       for doc in updateDocuments
         name = doc.name
@@ -127,5 +135,8 @@
           }

     this.body = returnObject
+    this.status = 201
   catch e
     utils.logAndSetResponse this, 500, "Could not fetch all users via the API #{e}", 'error'
+    this.body = e.message
+    this.status = 400


Remove specs that don't matter anymore w/ linewise folding

--- spec/app/renderer-spec.coffee
+++ spec/app/renderer-spec.coffee
@@ -327,107 +327,6 @@
           expect(line4.screenDelta).toEqual [1, 0]
           expect(line5.text).toMatch /9-+/

-      describe "when a fold begins on the line on which another fold ends", ->
-        describe "when the second fold is created before the first fold", ->
-          it "renders a placeholder for both folds on the first line of the first fold", ->
-            fold1 = renderer.createFold([[7, 5], [8, 36]])
-            fold2 = renderer.createFold([[4, 29], [7, 4]])
-
-            [line4, line5] = renderer.linesForRows(4, 5)
-            expect(line4.text).toBe  '    while(items.length > 0) {...}...concat(sort(right));'
-            expect(line5.text).toBe '  };'
-
-            expect(changeHandler.callCount).toBe 2
-            [[event1], [event2]] = changeHandler.argsForCall
-            expect(event1.oldRange).toEqual [[7, 0], [8, 56]]
-            expect(event1.newRange).toEqual [[7, 0], [7, 28]]
-            expect(event2.oldRange).toEqual [[4, 0], [7, 28]]
-            expect(event2.newRange).toEqual [[4, 0], [4, 56]]
-            changeHandler.reset()
-
-            fold1.destroy()
-            [line4, line5] = renderer.linesForRows(4, 5)
-            expect(line4.text).toBe '    while(items.length > 0) {...}'
-            expect(line5.text).toBe '    return sort(left).concat(pivot).concat(sort(right));'
-
-            expect(changeHandler).toHaveBeenCalled()
-            [event] = changeHandler.argsForCall[0]
-            expect(event.oldRange).toEqual [[4, 0], [4, 56]]
-            expect(event.newRange).toEqual [[4, 0], [5, 56]]
-            changeHandler.reset()
-
-            fold2.destroy()
-            [line4, line5] = renderer.linesForRows(4, 5)
-            expect(line4.text).toBe '    while(items.length > 0) {'
-            expect(line5.text).toBe '      current = items.shift();'
-
-            expect(changeHandler).toHaveBeenCalled()
-            [event] = changeHandler.argsForCall[0]
-            expect(event.oldRange).toEqual [[4, 0], [4, 33]]
-            expect(event.newRange).toEqual [[4, 0], [7, 5]]
-
-        describe "when the second fold is created after the first fold", ->
-          it "renders a placeholder for both folds on the first line of the first fold", ->
-            fold1 = renderer.createFold([[4, 29], [7, 4]])
-            fold2 = renderer.createFold([[7, 5], [8, 36]])
-            [line4, line5] = renderer.linesForRows(4, 5)
-            expect(line4.text).toBe  '    while(items.length > 0) {...}...concat(sort(right));'
-            expect(line5.text).toBe '  };'
-
-            expect(changeHandler.callCount).toBe 2
-            [[event1], [event2]] = changeHandler.argsForCall
-            expect(event1.oldRange).toEqual [[4, 0], [7, 5]]
-            expect(event1.newRange).toEqual [[4, 0], [4, 33]]
-            expect(event2.oldRange).toEqual [[4, 0], [5, 56]]
-            expect(event2.newRange).toEqual [[4, 0], [4, 56]]
-            changeHandler.reset()
-
-            fold1.destroy()
-            [line4, line5] = renderer.linesForRows(4, 5)
-            [line7] = renderer.linesForRows(7, 7)
-            expect(line4.text).toBe '    while(items.length > 0) {'
-            expect(line5.text).toBe '      current = items.shift();'
-            expect(line7.text).toBe '    }...concat(sort(right));'
-
-            expect(changeHandler).toHaveBeenCalled()
-            [event] = changeHandler.argsForCall[0]
-            expect(event.oldRange).toEqual [[4, 0], [4, 56]]
-            expect(event.newRange).toEqual [[4, 0], [7, 28]]
-            changeHandler.reset()
-
-            fold2.destroy()
-            [line4, line5] = renderer.linesForRows(4, 5)
-            expect(line4.text).toBe '    while(items.length > 0) {'
-            expect(line5.text).toBe '      current = items.shift();'
-
-            expect(changeHandler).toHaveBeenCalled()
-            [event] = changeHandler.argsForCall[0]
-            expect(event.oldRange).toEqual [[7, 0], [7, 28]]
-            expect(event.newRange).toEqual [[7, 0], [8, 56]]
-
-      describe "when a fold starts at the beginning of a line", ->
-        it "renders a placeholder at the beginning of the line", ->
-          renderer.createFold([[4, 0], [7, 4]])
-          expect(renderer.lineForRow(4).text).toBe '...}'
-
-      describe "when a fold ends at the beginning of a line", ->
-        it "renders a placeholder at the beginning of the line", ->
-          renderer.createFold([[4, 29], [7, 0]])
-          expect(renderer.lineForRow(4).text).toBe '    while(items.length > 0) {...    }'
-
-      describe "when a fold starts on the first line of the buffer", ->
-        it "renders the first line correctly when the fold is destroyed", ->
-          fold = renderer.createFold([[0, 14], [0, 27]])
-          fold.destroy()
-          expect(renderer.lineForRow(0).text).toBe 'var quicksort = function () {'
-
-      describe "when a fold causes a wrapped line to become shorter than the max line length", ->
-        it "unwraps the line", ->
-          renderer.setMaxLineLength(50)
-          renderer.createFold([[3, 0], [3, 15]])
-          expect(renderer.lineForRow(3).text).toBe '... items.shift(), current, left = [], right = [];'
-          expect(renderer.lineForRow(4).text).toBe '    while(items.length > 0) {'
-
     describe "when the buffer changes", ->
       [fold1, fold2] = []
       beforeEach ->


:bug: Fix a typo

:bug: Fix a typo

--- spec/indie-spec.coffee
+++ spec/indie-spec.coffee
@@ -42,5 +42,5 @@
     it 'triggers the onDidDestroy event', ->
       listener = jasmine.createSpy('indie.destroy')
       indie.onDidDestroy(listener)
-      indie.disposeS()
+      indie.dispose()
       expect(listener).toHaveBeenCalled()


print raw error when proxy raises an error.

I know it's dirty but that way we are sure that the error is displayed.

--- server/lib/proxy.coffee
+++ server/lib/proxy.coffee
@@ -22,6 +22,8 @@

     # proxy error handling
     proxy.on 'error', (err, req, res) ->
+        console.log err
+
         err = new Error err
         err.statusCode = 500
         err.template =


Recover the spirit of 5f2700b3.

Recover the spirit of 5f2700b3.

--- scripts/views/workspace/sidebar/toc-branch.coffee
+++ scripts/views/workspace/sidebar/toc-branch.coffee
@@ -205,20 +205,16 @@

     deleteModule: (e) ->
       e.preventDefault()
-
       return if not confirm('Are you sure you want to delete this?')

-      if @model.getParent()
+      if @model.removeMe
         model = @model.dereferencePointer?() or @model
-        parent = @model.getParent().dereferencePointer?() or @model.getParent()
+        parent = @model.getParent()
+        parent = parent.dereferencePointer?() or parent
         root = @model.getRoot?()
-
-        @model.getParent().removeChild(@model)
-
+        @model.removeMe()
         if model.get('_selected') or model.findDescendantBFS?((child) -> (child.dereferencePointer?() or child).get('_selected'))
           controller.goEdit(parent.findDescendantDFS((model) -> return model.getChildren().isEmpty()), root)
-      else
-        @model.removeMe() if @model.removeMe && confirm('Are you sure you want to delete this?')

     goEdit: () ->
       # Edit the model in the context of this folder/book. Explicitly close


rewriter: `(a): (b): (c)` is now allowed

--- rewriter.coffee
+++ rewriter.coffee
@@ -134,14 +134,15 @@
       if tag in EXPRESSION_END
         start = stack.pop()
         return 1
-      return 1 unless tag is ':'
-      ago2 = @tag i - 2
-      return 1 unless ago2 is ':' or stack[stack.length - 1]?[0] isnt '{'
+      return 1 unless tag is ':' and
+        ((ago2 = @tag i - 2) is ':' or
+         (ago1 = @tag i - 1) is ')' and @tag(start[1] - 1) is ':' or
+         stack[stack.length - 1]?[0] isnt '{')
       stack.push ['{']
-      idx = if ago2 is '@'
+      idx = if ago1 is ')'
+        start[1]
+      else  if ago2 is '@'
         i - 2
-      else  if @tag(i - 1) is ')'
-        start[1]
       else
         i - 1
       idx -= 2 if @tag(idx - 2) is 'HERECOMMENT'


Agent pie: start/end angle pie transition work

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -151,6 +151,7 @@
         path.transition().duration(750).attrTween('d', (d,i) ->
             `var i`
             theOldDataInPie = @oldPieData ? piedata
+            console.log('@oldPieData',@oldPieData)
             # Interpolate the arcs in data space
             s0 = undefined
             e0 = undefined


Agent pie: edit label transition

Agent pie: edit label transition

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -125,9 +125,9 @@
         if totalLabel.empty()
             totalLabel = svg.append('g').attr('class', 'totalLabel')

-        # Create variables that will be in scope within the transition attrTween function
-        lastPieData = window.oldPieData[@instanceDataId]
+        # Create variables that will be in scope within the path.transition attrTween function
         myInstanceDataId = @instanceDataId
+        lastPieData = window.oldPieData[myInstanceDataId]

         path = pathGroup.selectAll('path.pie').data(piedata)
         path.enter().append('path').attr('class', 'pie').attr('fill', (d, i) -> color i)


Improve control flow when updating the global cache.

* Return errors instead of throwing them.
* Ensure the lock process is set before updating.

--- src/cache/global.coffee
+++ src/cache/global.coffee
@@ -61,19 +61,20 @@
       # Check if there's a process already running to update the cache.
       (exists, done) ->
         if exists
-          throw new CacheError 'The cache is currently locked.'
+          return done new CacheError 'The cache is currently locked.'

         client.get "lock-process:#{name}", done

       (pid, done) ->
         # If there's an update process, check that it's still running.
         if pid and processIsRunning pid
-          throw new CacheError 'A process is currently updating the cache.'
+          return done new CacheError 'A process is currently updating the cache.'

         # Time to update the cache.
         # Set the process lock.
-        client.set "lock-process:#{name}", process.pid
+        client.set "lock-process:#{name}", process.pid, done

+      (locked, done) ->
         # Run the provided method to generate the new value to cache.
         update (err, value) ->
           return done err if err


remove fairy from exception handler

remove fairy from exception handler

--- services/web/app.coffee
+++ services/web/app.coffee
@@ -23,9 +23,6 @@
 		res.end()

 if Settings.catchErrors
-	# fairy cleans then exits on an uncaughtError, but we don't want
-	# to exit so it doesn't need to do this.
-	require "fairy"
 	process.removeAllListeners "uncaughtException"
 	process.on "uncaughtException", (error) ->
 		logger.error err: error, "uncaughtException"


Use '@' instead of 'this.'

Use '@' instead of 'this.'

--- shared/base/view.coffee
+++ shared/base/view.coffee
@@ -113,7 +113,7 @@

   # Get the HTML for the view, including the wrapper element.
   getHtml: ->
-    html = this.getInnerHtml()
+    html = @getInnerHtml()
     attributes = @getAttributes()
     attrString = _.reduce(attributes, (memo, value, key) ->
       memo += " #{key}=\"#{value}\""


Added hooks for rendering and unrendering when converting entities to JSON to allow overriding.

--- src/EntityUtils.coffee
+++ src/EntityUtils.coffee
@@ -36,8 +36,7 @@
         height = space.height
         if height?
           args.height = height
-        result = converter.toGeoEntityArgs(args)
-        df.resolve(result)
+        df.resolve converter.toGeoEntityArgs(args)
       df.reject
     )
     df.promise
@@ -451,20 +450,12 @@
       entitiesJson.push(json)

     df = Q.defer()
-    if Entities.findByProjectAndScenario?
-      entities = Entities.findByProjectAndScenario(projectId, scenarioId).fetch()
-    else
-      entities = Entities.findByProject(projectId).fetch()
-    existingEntities = {}
-    ids = _.map entities, (entity) -> entity._id
-    if Meteor.isServer
-      # Unrender all entities when on the server to prevent using old rendered data.
-      unrenderPromises = _.map ids, (id) => @unrender(id)
-    else
-      unrenderPromises = []
+    entities = @_getEntitiesForJson(args)
+    ids = args.ids = _.map entities, (entity) -> entity._id
+    unrenderPromises = @_unrenderEntitiesBeforeJson(ids: ids)
     Q.all(unrenderPromises).then Meteor.bindEnvironment =>
-      renderPromise = @_renderBulk({ids: ids, projectId: projectId})
-      renderPromise.then ->
+      renderPromise = @_renderEntitiesBeforeJson(args)
+      renderPromise.then ->
         geoEntities = _.map ids, (id) -> AtlasManager.getEntity(id)
         _.each geoEntities, (entity) ->
           addEntity(entity)
@@ -475,6 +466,22 @@
       renderPromise.fin Meteor.bindEnvironment =>
         if Meteor.isServer then _.each ids, (id) => @unrender(id)
     df.promise
+
+  _getEntitiesForJson: (args) ->
+    if Entities.findByProjectAndScenario?
+      entities = Entities.findByProjectAndScenario(projectId, scenarioId).fetch()
+    else
+      entities = Entities.findByProject(projectId).fetch()
+
+  _renderEntitiesBeforeJson: (args) -> @_renderBulk(args)
+
+  _unrenderEntitiesBeforeJson: (args) ->
+    if Meteor.isServer
+      # Unrender all entities when on the server to prevent using old rendered data.
+      # unrenderPromises = _.map ids, (id) => @unrender(id)
+      unrenderPromises = _.map ids, (id) => @unrender(id)
+    else
+      unrenderPromises = []

   _getProjectAndScenarioArgs: (args) ->
     args ?= {}


Require libs in the index js

Require libs in the index js

--- rrrspec-web/assets/javascripts/index.coffee
+++ rrrspec-web/assets/javascripts/index.coffee
@@ -1,3 +1,11 @@
+#= require vendor/jquery-1.10.2
+#= require vendor/mustache
+#= require vendor/moment.min
+#= require vendor/underscore
+#= require vendor/backbone
+#= require bootstrap
+#= require models
+
 class TasksetsView extends Backbone.View
   initialize: (options) ->
     @subviews = []


Optimize recent subs api

Optimize recent subs api

--- server/payments/subscription_handler.coffee
+++ server/payments/subscription_handler.coffee
@@ -101,7 +101,9 @@
             return @sendDatabaseError(res, err)
           log.debug 'Analytics established connection to analytics server.'
           userEventMap = {}
-          db.collection('log').find({user: {$in: subscriberUserIDs}}).sort({_id: -1}).each (err, doc) =>
+          events = ['Finished subscription purchase', 'Show subscription modal']
+          query = {$and: [{user: {$in: subscriberUserIDs}}, {event: {$in: events}}]}
+          db.collection('log').find(query).sort({_id: -1}).each (err, doc) =>
             if err
               db.close()
               return @sendDatabaseError(res, err)


Register Ember Charts version with Ember.

--- src/dist.coffee
+++ src/dist.coffee
@@ -1,6 +1,9 @@
 require 'build/src/charts/templates'

 Ember.Charts = Ember.Namespace.create()
+Ember.Charts.VERSION = '0.0.1'
+
+Ember.libraries?.register 'Ember Charts', Ember.Charts.VERSION

 require 'build/src/charts/helpers'
 require 'build/src/charts/colorable'


draw label

draw label

--- src/draw.coffee
+++ src/draw.coffee
@@ -12,9 +12,11 @@
     paths = world.get 'path'
     return unless paths?
     paths = [paths] if paths !instanceof Array
-    for path in paths
+    elements = paths.map (path) ->
       dict['d'] = path
       SVG.path dict
+    elements.push SVG.text({x: 0, y:0},"hello")
+    elements

   draw_world = (world) ->
     console.log "draw_world #{world}"


library interface

library interface

--- src/RobustaTest.coffee
+++ src/RobustaTest.coffee
@@ -1,22 +1,11 @@
-###
-The whole thing could be titled EZTest, FuellTest
-###
 {Action, Actions, Array, Arrays, Environment, Function, FunctionByLengthMap, FunctionByTypesPairs, FunctionTemplate, Keys, Map, Number, Object, Optional, Pair, Pairs, RegExp, Set, SortedArray, String, Strings, Text} = require "Fuell"
-{Path, Paths, Environment} = require "FuellSys"
-Test = require "./RobustaTest/Test"
+Runner = require "./RobustaTest/Runner"
 MultisuiteSummary = require "./RobustaTest/MultisuiteSummary"
-SuiteByNamePairs = require "./RobustaTest/SuiteByNamePairs"
-CoffeeScript  = require 'coffee-script'
+SuiteByNamePairs = require "./SuiteByNamePairs/Runner"

-
-
-exports[k] = v for k, v of {
-  testDirectory:
-    Runner.testDirectory
-  testFile:
-    Runner.testFile
-  multisuiteSummaryText:
-    MultisuiteSummary.text
-
-}+exports =
+  testDirectory          : Runner.testDirectory
+  testFile               : Runner.testFile
+  multisuiteSummaryText  : MultisuiteSummary.text
+  runTestSuites          : SuiteByNamePairs.run


Fix Issue 79, Error using IE8

Fix Issue 79, Error using IE8

As recommended by jQuery Mobile documention, we need to start processing upon
the document pageinit event and not the document ready event.  When we do this,
we do not get the IE8 error in which the opac tries to focus on an element that
cannot be focussed, namely div.#main, which is the container of the primary
page.

--- src/main.coffee
+++ src/main.coffee
@@ -18,7 +18,8 @@
 	'messages2', 'load_spinner', 'login_bar'
 ], ($) ->

-	$ ->
+	$(document).bind 'pageinit', ->
+
 		# We will apply a load spinner to the body.  The load spinner will
 		# indicate that data is being transferred across the network.
 		$('body').load_spinner()


Remove the old one if we found two same file handles.

Somehow sometimes the binding.watch would return a handle that was
already taken by a live handler, I have no idea of why this happened,
but we simply remove the old one for now so we do not have to throw an
exception.

--- src/main.coffee
+++ src/main.coffee
@@ -40,7 +40,8 @@
     @handle = binding.watch(@path)
     if handleWatchers.has(@handle)
       troubleWatcher = handleWatchers.get(@handle)
-      throw new Error("The handle(#{@handle}) returned by watching #{@path} is the same with an already watched path(#{troubleWatcher.path})")
+      troubleWatcher.close()
+      console.error("The handle(#{@handle}) returned by watching #{@path} is the same with an already watched path(#{troubleWatcher.path})")
     handleWatchers.add(@handle, this)

   closeIfNoListener: ->


correct `this` ref

correct `this` ref


Adding a Point.subtract method.

Adding a Point.subtract method.

--- src/math.coffee
+++ src/math.coffee
@@ -39,6 +39,11 @@
     # vector.
     add : (vector) ->
         return new wolf.Vector(@x + vector.x, @y + vector.y)
+
+    # Return the point produced by substracting the other point from
+    # this point.
+    subtract : (other) ->
+        return new wolf.Point(@x - other.x, @y - other.y)

     # Return true if the point is the origin, otherwise false.
     isOrigin : () ->


Load / run scripts synchronously

Load / run scripts synchronously

--- index.coffee
+++ index.coffee
@@ -3,10 +3,9 @@

 module.exports = (robot, scripts) ->
     scriptsPath = path.resolve(__dirname, 'src')
-    fs.exists scriptsPath, (exists) ->
-        if exists
-            for script in fs.readdirSync(scriptsPath)
-                if scripts? and '*' not in scripts
-                    robot.loadFile(scriptsPath, script) if script in scripts
-                else
-                    robot.loadFile(scriptsPath, script)+    if fs.existsSync scriptsPath
+        for script in fs.readdirSync(scriptsPath).sort()
+            if scripts? and '*' not in scripts
+                robot.loadFile(scriptsPath, script) if script in scripts
+            else
+                robot.loadFile(scriptsPath, script)


update index.coffee

update index.coffee

--- index.coffee
+++ index.coffee
@@ -1,10 +1,12 @@
 fs = require 'fs'
 path = require 'path'

-module.exports = (robot) ->
+module.exports = (robot, scripts) ->
   scriptsPath = path.resolve(__dirname, 'src')
-  fs.exists path, (exists) ->
+  fs.exists scriptsPath, (exists) ->
     if exists
-      for script in fs.readdirSync(path)
-        robot.loadFile(path, file)
-        robot.parseHelp(path.join(path, file))
+      for script in fs.readdirSync(scriptsPath)
+        if scripts? and '*' not in scripts
+          robot.loadFile(scriptsPath, script) if script in scripts
+        else
+          robot.loadFile(scriptsPath, script)


Adds UNARY_MATH to lint !

Adds UNARY_MATH to lint !

--- index.coffee
+++ index.coffee
@@ -25,7 +25,8 @@
       '''

   tokens: [
-    'IF', 'LOOP', 'UNTIL', 'BOOL', 'UNARY', 'COMPARE', 'LOGIC', 'LOOP', '++', '--', '..', '...'
+    'IF', 'LOOP', 'UNTIL', 'BOOL', 'UNARY', 'UNARY_MATH', 'COMPARE', 'LOGIC', 'LOOP', '++', '--',
+    '..', '...'
   ]

   lintToken: (token, tokenApi) ->


Parse version filter

Parse version filter

--- src/cmd/install.coffee
+++ src/cmd/install.coffee
@@ -14,4 +14,21 @@
 """

 @cmd = ->
-  echo "I"
+  z = parse()
+  echo dump z
+
+# Parse version requirements
+@parse =
+parse = (args = argv.slice 1)->
+  ks = abbrev.apply abbrev, keys
+  r = {}
+  for z in args
+    if x = ks[z]
+      r.dist = x
+    else if /^x(\d)/.test z
+      r.x64 = /^6/.test RegExp.$1
+    else if /^\d/.test z
+      r.ver = for z in z.split /\D+/ when z.length
+        Number z
+  r.z = [r.ver or [], [r.dist]]
+  r


Fixed broken auto-reload for workers

Fixed broken auto-reload for workers

--- src/moon.coffee
+++ src/moon.coffee
@@ -289,28 +289,36 @@
       amount++
       while amount -= 1
         worker =  @cluster.fork()
-        @_workers++
-        @workers[worker.pid] = worker
-
-        # On worker death
-        @cluster.on "death", (worker) =>
-          message = "Worker ##{worker.pid} died"
-          if (!worker.refork) and (worker.exitCode > 0)
-            message += " with error: code " + worker.exitCode
-
-          # Remove worker from master list
-          delete @workers[worker.pid]
-
-          if worker.refork or @env is "development"
-            worker = @cluster.fork()
-            @workers[worker.pid] = worker
-          else
-            @_workers--
-            logger.info message
-
-          if @_workers is 0
-            logger.error "All workers are dead. Exiting."
-            process.exit 0
+        # uniqueID is not set in pre v0.8
+        if not worker.uniqueID then worker.uniqueID = worker.pid
+        @_workers++
+        @workers[worker.uniqueID] = worker
+
+      # On worker exit
+      @cluster.on "exit", (worker) =>
+        message = "Worker ##{worker.uniqueID} died"
+        if (!worker.refork) and (worker.exitCode > 0)
+          message += " with error: code #{worker.exitCode}"
+
+        # Remove worker from master list
+        delete @workers[worker.uniqueID]
+
+        if worker.refork or @env is "development"
+          worker = @cluster.fork()
+          @workers[worker.uniqueID] = worker
+        else
+          @_workers--
+          logger.info message
+
+        if @_workers is 0
+          logger.error "All workers are dead. Exiting."
+          process.exit 0
+
+      @cluster.on "online", (worker) =>
+        logger.debug "Worker ##{worker.uniqueID} came online"
+
+      @cluster.on "listening", (worker, listen) =>
+        logger.debug "Worker ##{worker.uniqueID}  is now listening on #{listen.address}:#{listen.port}"

       process.on "message", (msg) =>
         return unless msg.cmd
@@ -326,8 +334,10 @@
         if @cluster.isWorker
           process.on "message", (msg) =>
             switch msg.cmd
-              when "pushToSockets" then @server.pushToSockets msg.data
-              when "stop", "restart" then process.exit(0)
+              when "pushToSockets"
+                @server.pushToSockets msg.data
+              when "stop", "restart"
+                process.exit(0)
         else
           process
             .on "restart", () =>


Add spec for default color value

Add spec for default color value

--- spec/config-spec.coffee
+++ spec/config-spec.coffee
@@ -1291,7 +1291,7 @@
         beforeEach ->
           schema =
             type: 'color'
-            default: true
+            default: 'white'
           atom.config.setSchema('foo.bar.aColor', schema)

         it 'coerces various types to a color object', ->
@@ -1305,6 +1305,13 @@
           expect(atom.config.get('foo.bar.aColor')).toEqual {red: 1, green: 2, blue: 3, alpha: 1}
           atom.config.set('foo.bar.aColor', 'rgba(4,5,6,.7)')
           expect(atom.config.get('foo.bar.aColor')).toEqual {red: 4, green: 5, blue: 6, alpha: .7}
+
+        it 'reverts back to the default value when undefined is passed to set', ->
+          atom.config.set('foo.bar.aColor', 'rgb(255,255,255)')
+          expect(atom.config.get('foo.bar.aColor')).toEqual {red: 255, green: 255, blue: 255, alpha: 1}
+
+          atom.config.set('foo.bar.aColor', undefined)
+          expect(atom.config.get('foo.bar.aColor')).toEqual {red: 255, green: 255, blue: 255, alpha: 1}

       describe 'when the `enum` key is used', ->
         beforeEach ->


Tests: Skip broken coordinator tests

Tests: Skip broken coordinator tests

Broken since msgflo-nodejs 0.4.2. Could be fixed by creating outqueues,
but this functionality should probably use CC/BCC or bind to exchanges
instead

--- spec/coordinator.coffee
+++ spec/coordinator.coffee
@@ -45,7 +45,7 @@
             done()
           first.start (err) -> chai.expect(err).to.be.a 'null'

-      describe 'sending data into participant input queue', ->
+      describe.skip 'sending data into participant input queue', ->
         it 'should receive results on output queue', (done) ->
           @timeout 4000
           first = participants.Hello address, 'hello-first'
@@ -57,7 +57,7 @@
             coordinator.sendTo id, 'name', 'Jon'
           first.start (err) -> chai.expect(err).to.be.a 'null'

-      describe 'sending data to participant connected to another', ->
+      describe.skip 'sending data to participant connected to another', ->
         it 'should receive results at end of flow', (done) ->
           @timeout 4000
           first = participants.Hello address, 'hello1'


Add failing spec

Add failing spec

--- spec/editor-spec.coffee
+++ spec/editor-spec.coffee
@@ -63,6 +63,15 @@
       expect(editor).not.toMatchSelector ':focus'
       expect(editor.hiddenInput).toMatchSelector ':focus'

+    it "does not scroll the editor (regression)", ->
+      editor.attachToDom(heightInLines: 2)
+      editor.selectAll()
+      editor.hiddenInput.blur()
+      editor.focus()
+
+      expect(editor.hiddenInput).toMatchSelector ':focus'
+      expect($(editor[0]).scrollTop()).toBe 0
+
   describe "when the hidden input is focused / unfocused", ->
     it "assigns the isFocused flag on the editor and also adds/removes the .focused css class", ->
       editor.attachToDom()


remove an un needed console.dir

remove an un needed console.dir

--- spec/jekyll-spec.coffee
+++ spec/jekyll-spec.coffee
@@ -43,8 +43,6 @@
       runs ->
         relativePath = atom.workspace.getActiveTextEditor().buffer.file.path.replace(path.join(__dirname, 'sample'), '')

-        console.dir relativePath
-
         expect(relativePath.replace('\\', '/')).toBe '/index.html'
         expect(atom.workspace.getTextEditors().length).toBe 1


Remove 'workspace' from serialized state in spec helper

…Instead of 'workspaceView'.

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -107,7 +107,7 @@

   atom.workspaceView?.remove?()
   atom.workspaceView = null
-  delete atom.state.workspaceView
+  delete atom.state.workspace

   atom.project?.destroy?()
   atom.project = null


default message to empty string

default message to empty string

--- services/web/public/coffee/main/contact-us.coffee
+++ services/web/public/coffee/main/contact-us.coffee
@@ -22,9 +22,9 @@
 			ticketNumber = Math.floor((1 + Math.random()) * 0x10000).toString(32)
 			params =
 				email: $scope.form.email
-				message: $scope.form.message
+				message: $scope.form.message or ""
 				subject: $scope.form.subject + " - [#{ticketNumber}]"
-				about : $scope.form.project_url
+				about : $scope.form.project_url or ""
 				labels: "support"

 			Groove.createTicket params, (err, json)->


more debug

more debug

--- src/poll.coffee
+++ src/poll.coffee
@@ -50,6 +50,7 @@
 		@robot.logger.info "Topic: #{topic}"
 		options = msg.match[2]
 		@robot.logger.info "options: #{options}"
+		@robot.logger.info @
 		response = @createPoll topic, options
 		msg.send "@channel: #{response}"


Fixed fat-arrow

Fixed fat-arrow

--- client/landing/app/Applications/Chat.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Chat.kdapplication/AppController.coffee
@@ -71,7 +71,7 @@
           style      : "modal-clean-red"
           callback   : ->
             chatChannel?.close()?.off()
-            conversation.leave (err)=>
+            conversation.leave (err)->
               warn err  if err
               modal.destroy()
               callback?()


fixing standalone @ references

fixing standalone @ references

--- lexer.coffee
+++ lexer.coffee
@@ -128,7 +128,8 @@
     else
       @tag(1, 'PROPERTY_ACCESS')
   tag: 'IDENTIFIER'
-  tag:  id.toUpperCase() if KEYWORDS.indexOf(id) >= 0 and not (ACCESSORS.indexOf(@tag()) >= 0)
+  tag:  id.toUpperCase() if KEYWORDS.indexOf(id) >= 0 and
+    not ((ACCESSORS.indexOf(@tag()) >= 0) and not @prev().spaced)
   throw new Error('SyntaxError: Reserved word "' + id + '" on line ' + @line) if RESERVED.indexOf(id) >= 0
   tag: 'LEADING_WHEN' if tag is 'WHEN' and BEFORE_WHEN.indexOf(@tag()) >= 0
   @token(tag, id)
@@ -194,7 +195,7 @@
   @line += indent.match(MULTILINER).length
   @i    += indent.length
   next_character: @chunk.match(MULTI_DENT)[4]
-  prev: @tokens[@tokens.length - 2]
+  prev: @prev(2)
   no_newlines: next_character is '.' or (@value() and @value().match(NO_NEWLINE) and prev and (prev[0] isnt '.') and not @value().match(CODE))
   return @suppress_newlines(indent) if no_newlines
   size: indent.match(LAST_DENTS).reverse()[0].match(LAST_DENT)[1].length
@@ -221,7 +222,7 @@
 # Matches and consumes non-meaningful whitespace.
 lex::whitespace_token: ->
   return false unless space: @match WHITESPACE, 1
-  prev: @tokens[@tokens.length - 1]
+  prev: @prev()
   prev.spaced: true if prev
   @i += space.length
   true
@@ -251,8 +252,7 @@
     throw new Error('SyntaxError: Reserved word "' + @value() + '" on line ' + @line + ' can\'t be assigned') if JS_FORBIDDEN.indexOf(@value()) >= 0
   tag: 'TERMINATOR' if value == ';'

-  prev: @tokens[@tokens.length - 1]
-  if CALLABLE.indexOf(@tag()) >= 0 and (not prev or not prev.spaced)
+  if CALLABLE.indexOf(@tag()) >= 0 and (not @prev() or not @prev().spaced)
     tag: 'CALL_START'  if value is '('
     tag: 'INDEX_START' if value is '['
   @token tag, value
@@ -267,15 +267,19 @@

 # Look at a tag in the current token stream.
 lex::tag: (index, tag) ->
-  return unless tok: @tokens[@tokens.length - (index or 1)]
+  return unless tok: @prev(index)
   return tok[0]: tag if tag?
   tok[0]

 # Look at a value in the current token stream.
 lex::value: (index, val) ->
-  return unless tok: @tokens[@tokens.length - (index or 1)]
+  return unless tok: @prev(index)
   return tok[1]: val if val?
   tok[1]
+
+# Look at a previous token.
+lex::prev: (index) ->
+  @tokens[@tokens.length - (index or 1)]

 # Count the occurences of a character in a string.
 lex::count: (string, letter) ->
@@ -301,7 +305,7 @@
   i: 0
   while true
     i += 1
-    tok: @tokens[@tokens.length - i]
+    tok: @prev(i)
     return if not tok
     switch tok[0]
       when 'IDENTIFIER' then tok[0]: 'PARAM'


Disabled playing on click since it's buggy as hell

--- app/views/tile_view.coffee
+++ app/views/tile_view.coffee
@@ -6,7 +6,6 @@
   className: 'tile'
   template: _.template("
<%= label %>
")
   events:
-    'click'      : 'play'
     'touchstart' : 'dragTileStart'
     'touchmove'  : 'dragTileMove'
     'touchend'   : 'dragTileEnd'


Port Network tests

Port Network tests

--- spec/Network.coffee
+++ spec/Network.coffee
@@ -4,7 +4,7 @@
   path = require 'path'
   root = path.resolve __dirname, '../'
 else
-  noflo = require 'noflo/src/lib/NoFlo.js'
+  noflo = require 'noflo'
   root = 'noflo'

 describe 'NoFlo Network', ->


:lipstick:

:lipstick:


Attribute some of my nonsense.

Attribute some of my nonsense.

--- scripts/dice.coffee
+++ scripts/dice.coffee
@@ -16,6 +16,8 @@
 # Author:
 #   ab9
 #   https://github.com/github/hubot-scripts/blob/master/src/scripts/dice.coffee
+#   drobati
+#   Added fudge dice and modifiers.

 module.exports = (robot) ->
   robot.respond /roll (die|one)/i, (msg) ->


Layout

Layout

- New methods "setAbsolute", "unsetAbsolute", can be used
  to toggle the "absolute" mechanism Layout provides.

--- src/base/Layout/Layout.coffee
+++ src/base/Layout/Layout.coffee
@@ -279,6 +279,23 @@
 		else
 			return super(value, key)

+	setAbsolute: ->
+		@addClass("cui-absolute")
+		Layout.__all()
+
+	unsetAbsolute: ->
+		@DOM.removeAttribute("data-cui-absolute-check-value")
+		@DOM.removeAttribute("data-cui-absolute-values")
+
+		for child in CUI.DOM.children(@DOM)
+			CUI.DOM.setStyle child,
+				top: ""
+				left: ""
+				right: ""
+				bottom: ""
+
+		@removeClass("cui-absolute")
+		@

 	getName: ->
 		assert(false, "#{@__cls}.getName", "Needs to be overwritten.")


cordova plugins activated

cordova plugins activated

--- build/tasks/cordovacli.coffee
+++ build/tasks/cordovacli.coffee
@@ -6,10 +6,29 @@
     cordova:
         options:
 #            command: ['create','platform','plugin','build']
-            command: 'create'
+            command: ['create','plugin']
 #            platforms: ['ios','android']
             platforms: 'android'
-            plugins: ['device','dialogs']
+#            plugins: ['device','dialogs']
+            plugins: [
+                      'battery-status',
+                      'camera',
+                      'console',
+                      'contacts',
+                      'device',
+                      'device-motion',
+                      'device-orientation',
+                      'dialogs',
+                      'file',
+                      'geolocation',
+                      'globalization',
+                      'inappbrowser',
+                      'media',
+                      'media-capture',
+                      'network-information',
+                      'splashscreen',
+                      'vibration'
+                      ]
             path: 'dist'
             id: 'com.planetva.todo'
             name: 'ToDo'


Update node data structure only after sanity checks

--- src/coordinator.coffee
+++ src/coordinator.coffee
@@ -222,8 +222,6 @@
       callback = metadata
       metadata = {}
     metadata = {} unless metadata
-    @nodes[node] = { metadata: {} } if not @nodes[node]
-    @nodes[node].metadata = metadata
     if @options.ignore?.length and node in @options.ignore
       console.log "WARNING: Not restarting ignored participant #{node}"
       return callback null
@@ -231,6 +229,11 @@
       console.log "WARNING: Attempting to start participant with missing component: #{node}(#{component})"
       # XXX: should be an error, but Flowhub does this in project mode..
       return callback null
+
+    @nodes[node] = { metadata: {} } if not @nodes[node]
+    @nodes[node].metadata = metadata
+    @nodes[node].component = component
+
     iips = {}
     cmd = @library.componentCommand component, node, iips
     commands = {}


Update: configを後から拡張可能に

Update: configを後から拡張可能に

--- src/core/config.coffee
+++ src/core/config.coffee
@@ -69,10 +69,9 @@
   return ensureFile(filePath).then( ->
     return readJson(filePath, throws: false)
   ).then( (content) ->
+    data = Object.assign({}, DEFAULT_DATA)
     if content?
-      data = content
-    else
-      data = Object.assign({}, DEFAULT_DATA)
+      data = Object.assign(data, content)
     _update()
   )


Add missing fs-plus require

Add missing fs-plus require

--- spec/default-directory-provider-spec.coffee
+++ spec/default-directory-provider-spec.coffee
@@ -1,5 +1,6 @@
 DefaultDirectoryProvider = require "../src/default-directory-provider"
 path = require "path"
+fs = require 'fs-plus'
 temp = require "temp"

 describe "DefaultDirectoryProvider", ->


Only authenticate on certain paths

Only authenticate on certain paths

--- server/auth.coffee
+++ server/auth.coffee
@@ -20,6 +20,7 @@
 #
 # User information is also stored in redis.
 exports.middleware = -> (req, res, next) ->
+  return next()  if req.path.match(/^\/css|^\/js|^\/fonts/)
   authenticate req, (body) ->
     if !body
       redirectURL = "https://pokebattle.com/accounts/login"


Next try to fix see more feature.

Next try to fix see more feature.

--- app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee
+++ app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee
@@ -82,9 +82,9 @@
         if article_lines.length > preview
           preview_mode = true
           if article_lines[preview] is ''
-            article_lines.splice( preview-1, 0, "----SEEMORE----" )
+            article_lines.splice( preview, 0, "----SEEMORE----" )
           else
-            article_lines.splice( preview, 0, "----SEEMORE----" )
+            article_lines.splice( preview + 1, 0, "----SEEMORE----" )
           article['html'] = article_lines.join("\n")
         article['html'] = window.linkify( article['html'] )
         notify = "" + T('See more') + ""


less naming

less naming

--- gulp-nav.coffee
+++ gulp-nav.coffee
@@ -27,7 +27,7 @@
   finish = finish.split '/'
   finish.shift() while start.length and start.shift() is last = finish[0]
   finish = last unless finish.length
-  ('..' for s in start)                               # ascend out of remaining
+  ('..' for _ in start)                               # ascend out of remaining
     .concat finish                                    # descend into remaining
     .join '/'
     .replace /(^|\.\/)$/, '.'


Few fixes for form serializer

Few fixes for form serializer

--- app/assets/javascripts/rademade_admin/form/form-ajax-submit.coffee
+++ app/assets/javascripts/rademade_admin/form/form-ajax-submit.coffee
@@ -74,6 +74,7 @@
     # It finds all 'array' members of data hash,
     # and splits their values by ',', cleaning all
     # non-space characters.
+    #todo extract. All class need super refactoring. Sergey, you can do it :)
     for memb of items.data
       array = items.data[memb]
       if $.isArray(array)
@@ -85,6 +86,9 @@
             newArray = $.merge(newArray, cleanVal.split(','))

         items.data[memb] = if newArray.length is 0 then [''] else newArray
+
+    input_method = @_$form.find('input[name="_method"]')
+    items['_method'] = input_method.val() if input_method instanceof jQuery

     $.ajax(
       url: @_$form.attr('action')


logic of redraw loop changed to constant loop

--- hyperbolic_tessellation_test_app.coffee
+++ hyperbolic_tessellation_test_app.coffee
@@ -246,19 +246,31 @@
   updatePopulation()

 frameRequested = false
+dirty = true
 redraw = ->
+  dirty = true
+  #avoid spamming frame requests for smoother movement.
+  #unless frameRequested
+  #  frameRequested = true
+  #  window.requestAnimationFrame ->
+  #    drawEverything()
+  #    frameRequested = false
+
+drawEverything = ->
   s = Math.min( canvas.width, canvas.height ) / 2
-  #avoid spamming frame requests for smoother movement.
-  unless frameRequested
-    frameRequested = true
-    window.requestAnimationFrame ->
-      frameRequested = false
-      context.clearRect 0, 0, canvas.width, canvas.height
-      context.save()
-      context.scale s, s
-      context.translate 1, 1
-      observer.draw cells, tfm, context
-      context.restore()
+  context.clearRect 0, 0, canvas.width, canvas.height
+  context.save()
+  context.scale s, s
+  context.translate 1, 1
+  observer.draw cells, tfm, context
+  context.restore()
+
+redrawLoop = ->
+  if dirty
+    drawEverything()
+    dirty = false
+  requestAnimationFrame redrawLoop
+

 toggleCellAt = (x,y) ->
   s = Math.min( canvas.width, canvas.height ) * 0.5
@@ -403,8 +415,9 @@
 updatePopulation = ->
   E('population').innerHTML = ""+cells.count

-redraw()
+#redraw()
 updatePopulation()
+redrawLoop()

 viewUpdates = 0
 #precision falls from 1e-16 to 1e-9 in 1000 steps.


Fix home page compile in gulpfile

Fix home page compile in gulpfile

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -5,7 +5,7 @@
 gulp.task 'default', ->
 	gulp.src './index.jade'
 	.pipe jade()
-	.pipe gulp.dest './index.html'
+	.pipe gulp.dest '.'

 	gulp.src './on/**/index.jade'
 	.pipe jade()


updated to v0.0.74

updated to v0.0.74

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -13,6 +13,8 @@

   gulp.src './source/index.js'
   .pipe gulp.dest ''
+
+#return (require 'gulp').task 'default', -> compile()

 # require


Toggle `expanded` class in particles.js canvas

--- assets/js/src/cover.coffee
+++ assets/js/src/cover.coffee
@@ -13,6 +13,7 @@
     method = if options.toggle is 'hide' then 'addClass' else 'toggleClass'
     $('.cover')[method] 'expanded'
     $('.link-item')[method] 'expanded'
+    $('#particles-js')[method] 'expanded'
     Uno.search.form options.form if options.form?

   $('#blog-button').click ->


Add major bump protection :-)

Add major bump protection :-)

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -328,8 +328,11 @@
   runSequence 'build', 'run', done

 gulp.task 'bump', (done) ->
+  type = args.major && 'major' || args.minor && 'minor' || 'patch'
+  # This prevents accidental major bump.
+  return if type == 'major'
   gulp.src paths.packages
-    .pipe bump type: args.major && 'major' || args.minor && 'minor' || 'patch'
+    .pipe bump type: type
     .pipe gulp.dest './'
     .on 'end', ->
       version = require('./package').version


chore(build): add open to serve config

chore(build): add open to serve config

An update in gulp-connect required the open config to be set.
The app was loaded without open being set prior.

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -192,9 +192,10 @@

 gulp.task 'serve', ['build'], ->
 	server = connect.server
+		livereload: true
+		open: true
+		port: devPort
 		root: [distDirectory]
-		port: devPort
-		livereload: true

 	server()


build step fix

build step fix

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -143,7 +143,7 @@
 gulp.task 'stylus', -> processStylesheets()
 gulp.task 'static', -> processStatic()

-gulp.task 'minify', ['browserify', 'stylus'], ->
+gulp.task 'minify', ['browserify', 'stylus', 'static'], ->
   gulp.src("#{ASSETS_LOCATION}/*.js")
     .pipe(uglify())
     .pipe(rename(MINIFIED_NAME))


gulpfile error

gulpfile error

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -37,8 +37,8 @@
     ])
     .pipe(
       gulpif("settings.json",
-        replace(/"parse": \{(.*)\}/, "\"parse\": #{JSON.stringify GLOBAL_CONFIGS.parse}"),
-        replace(/"database": \{(.*)\}/, "\"database\": #{JSON.stringify GLOBAL_CONFIGS.database}")
+        replace(/"PARSE": \{(.*)\}/, "\"PARSE\": #{JSON.stringify GLOBAL_CONFIGS.parse}"),
+        replace(/"DATABASE": \{(.*)\}/, "\"DATABASE\": #{JSON.stringify GLOBAL_CONFIGS.database}")
         )
     )
     .pipe(gulpif("*.coffee",coffee()))


beeeeep

beeeeep

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -41,11 +41,10 @@

 # some prints

-console.log 'Build in ' + env + ' mode.'
-console.log 'Debug is ' + (if debug then 'enabled' else 'disabled') + '.'
-console.log 'Paths are : '
-console.log paths
-
+$.util.log 'Build in ' + env + ' mode.'
+$.util.log 'Debug is ' + (if debug then 'enabled' else 'disabled') + '.'
+$.util.log 'Paths are : '
+$.util.log paths

 # preprocessing tasks

@@ -155,6 +154,7 @@
     paths.build + '/templates.js'
     paths.build + '/conf.js'
   ], cb
+  do $.util.beep

 # final build task


turn on jsnext flag of node-resolve

turn on jsnext flag of node-resolve

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -181,7 +181,10 @@
         cache: utils.cache
         plugins: _.compact [

-            utils.require 'rollup-plugin-node-resolve'
+            utils.require 'rollup-plugin-node-resolve', {
+                jsnext: true
+                browser: true
+            }

             utils.require 'rollup-plugin-commonjs', {
                 include: 'node_modules/**'


fix #22

fix #22

--- server/init.coffee
+++ server/init.coffee
@@ -12,7 +12,7 @@
             CozyInstance.getInstance (err, instance) ->

                 edenUrl = "http://www.enov.fr/mesinfos/"
-                if instance.helpUrl? and instance.helpUrl is edenUrl
+                if instance? and instance.helpUrl? and instance.helpUrl is edenUrl
                     bankListFile = "banks-mesinfos.json"
                 else
                     bankListFile = "banks-all.json"


Empty values are not sending

Empty values are not sending

When using PHP 7.1 types empty arguments throw an error due to bad type conversion from empty string to int. They must be not sent

public function handleSort(?int $item_id = NULL, ?int $prev_id = NULL, ?int $next_id = NULL)

--- assets/src/datagrid.coffee
+++ assets/src/datagrid.coffee
@@ -236,8 +236,8 @@
 			component_prefix = row.closest('.datagrid').find('tbody').attr('data-sortable-parent-path')

 			data[(component_prefix + '-item_id').replace(/^-/, '')] = item_id
-			data[(component_prefix + '-prev_id').replace(/^-/, '')] = prev_id
-			data[(component_prefix + '-next_id').replace(/^-/, '')] = next_id
+			if (prev_id != null) data[(component_prefix + '-prev_id').replace(/^-/, '')] = prev_id
+			if (next_id != null) data[(component_prefix + '-next_id').replace(/^-/, '')] = next_id

 			$.nette.ajax({
 				type: 'GET',
@@ -302,8 +302,8 @@
 				data = {}

 				data[(component_prefix + '-item_id').replace(/^-/, '')] = item_id
-				data[(component_prefix + '-prev_id').replace(/^-/, '')] = prev_id
-				data[(component_prefix + '-next_id').replace(/^-/, '')] = next_id
+				if (prev_id != null) data[(component_prefix + '-prev_id').replace(/^-/, '')] = prev_id
+				if (next_id != null) data[(component_prefix + '-next_id').replace(/^-/, '')] = next_id
 				data[(component_prefix + '-parent_id').replace(/^-/, '')] = parent_id

 				$.nette.ajax({


Fixed Multiple Game Running Bug

Fixed Multiple Game Running Bug

--- server/main.coffee
+++ server/main.coffee
@@ -24,10 +24,13 @@
         OnlineUsers.remove(user._id)
     return
   ,2000
+
   #Increments the Games Running
   Meteor.setInterval () ->
     runningGames = GameRooms.find({state: "launched"}).fetch()
+    console.log("Games Running:" + runningGames.length)
     for n, i in runningGames
+      console.log("Game Number:" + i)
       n.gameData.MapGrid.tiles = MapMethods.newGeneration(n.gameData.MapGrid.tiles)
       console.log(n.gameData.Age)
       GameRooms.update(n._id,
@@ -36,9 +39,9 @@
             Age     : n.gameData.Age+1
             MapGrid :
               tiles : n.gameData.MapGrid.tiles )
-      console.log("Updated DB")
-      return
-  ,5000
+    return
+  ,2000
+
   #Delete Games if the users are no longer in them every few minutes
   Meteor.setInterval () ->
     runningGames = GameRooms.find({state: "launched"}).fetch()
@@ -69,5 +72,5 @@
               console.log("Player Removed")
         else
           console.log("Were Good, the user is still in")
-  ,1000
+  ,4000


Export Emitter instead of EventEmitter

Export Emitter instead of EventEmitter

--- exports/atom.coffee
+++ exports/atom.coffee
@@ -1,6 +1,6 @@
 {View, $$, $$$} = require '../src/space-pen-extensions'
 {Document, Point, Range, Site} = require 'telepath'
-{EventEmitter, Subscriber} = require 'emissary'
+{Emitter, Subscriber} = require 'emissary'

 module.exports =
   _: require '../src/underscore-extensions'
@@ -11,7 +11,7 @@
   BufferedProcess: require '../src/buffered-process'
   Directory: require '../src/directory'
   Document: Document
-  EventEmitter: EventEmitter
+  Emitter: Emitter
   File: require '../src/file'
   fs: require '../src/fs-utils'
   Git: require '../src/git'


fix to oab reindex script, try again

fix to oab reindex script, try again

--- server/api/lib/elasticsearch.coffee
+++ server/api/lib/elasticsearch.coffee
@@ -114,8 +114,9 @@
     return false

 API.es._reindexing = false
-API.es.reindex = (index, type, mapping=API.es._mapping, rename, dlt=false, change, fromurl=API.settings.es.url, tourl=API.settings.es.url) ->
+API.es.reindex = (index, type, mapping=API.es._mapping, rename, dlt=false, change, fromurl=API.settings.es.url, tourl) ->
   fromurl = fromurl[Math.floor(Math.random()*fromurl.length)] if Array.isArray fromurl
+  tourl ?= fromurl # define here, not in the method signature, to ensure it matches fromurl when it should.
   tourl = tourl[Math.floor(Math.random()*tourl.length)] if Array.isArray tourl
   return false if not index? or not type?
   # index names will be treated as specific
@@ -123,7 +124,7 @@
   API.es._reindexing = index + '/' + type
   toindex = if rename? then rename.split('/')[0] else index
   totype = if rename? then (if rename.indexOf('/') isnt -1 then rename.split('/')[1] else rename) else type
-  intermediate = if not rename? and fromurl is tourl then '_temp_reindex_' else ''
+  intermediate = if not rename? and fromurl is tourl then 'temp_reindex_' else ''
   processed = 0
   try
     try pim = RetryHttp.call 'PUT', tourl + '/' + intermediate + toindex, {retry:API.es._retries}
@@ -156,10 +157,11 @@
     processed = false
   if processed isnt false
     if dlt isnt false or intermediate isnt ''
+      # can only delete original type, because the original index could have other types that should remain
       deleted_original = RetryHttp.call 'DELETE', fromurl + '/' + index + '/' + type, {retry:API.es._retries}
     if intermediate isnt ''
       try
-        try nim = RetryHttp.call 'PUT', tourl + '/' + toindex, {retry:API.es._retries}
+        try nim = RetryHttp.call 'PUT', tourl + '/' + toindex, {retry:API.es._retries} # will fail if index still exists, but that is OK
         nitm = RetryHttp.call 'PUT', tourl + '/' + toindex + '/_mapping/' + totype, {data: mapping, retry:API.es._retries}
         ret = RetryHttp.call 'POST', tourl + '/' + intermediate + toindex + '/' + totype + '/_search?search_type=scan&scroll=1m', {data:{query: { match_all: {} }, size: 10000 }, retry:API.es._retries}
         if ret.data?._scroll_id?


update values

update values

--- server/models/homedata_model.coffee
+++ server/models/homedata_model.coffee
@@ -6,9 +6,9 @@
     helloworld:           type: String,     default: 'Hello!'
     username:             type: String,     default: 'Cozy User'
     title:                type: String,     default: 'view finder'
-    lat:                  type: Number,     default: 42
-    lng:                  type: Number,     default: 0
-    zoom:                 type: Number,     default: 3
+    lat:                  type: Number,     default: 13
+    lng:                  type: Number,     default: -37
+    zoom:                 type: Number,     default: 2
     show_pin_point:       type: Boolean,    default: true
     placesdata_db:        type: Boolean,    default: true
     kilometres:           type: Boolean,    default: true
@@ -27,4 +27,3 @@
     mapbox_subdomains:    type: String,     default: 'abcd'
     mapbox_id:            type: String,     default: 'examples.map-i87786ca'
     mapbox_accessToken:   type: String,     default: '<your access token here>'
-


Changed if statements within _onTouchEnd - previously they were strictly checking for GESTURE.angle_difference !== 0 and GESTURE.distance_difference !== 0 but because capture rotation and capture pinch return undefined if they are below the predetermined threshold it meant that any double touch that wasn't a pinch or a zoom (like a double tap) was still firing these events: 'pinch', 'pinchIn' 'rotate', 'rotateLeft' So just changed them to check for if angle_difference and distance_difference are truthy so a negative or positive number will pass through but undefined will not. Also added in a 'twoTap' event for when you do a double finger tap as I couldn't find any support for this anywhere. I think the coffee script is correct but not sure as I usually just do pure JS. Also couldn't find any instructions for if a build was required before committing (assume that's what Grunt is for?) but you can at least see the changes here and decide if they're worthwhile. :)

--- src/quo.gestures.coffee
+++ src/quo.gestures.coffee
@@ -8,7 +8,7 @@
     TOUCH_TIMEOUT = undefined
     HOLD_DELAY = 650
     GESTURES = ["touch",
-                "tap", "singleTap", "doubleTap", "hold",
+                "tap", "singleTap", "twoTap" "doubleTap", "hold",
                 "swipe", "swiping", "swipeLeft", "swipeRight", "swipeUp", "swipeDown",
                 "rotate", "rotating", "rotateLeft", "rotateRight",
                 "pinch", "pinching", "pinchIn", "pinchOut",
@@ -105,12 +105,12 @@
                     ), 100)
         else
             anyevent = false
-            if GESTURE.angle_difference isnt 0
+            if GESTURE.angle_difference
                 _trigger "rotate", angle: GESTURE.angle_difference
                 rotation_direction = if GESTURE.angle_difference > 0 then "rotateRight" else "rotateLeft"
                 _trigger rotation_direction, angle: GESTURE.angle_difference
                 anyevent = true
-            if GESTURE.distance_difference isnt 0
+            if GESTURE.distance_difference
                 _trigger "pinch", angle: GESTURE.distance_difference
                 pinch_direction = if GESTURE.distance_difference > 0 then "pinchOut" else "pinchIn"
                 _trigger pinch_direction, distance: GESTURE.distance_difference
@@ -120,6 +120,9 @@
                     _trigger "drag"
                     drag_direction = _swipeDirection(FIRST_TOUCH[0].x, CURRENT_TOUCH[0].x, FIRST_TOUCH[0].y, CURRENT_TOUCH[0].y)
                     _trigger "drag" + drag_direction
+                    anyevent = true
+            if not anyevent
+                _trigger "twoTap"
             _cleanGesture()
         EVENT = undefined


Client: Test: Stores: Use envDataProvider.fetch.toReturnLoadDataWithOwnMachine

--- client/app/lib/flux/test/stores/environment/workspacesstore.coffee
+++ client/app/lib/flux/test/stores/environment/workspacesstore.coffee
@@ -12,12 +12,7 @@
 { _id }               = workspace

-ENV_DATA =
-  collaboration : []
-  shared        : []
-  own           : [
-    { machine : mock.getMockJMachine(), workspaces : [ workspace ] }
-  ]
+ENV_DATA = mock.envDataProvider.fetch.toReturnLoadDataWithOwnMachine()

 describe 'WorkspacesStore', ->


Load package stylesheets right before activation

Previously this was done eagerly for packages using activation events.

--- src/atom-package.coffee
+++ src/atom-package.coffee
@@ -65,6 +65,7 @@
   activateNow: ->
     try
       @activateConfig()
+      @activateStylesheets()
       if @requireMainModule()
         @mainModule.activate(atom.getPackageState(@name) ? {})
         @mainActivated = true
@@ -80,11 +81,13 @@
       @mainModule.activateConfig?()
     @configActivated = true

+  activateStylesheets: ->
+    type = if @metadata.theme then 'theme' else 'bundled'
+    applyStylesheet(stylesheetPath, content, type) for [stylesheetPath, content] in @stylesheets
+
   activateResources: ->
     keymap.add(keymapPath, map) for [keymapPath, map] in @keymaps
     atom.contextMenu.add(menuPath, map['context-menu']) for [menuPath, map] in @menus
-    type = if @metadata.theme then 'theme' else 'bundled'
-    applyStylesheet(stylesheetPath, content, type) for [stylesheetPath, content] in @stylesheets
     syntax.addGrammar(grammar) for grammar in @grammars
     for [scopedPropertiesPath, selector, properties] in @scopedProperties
       syntax.addProperties(scopedPropertiesPath, selector, properties)


improve fastBinding, compiling

improve fastBinding, compiling

--- src/fastBinding.coffee
+++ src/fastBinding.coffee
@@ -1,9 +1,48 @@
+
+pathToEl = (path) ->
+    if not path.length
+        return 'el'
+
+    result = 'el'
+    for i in path
+        result += ".childNodes[#{i}]"
+    result
+
+
+compileText = (text) ->
+    data = alight.utils.parsText text
+    for d in data
+        if d.type isnt 'expression'
+            continue
+
+        if d.list.length > 1  # has filters
+            return null
+
+        key = d.list[0]
+        if key[0] is '#'
+            return null
+        if key[0] is '='
+            return null
+        if key[0..1] is '::'
+            return null
+
+        ce = alight.utils.compile.expression key,
+            string: true
+            full: true
+            rawExpression: true
+
+        if not ce.rawExpression
+            throw 'Error'
+        d.re = ce.rawExpression
+
+    st = alight.utils.compile.buildSimpleText text, data
+    st.fn
+

 alight.core.fastBinding = fastBinding = (element) ->
     self = @
-    self.textBindings = []
-    self.attrBindings = []
-
+    source = []
+    self.fastWatchFn = []
     path = [0]
     walk = (element, deep) ->
         if element.nodeType is 1
@@ -11,10 +50,20 @@
             for attr in element.attributes
                 if attr.value.indexOf(alight.utils.pars_start_tag) < 0
                     continue
-                self.attrBindings.push
-                    value: attr.value
-                    name: attr.nodeName
-                    path: path.slice()
+
+                text = attr.value
+                key = attr.nodeName
+
+                rel = pathToEl path
+                fn = compileText text
+                rtext = text.replace(/"/g, '\\"').replace(/\n/g, '\\n')
+                rCallback = 'function(value) {f$.attr(' + rel + ', "' + key + '", value); return "$scanNoChanges"}'
+                if fn
+                    source.push 's.fw("' + rtext + '", ' + self.fastWatchFn.length + ', ' + rCallback + ');'
+                    self.fastWatchFn.push fn
+                else
+                    source.push 's.wt("' + rtext + '", ' + rCallback + ');'
+
             # child nodes
             for childElement, i in element.childNodes
                 path.length = deep + 1
@@ -23,43 +72,56 @@
         else if element.nodeType is 3
             if element.nodeValue.indexOf(alight.utils.pars_start_tag) < 0
                 return
-            self.textBindings.push
-                value: element.nodeValue
-                path: path.slice()
+
+            text = element.nodeValue
+
+            rel = pathToEl path
+            fn = compileText text
+            rtext = text.replace(/"/g, '\\"').replace(/\n/g, '\\n')
+            rCallback = 'function(value) {' + rel + '.nodeValue=value; return "$scanNoChanges"}'
+            if fn
+                source.push 's.fw("' + rtext + '", ' + self.fastWatchFn.length + ', ' + rCallback + ');'
+                self.fastWatchFn.push fn
+            else
+                source.push 's.wt("' + rtext + '", ' + rCallback + ');'
+
         null

     walk element, 0
+
+    source = source.join '\n'
+    self.resultFn = alight.utils.compile.Function 's', 'el', 'f$', source

     @

 fastBinding::bind = (cd, element) ->
     self = @
+    self.currentCD = cd
+    self.resultFn self, element, f$
+    null

-    for item in self.attrBindings
-        childElement = element
-        for n in item.path
-            childElement = childElement.childNodes[n]
+fastBinding::fw = (text, fnIndex, callback) ->
+    self = @
+    cd = self.currentCD
+    fn = self.fastWatchFn[fnIndex]
+    value = fn cd.scope
+
+    callback value
+    cd.watchList.push
+        isStatic: false
+        isArray: false
+        extraLoop: false
+        deep: false
+        value: value
+        callbacks: [callback]
+        exp: fn
+        src: text
+        onStop: []
+    null

-        setter = do (element=childElement, attrName=item.name) ->
-            (result) ->
-                f$.attr element, attrName, result
-                '$scanNoChanges'

-        cd.watchText item.value, setter,
-            init: true
-
-    for item in self.textBindings
-        childElement = element
-        for n in item.path
-            childElement = childElement.childNodes[n]
-
-        setter = do (element=childElement) ->
-            (result) ->
-                element.nodeValue = result
-                '$scanNoChanges'
-
-        cd.watchText item.value, setter,
-            init: true
-
+fastBinding::wt = (expression, callback) ->
+    @.currentCD.watchText expression, callback,
+        init: true
     null


Better click to open

Better click to open

--- app/assets/javascripts/ckeditor/plugins/effective_menus/plugin.js.coffee
+++ app/assets/javascripts/ckeditor/plugins/effective_menus/plugin.js.coffee
@@ -70,7 +70,7 @@
         event.preventDefault()

     initCkEditorEvents: ->
-      @menu.on 'dblclick', 'li.dropdown', (event) ->
+      @menu.on 'click', 'li.dropdown.open', (event) ->
         event.stopPropagation()
         CKEDITOR.instances[Object.keys(CKEDITOR.instances)[0]].openDialog 'effectiveMenusDialog', (dialog) ->
           dialog.effective_menu_item = $(event.currentTarget)


fix for #395

fix for #395

--- app/assets/javascripts/oxalis/view/left-menu/dataset_actions_view.coffee
+++ app/assets/javascripts/oxalis/view/left-menu/dataset_actions_view.coffee
@@ -101,7 +101,7 @@

     event.preventDefault()
     @saveNow().done =>
-        window.location.href = event.target.href
+        window.location.href = event.currentTarget.href

   saveTracing : (event) ->


Switch to using an output formatter for the currency and date formatting

I was having some trouble with no method errors on the data formating.
Instead of troubleshoot that, I just wrote the output formatter. I
should review this later and test the formats instead. Extending Number
and Date would be nicer.

--- src/scripts/cash.coffee
+++ src/scripts/cash.coffee
@@ -18,8 +18,14 @@
 # Author:
 #   jhubert

-Number.prototype.toDollars = (currency_symbol = (process.env.HUBOT_CASH_CURRENCY_SYMBOL or '$'), thousands_separator = (process.env.HUBOT_CASH_THOUSANDS_SEPARATOR or ',')) ->
-    n = this
+class OutputFormatter
+  months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]
+
+  constructor: ->
+    return
+
+  toDollars: (number, currency_symbol = (process.env.HUBOT_CASH_CURRENCY_SYMBOL or '$'), thousands_separator = (process.env.HUBOT_CASH_THOUSANDS_SEPARATOR or ',')) ->
+    n = parseInt(number, 10)
     sign = if n < 0 then "-" else ""
     i = parseInt(n = Math.abs(n).toFixed(0)) + ''
     j = if (j = i.length) > 3 then j % 3 else 0
@@ -27,12 +33,13 @@
     y = i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands_separator)
     sign + currency_symbol + x + y

-Date.months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]
-Date::getNiceDate = ->
-  Date.months[@getMonth()] + ' ' + @getDate() + ', ' + @getFullYear()
+  toNiceDate: (date) ->
+    date = new Date(String(date))
+    @months[date.getMonth()] + ' ' + date.getDate() + ', ' + date.getFullYear()

-Date::getMonthName = ->
-  Date.months[@getMonth()]
+  getMonthName: (date) ->
+    date = new Date(String(date))
+    @months[date.getMonth()]

 class Cash
   constructor: (@robot) ->
@@ -73,14 +80,15 @@
 module.exports = (robot) ->

   cash = new Cash robot
+  optf = new OutputFormatter()

   robot.respond /cash (left|on hand)( is)? (.+)$/i, (msg) ->
     amount = cash.set_on_hand msg.match[3]
-    msg.send "Ok, cash on hand is #{amount.toDollars()}"
+    msg.send "Ok, cash on hand is #{optf.toDollars(amount)}"

   robot.respond /cash burn( rate)?( is)? (.+)$/i, (msg) ->
     amount = cash.set_burn_rate msg.match[3]
-    msg.send "Ok, our burn rate is #{amount.toDollars()} per month"
+    msg.send "Ok, our burn rate is #{optf.toDollars(amount)} per month"

   robot.respond /cash (stats|state|update)/i, (msg) ->
     data = cash.data()
@@ -102,7 +110,7 @@
       end_date.setMonth(end_date.getMonth() + months)

       output = ''
-      output += "Ok, we have #{current_cash.amount.toDollars()} on hand as of #{current_cash.date.getNiceDate()}"
+      output += "Ok, we have #{optf.toDollars(current_cash.amount)} on hand as of #{optf.toNiceDate(current_cash.date)}"

       # If we have history, add a comparison to the last cash status
       if data.on_hand.length > 1
@@ -113,11 +121,11 @@
         else
           diff_type = 'less'

-        output += ", which is #{Math.abs(diff).toDollars()} #{diff_type} than on #{last_cash.date.getNiceDate()}. "
+        output += ", which is #{optf.toDollars(Math.abs(diff))} #{diff_type} than on #{optf.toNiceDate(last_cash.date)}. "
       else
         output += "."

-      output += "\nAt our current burn rate (#{current_burn.rate.toDollars()} / month), we have #{months} months left. That gets us to #{end_date.getMonthName()} #{end_date.getFullYear()}."
+      output += "\nAt our current burn rate (#{optf.toDollars(current_burn.rate)} / month), we have #{months} months left. That gets us to #{optf.getMonthName(end_date)} #{end_date.getFullYear()}."

       msg.send output
     else


maths (UK)

maths (UK)

in the UK, it is mathS, not math

--- src/scripts/math.coffee
+++ src/scripts/math.coffee
@@ -5,7 +5,7 @@
 #   hubot math me <expression> - Calculate the given expression.
 #   hubot convert me <expression> to <units> - Convert expression to given units.
 module.exports = (robot) ->
-  robot.respond /(calc|calculate|convert|math)( me)? (.*)/i, (msg) ->
+  robot.respond /(calc|calculate|convert|math|maths)( me)? (.*)/i, (msg) ->
     msg
       .http('https://www.google.com/ig/calculator')
       .query


Finder: style included

Finder: style included

--- client/finder/includes.coffee
+++ client/finder/includes.coffee
@@ -43,6 +43,7 @@
   "fs/appswatcher.coffee",

   # Styles
-  "styl/app.finder.styl"
+  # "styl/app.finder.styl"
+  "styl/resurrection.finder.styl"

 ]


Add user's _id in onlineUsers

Add user's _id in onlineUsers

--- client/lib/RoomManager.coffee
+++ client/lib/RoomManager.coffee
@@ -178,6 +178,7 @@
 			delete onlineUsersValue[user.username]
 		else
 			onlineUsersValue[user.username] =
+				_id: user._id
 				status: status
 				utcOffset: utcOffset


Fix Logging

Fix Logging

--- src/server/index.coffee
+++ src/server/index.coffee
@@ -15,6 +15,10 @@
 module.exports.expressApp = expressApp

 derby.use require('racer-db-mongo')
+
+if process.env.NODE_ENV is 'development'
+  racer.use(racer.logPlugin)
+  derby.use(derby.logPlugin)

 store = module.exports.pvStore = derby.createStore
   listen: server
@@ -75,12 +79,3 @@

 io.configure 'production', ->
   io.set "transports", ["websocket", "xhr-polling", "jsonp-polling", "htmlfile"]
-
-if process.env.NODE_ENV is "production"
-  # If error is thrown, don't crash the server
-  process.on 'uncaughtException', (err) ->
-    console.log err.stack
-    console.log "Node NOT Exiting..."
-else
-  racer.use(racer.logPlugin)
-  derby.use(derby.logPlugin)


Change default reason to a period

Change default reason to a period

It seems Bitbucket now always has a response.reason included so the check
needs to be updated to also check the pullrequest reason exists too.

--- src/bitbucket-pr.coffee
+++ src/bitbucket-pr.coffee
@@ -39,7 +39,10 @@
     @destination_branch = @resp.pullrequest.destination.branch.name
     @repo_name = @resp.repository.name
     @pr_link = @resp.pullrequest.links.html.href
-    @reason = if @resp.reason isnt '' then ":\n\"#{@resp.pullrequest.reason}\"" else "."
+    @reason = "."
+    if @resp.reason isnt ''
+      if @resp.pullrequest.reason isnt ''
+        @reason = ":\n\"#{@resp.pullrequest.reason}\""

   getReviewers: ->
     if @resp.pullrequest.reviewers.length > 0


Remove : from error message

Remove : from error message

--- src/browser/main.coffee
+++ src/browser/main.coffee
@@ -66,7 +66,7 @@
     try
       AtomPortable.setPortable(atomHome)
     catch error
-      console.log("Failed copying portable directory: '#{atomHome}' to '#{AtomPortable.getPortableAtomHomePath()}'")
+      console.log("Failed copying portable directory '#{atomHome}' to '#{AtomPortable.getPortableAtomHomePath()}'")
       console.log("#{error.message} #{error.stack}")

   if AtomPortable.isPortableInstall(process.platform, process.env.ATOM_HOME, atomHome)


:art: Move one flag near deprecated flag

--- src/browser/main.coffee
+++ src/browser/main.coffee
@@ -107,6 +107,8 @@
       ATOM_HOME               The root path for all configuration files and folders.
                               Defaults to `~/.atom`.
   """
+  # Deprecated 1.0 API preview flag
+  options.alias('1', 'one').boolean('1').describe('1', 'This option is no longer supported. Atom now defaults to launching with the 1.0 API. Use --include-deprecated-apis to run Atom with deprecated APIs.')
   options.boolean('include-deprecated-apis').describe('include-deprecated-apis', 'Include deprecated APIs.')
   options.alias('d', 'dev').boolean('d').describe('d', 'Run in development mode.')
   options.alias('f', 'foreground').boolean('f').describe('f', 'Keep the browser process in the foreground.')
@@ -121,9 +123,6 @@
   options.alias('v', 'version').boolean('v').describe('v', 'Print the version.')
   options.alias('w', 'wait').boolean('w').describe('w', 'Wait for window to be closed before returning.')
   options.string('socket-path')
-
-  # Deprecated 1.0 API preview flag
-  options.alias('1', 'one').boolean('1').describe('1', 'This option is no longer supported. Atom now defaults to launching with the 1.0 API. Use --include-deprecated-apis to run Atom with deprecated APIs.')

   args = options.argv


Extract MockFunction._build_mock_function()

--- src/TinyMock.coffee
+++ src/TinyMock.coffee
@@ -11,7 +11,31 @@
     fail(messages.ExpectsMethodAlreadyExists, expects_method_name) if Object.prototype[expects_method_name]?
     mock_objects = ( new MockObject() for i in [1..mock_count] )
     mock_methods = new MockMethodList()
-    Object.prototype[expects_method_name] = (method_name) ->
+    Object.prototype[expects_method_name] = _build_mock_function(expects_method_name, mock_methods)
+    try
+      test_function.apply(null, mock_objects)
+      errors = mock_methods.find_errors()
+      fail( errors.join("\n") + "\n" ) unless errors.length == 0
+    finally
+      mock_methods.restore_original_methods()
+      delete Object.prototype[expects_method_name]
+
+  # private
+
+  _check_mock_usage = (args) ->
+    fail(messages.MockUsage) if args.length < 1 or 2 < args.length
+    fail(messages.MockUsage) if args.length == 1 and not is_function(args[0])
+    fail(messages.MockUsage) if args.length == 2 and not is_function(args[1])
+    fail(messages.MockBadUsage) if args.length == 2 and not has_property(args[0], "expects_method_name") and not has_property(args[0], "mock_count")
+
+  _parse_args = (args) ->
+    test_function = ( if args.length == 1 then args[0] else args[1] )
+    expects_method_name = ( if args.length == 2 then args[0].expects_method_name ) ? "expects"    # TODO: use merge idiom?  what happens if expects_method_name is not a valid method name?
+    mock_count = ( if args.length == 2 then args[0].mock_count ) ? 5                              # TODO: what happens if mock_count is not a number?
+    [ expects_method_name, mock_count, test_function ]
+
+  _build_mock_function = (expects_method_name, mock_methods) ->
+    (method_name) ->
       fail(messages.ExpectsUsage) unless method_name?
       fail(messages.ExpectsUsage) if arguments.length != 1
       fail(messages.NotAnExistingMethod, method_name) unless is_mock_object(@) or has_method(@, method_name)
@@ -40,27 +64,6 @@
         @[method_name] = mock_method
         mock_methods.add(mock_method)
       expectations.create_expectation()
-    try
-      test_function.apply(null, mock_objects)
-      errors = mock_methods.find_errors()
-      fail( errors.join("\n") + "\n" ) unless errors.length == 0
-    finally
-      mock_methods.restore_original_methods()
-      delete Object.prototype[expects_method_name]
-
-  # private
-
-  _check_mock_usage = (args) ->
-    fail(messages.MockUsage) if args.length < 1 or 2 < args.length
-    fail(messages.MockUsage) if args.length == 1 and not is_function(args[0])
-    fail(messages.MockUsage) if args.length == 2 and not is_function(args[1])
-    fail(messages.MockBadUsage) if args.length == 2 and not has_property(args[0], "expects_method_name") and not has_property(args[0], "mock_count")
-
-  _parse_args = (args) ->
-    test_function = ( if args.length == 1 then args[0] else args[1] )
-    expects_method_name = ( if args.length == 2 then args[0].expects_method_name ) ? "expects"    # TODO: use merge idiom?  what happens if expects_method_name is not a valid method name?
-    mock_count = ( if args.length == 2 then args[0].mock_count ) ? 5                              # TODO: what happens if mock_count is not a number?
-    [ expects_method_name, mock_count, test_function ]