Should fix #2

Should fix #2

--- lib/index.coffee
+++ lib/index.coffee
@@ -1,6 +1,7 @@
 Assert = require 'assert'
 FFI = require 'ffi'
 Net = require 'net'
+OS = require 'os'
 Ref = require 'ref'
 Util = require 'util'
 UV = null
@@ -14,9 +15,14 @@
 ## CONSTANTS
 SOL_TCP   = 6

-TCP_KEEPIDLE   = 4
-TCP_KEEPINTVL   = 5
-TCP_KEEPCNT     = 6
+if OS.platform() is 'darwin'
+  #TCP_KEEPIDLE    = 0x10 # Managed by libuv
+  TCP_KEEPINTVL   = 0x101
+  TCP_KEEPCNT     = 0x102
+else
+  #TCP_KEEPIDLE    = 4 # Managed by libuv
+  TCP_KEEPINTVL   = 5
+  TCP_KEEPCNT     = 6

 ## FFI Bindings
 bindings = FFI.Library null,


add comments, remove unneeded conditionals/deletes

--- lib/index.coffee
+++ lib/index.coffee
@@ -42,70 +42,121 @@
     unless @only?.length then @only = ['paths']

   on: (event, listener) ->
+    # handle some extra implied stuff based on adding listeners.
+    # if they add a done() listener, then process asynchronously.
+    # if they listen to events for a mode, add that mode to what we do.
     switch event
       when 'done'          then @async = true
       when 'file', 'files' then @only.push 'files'
       when 'dir',  'dirs'  then @only.push 'dirs'
       when 'path', 'paths' then @only.push 'paths'

+    # always perform the on() operation
     super event, listener

   run: (options, done) ->
+
+    # if they specified options, done, or both, then reconfigure
     if arguments.length > 0 then @_configure options, done
+
+    # there must be a `target` for us to start at
     unless @target? then throw new Error 'dirator requires a `target` to run'
+
+    # use two different processing styles based on the `async` setting
     if @async then @_iterate [new Path @target] else @_iterateSync()
+

   _iterateSync: ->
     # TODO:
     #  adapt to use emit to send them instead of gathering it all up into arrays
     #  only when there *are* listeners. otherwise, return all the arrays.
     #  combine ops as in node-paths ...?
+
+    # hold all results info in this as we do all the work
     results = found: {}, rejected: paths:0, strings:0
+
     emit = {}
+
+    # if these modes are enabled, then gather their stuff and counts
     for type in ['files', 'dirs', 'paths']
       if type in @only
         results[type] = []
         results.found[type] = 0

+    # begin at the target path.
+    # if it has directories, and `recurse` is on, then we'll add them to
+    # this array, and keep processing this until there aren't anymore.
     dirArray = [new Path @target]

+    # get configured filters
     options = acceptString:@_acceptString, acceptPath:@_acceptPath

+    # keep processing directories in the array until there aren't any more.
+    # when we find more directories we append them to the array
     while dirArray.length > 0
+
+      # process last dir so we continue down into a directory until there
+      # aren't anymore, then, we go back up to the dir which led us there
+      # and begin the next directory there.
+      # basically, this makes us traverse the directories in a sensible order
       dir = dirArray.pop()

+      # use dir's list() operation to see what we have in this dir
       result = dir.list options

+      # update `results` counts from this `result`
       results.rejected.paths   += result.rejected.paths
       results.rejected.strings += result.rejected.strings
-
+      # this one is conditional because we may not be tracking paths
       results.found.paths += result.paths.length if results.found?.paths?

+      # look at each path the list() op found
       for path in result.paths
+
+        # if we're tracking paths, then store each path
         results?.paths?.push path
+
+        # if it's a directory
         if path.isDir()
+
+          # update the count only if we're tracking directories
           results.found?.dirs += 1 if results.found?.dirs?
+
+          # only add this directory to our workload if `recurse` is on
           dirArray.push path if @recurse
+
+          # add directory to our results only if we're tracking them
           results?.dirs?.push path
+
+        # if it's a file then conditionally track the count and the file
         else if path.isFile()
           results.found?.files += 1 if results.found?.files?
           results?.files?.push path

+    # loop is complete, so, return all our results
     return results

+
   _iterate: (dirArray, options) ->
+
+    # won't have options the first time. later times provide it
+    # to keep the operation going
     unless options?
       options = @_buildAsyncOptions dirArray
       dirArray.options = options

+    # if there's another directory to iterate then pop() it and do a list() op
     if dirArray.length > 0
       dir = dirArray.pop()
       dir.list options.list # option actions take care of everything else
+
+    # all done, so, emit the event
     else @emit 'done', undefined, options.results

+
   _buildAsyncOptions: (dirArray) ->

-    action = {}  # holds temp arrays and *each* actions
+    action = {}  # holds temp arrays and actions

     # holds statistics for `done`
     results = found: {}, rejected: paths:0, strings:0
@@ -113,62 +164,90 @@
     list = # holds options to give to path.list()
       acceptString: @_acceptString
       acceptPath: @_acceptPath
+
       each: (result) => # these also increment the results.found values
-        action?.file? result
-        action?.dir?  result
-        action?.path? result
+
+        # call each actions with conditional '?' in case they don't exist
+        action.file? result
+        action.dir?  result
+        action.path? result
+
       all: (error, result) =>
+
         if error? then return @emit 'done', error, result
-        action?.files? result # action.files doesn't use result...pass anyway
-        action?.dirs?  result # action.dirs doesn't use result...pass anyway
-        action?.paths? result
+
+        # call each actions with conditional '?' in case they don't exist
+        action.files? result # action.files doesn't use result...pass anyway
+        action.dirs?  result # action.dirs doesn't use result...pass anyway
+        action.paths? result
+
         results.rejected.paths   += result.rejected.paths
         results.rejected.strings += result.rejected.strings
+
         # now call this again if @recurse
         if @recurse then @_iterate dirArray, dirArray.options
         else @emit 'done', undefined, results

+    # if the 'files' mode is active
     if 'files' in @only
+      # prep stuff to do file/files stuff
       action.tempFiles = []
       results.found.files = 0
-      action.file = (result) => if result.path.isFile()
-        action.tempFiles.push result.path
-        result.file = result.path
-        @emit 'file', result
-
+
+      # provide a 'file' action
+      action.file = (result) =>
+        if result.path.isFile()
+          action.tempFiles.push result.path
+          result.file = result.path
+          @emit 'file', result
+
+      # provide a 'files' action
       action.files = =>
         results.found.files += action.tempFiles.length
         @emit 'files', files:action.tempFiles
-        delete action.tempFiles
         action.tempFiles = []

+    # if the 'dirs' mode is active
     if 'dirs' in @only
+
       action.tempDirs = []
       results.found.dirs = 0
-      action.dir = (result) => if result.path.isDir()
-        if @recurse then dirArray.push result.path
-        action.tempDirs.push result.path
-        result.dir = result.path
-        @emit 'dir', result
-
+
+      # provide a 'dir' action
+      action.dir = (result) =>
+        if result.path.isDir()
+          if @recurse then dirArray.push result.path
+          action.tempDirs.push result.path
+          result.dir = result.path
+          @emit 'dir', result
+
+      # provide a 'dirs' action
       action.dirs = =>
         results.found.dirs += action.tempDirs.length
         @emit 'dirs', dirs:action.tempDirs
-        delete action.tempDirs
         action.tempDirs = []

+    # if `recurse` is on then provide a 'dir' action, not because
+    # they want each dir, but to add new dirs to traverse into
     else if @recurse
       action.dir = (result) ->
         if result.path.isDir() then dirArray.push result.path

+    # if the 'paths' mode is active
     if 'paths' in @only
+
       results.found.paths = 0
-      action.path  = (result) =>  @emit 'path', result
+
+      # provide a 'path' action (we're only emitting, so, bind it)
+      action.path = @emit.bind this, 'path'
+
+      # provide a 'paths' action
       action.paths = (result) =>
         results.found.paths += result.paths.length
         @emit 'paths', result

     return action:action, results:results, list:list # return options object
+

 # Use three ways:
 #  1. Dirator = require('dirator').Dirator
@@ -177,6 +256,11 @@
 #  3. require('dirator')(options)
 module.exports = (args...) -> new Dirator(args...).run()
 module.exports.Dirator = Dirator
+
+# Provide convenience functions prebuilt with mode:
+#   dirator.files()
+#   dirator.dirs()
+#   dirator.paths()
 for type in ['files', 'dirs', 'paths']
   do (type) ->
     module.exports[type] = (options = {}, done) ->


pass things to callbacks instead of outer result object, replace push with assign, revise various parts

--- lib/index.coffee
+++ lib/index.coffee
@@ -21,20 +21,20 @@
     for event in ['file', 'dir', 'path']
       if options[event]?
         @on event, options[event]
-        @only.push event + 's'
+        @only[@only.length] = event + 's'

     # add the array callbacks, when specfied. add the type to `only`
     for event in ['files', 'dirs', 'paths']
       if options[event]?
         @on event, options[event]
-        if event not in @only then @only.push event
+        if event not in @only then @only[@only.length] = event

     # store both accept filters provided (when not provided, they become undefined)
     for accept in ['acceptString', 'acceptPath']
       @['_' + accept] = options[accept]

     # always recurse unless options specify *not* to
-    if options.recurse isnt false then @recurse = true
+    @recurse = options.recurse isnt false

     # override `only` settings from events when `only` is explicitly set in options
     if options.only? then @only = options.only
@@ -47,9 +47,9 @@
     # if they listen to events for a mode, add that mode to what we do.
     switch event
       when 'done'          then @async = true
-      when 'file', 'files' then @only.push 'files'
-      when 'dir',  'dirs'  then @only.push 'dirs'
-      when 'path', 'paths' then @only.push 'paths'
+      when 'file', 'files' then @only[@only.length] = 'files'
+      when 'dir',  'dirs'  then @only[@only.length] = 'dirs'
+      when 'path', 'paths' then @only[@only.length] = 'paths'

     # always perform the on() operation
     super event, listener
@@ -57,7 +57,7 @@
   run: (options, done) ->

     # if they specified options, done, or both, then reconfigure
-    if arguments.length > 0 then @_configure options, done
+    if options? or done? then @_configure options, done

     # there must be a `target` for us to start at
     unless @target? then throw new Error 'dirator requires a `target` to run'
@@ -70,7 +70,6 @@
     # TODO:
     #  adapt to use emit to send them instead of gathering it all up into arrays
     #  only when there *are* listeners. otherwise, return all the arrays.
-    #  combine ops as in node-paths ...?

     # hold all results info in this as we do all the work
     results = found: {}, rejected: paths:0, strings:0
@@ -123,7 +122,7 @@
           results.found?.dirs += 1 if results.found?.dirs?

           # only add this directory to our workload if `recurse` is on
-          dirArray.push path if @recurse
+          dirArray[dirArray.length] = path if @recurse

           # add directory to our results only if we're tracking them
           results?.dirs?.push path
@@ -165,14 +164,14 @@
       acceptString: @_acceptString
       acceptPath: @_acceptPath

-      each: (result) => # these also increment the results.found values
+      each: (result) -> # these also increment the results.found values

         # call each actions with conditional '?' in case they don't exist
         action.file? result
         action.dir?  result
         action.path? result

-      all: (error, result) =>
+      done: (error, result) =>

         if error? then return @emit 'done', error, result

@@ -196,15 +195,16 @@

       # provide a 'file' action
       action.file = (result) =>
-        if result.path.isFile()
-          action.tempFiles.push result.path
-          result.file = result.path
-          @emit 'file', result
+        path = result.path
+        if path.isFile()
+          action.tempFiles[action.tempFiles.length] = path
+          # result.file = path
+          @emit 'file', path

       # provide a 'files' action
       action.files = =>
         results.found.files += action.tempFiles.length
-        @emit 'files', files:action.tempFiles
+        @emit 'files', action.tempFiles
         action.tempFiles = []

     # if the 'dirs' mode is active
@@ -215,38 +215,39 @@

       # provide a 'dir' action
       action.dir = (result) =>
-        if result.path.isDir()
-          if @recurse then dirArray.push result.path
-          action.tempDirs.push result.path
-          result.dir = result.path
-          @emit 'dir', result
+        path = result.path
+        if path.isDir()
+          if @recurse then dirArray[dirArray.length] = path
+          action.tempDirs[action.tempDirs.length] = path
+          result.dir = path
+          @emit 'dir', path

       # provide a 'dirs' action
       action.dirs = =>
         results.found.dirs += action.tempDirs.length
-        @emit 'dirs', dirs:action.tempDirs
+        @emit 'dirs', action.tempDirs
         action.tempDirs = []

     # if `recurse` is on then provide a 'dir' action, not because
     # they want each dir, but to add new dirs to traverse into
     else if @recurse
       action.dir = (result) ->
-        if result.path.isDir() then dirArray.push result.path
+        if result.path.isDir() then dirArray[dirArray.length] = result.path

     # if the 'paths' mode is active
     if 'paths' in @only

       results.found.paths = 0

-      # provide a 'path' action (we're only emitting, so, bind it)
-      action.path = @emit.bind this, 'path'
+      # provide a 'path' action
+      action.path = (result) =>  @emit 'path', result.path

       # provide a 'paths' action
       action.paths = (result) =>
         results.found.paths += result.paths.length
-        @emit 'paths', result
-
-    return action:action, results:results, list:list # return options object
+        @emit 'paths', result.paths
+
+    return { action, results, list } # return options object

 # Use three ways:
@@ -254,7 +255,7 @@
 #  2. dirator = require('dirator')
 #     dirator options
 #  3. require('dirator')(options)
-module.exports = (args...) -> new Dirator(args...).run()
+module.exports = (options, done) -> new Dirator(options, done).run()
 module.exports.Dirator = Dirator

 # Provide convenience functions prebuilt with mode:


change opts to params to avoid module level conflict

--- lib/index.coffee
+++ lib/index.coffee
@@ -158,8 +158,8 @@
      * @return {String} - URL string for the asset
     ###

-    asset_view_helper = (asset = {}, opts) ->
+    asset_view_helper = (asset = {}, params) ->
       asset.fields ?= {}
       asset.fields.file ?= {}
       url = asset.fields.file.url
-      if opts then "#{url}?#{querystring.stringify(opts)}" else url
+      if params then "#{url}?#{querystring.stringify(params)}" else url


reviewed style

reviewed style

--- lib/index.coffee
+++ lib/index.coffee
@@ -1,17 +1,17 @@
 'use strict'

-Args             = require 'args-js'
-parallel         = require 'run-parallel'
-childProcess     = require 'child_process'
-spawn            = require('child_process').spawn
+Args         = require 'args-js'
+parallel     = require 'run-parallel'
+childProcess = require 'child_process'
+spawn        = childProcess.spawn
 # the library uses native use native child_process.execSync if available (from node v0.12+)
-execSync         = require 'sync-exec'
+execSync     = require 'sync-exec'
 # the library on iojs and node >= 0.12 it will just export the built in child_process.spawnSync
-spawnSync        = require 'spawn-sync'
+spawnSync    = require 'spawn-sync'

 exec = (cmd, opts, cb) ->
   childProcess.exec cmd, opts, (err, stdout, stderr) ->
-    cb err, { stdout: stdout, stderr: stderr}
+    cb err, {stdout: stdout, stderr: stderr}

 module.exports = class Terminal


defining given ... finally!!! almost there i swear :)

--- js/cs/test/spec/given_spec.coffee
+++ js/cs/test/spec/given_spec.coffee
@@ -1,10 +1,12 @@
+should = require 'should'
+
 describe 'Given', ->
 # It's got 2 uses static/dynamic
-# static: builds up the chain of events
+# static: builds up the chain of corals
 # dynamic: used to keep temp/helper info

   describe 'Static', ->
-  # It's used to append events
+  # appends to corals
   # does not lead to a conclusion
   # just appends to the events

@@ -44,4 +46,15 @@

       sut.corals.should.eql [4, 42, 420, 42, true, 'that']

-  describe 'Helpers (dynamic given)', ->+  describe 'Dynamic', ->
+  # builds up temp info during then()
+  # it becomes part of this but not of value
+  # use to extract methods/calculations
+  # it obey's the when rules
+  # precedes then()
+
+    it 'value', ->
+
+      sut = corals given: alive: true
+      should.not.exist sut.then().alive
+      sut.alive.should.be.true()


don't test creating contexts in node

don't test creating contexts in node

--- test/context.coffee
+++ test/context.coffee
@@ -1,6 +1,8 @@
 define (require) ->
   expect = require 'expect'
   context = require 'context'
+
+  in_browser = (it) -> if window? then it else it.skip

   later = (done, fn) ->
     try
@@ -11,7 +13,7 @@

   describe 'contexts', ->
     describe 'base contexts', ->
-      it 'can be created', (done) ->
+      in_browser(it) 'can be created', (done) ->
         context.create_base_context(imports: ['builtins'])
         .then(-> done())
         .fail done
@@ -27,7 +29,7 @@
         $el = context.render run_context
         expect($el.text()).to.be html

-    describe 'full contexts', ->
+    in_browser(describe) 'full contexts', ->
       ctx = null
       complete_callback = null
       on_complete = (fn, done) ->


Extraneous newline.

Extraneous newline.

--- lib/setup.coffee
+++ lib/setup.coffee
@@ -91,7 +91,6 @@
   app.use ensureSSL
   app.use hstsMiddleware

-
   # Increase max sockets. The goal of this is to improve app -> api
   # performance but the downside is it limits client connection reuse with keep-alive
   if typeof MAX_SOCKETS == 'number' and MAX_SOCKETS > 0


update sub nav

update sub nav

--- sub-nav.coffee
+++ sub-nav.coffee
@@ -1,5 +1,5 @@
 ###
-Secondary Page SubNav Usage
+Secondary Page SubNav Usage : readymade

 1. Create a nav with class="sub-nav-PAGE_NAME"
     ex: "science", "education"
@@ -9,21 +9,33 @@

 3. Add content sections with class="sub-nav-PAGE_NAME-SECTION_NAME"

-4. The first child button and content section will be the default active
+4. Name the Readymade page PAGE_NAME
 ###

 class SubNav
-  constructor: (pageName) -> @createSubNav(pageName)
+  constructor: (@page) ->
+    @el = $(".readymade-generic-page[data-readymade-page='#{@page}']")
+    setTimeout => @activateFirstTab(page)

-  createSubNav: (pageName) ->
-    setTimeout =>
-      initialPageBtn = $(".sub-nav-#{pageName} button:nth-child(1)").addClass("active")
-      initialClassName = initialPageBtn.attr('name')
+    @el.find(".sub-nav-#{page} button").on "click", (e) =>
+      @activateSection(e.target.name)

-      $(".sub-nav-#{pageName}-#{initialClassName}:nth-child(1)").siblings().hide()
+  showSection: (section) ->
+    @el.find(".sub-nav-#{@page}-#{section}")
+      .show()
+      .siblings().hide()

-      $(".sub-nav-#{pageName} button").on "click", (e) =>
-        $(".sub-nav-#{pageName}-#{e.target.name}").show().siblings().hide()
-        $(".sub-nav-#{pageName} button[name=#{e.target.name}]").addClass("active").siblings().removeClass("active")
+  activateSubNavLink: (section) ->
+    @el.find(".sub-nav-#{@page} button[name=#{section}]")
+      .addClass("active")
+      .siblings().removeClass("active")
+
+  activateFirstTab: ->
+     firstSection = $(".sub-nav-#{@page} button:nth-child(1)").attr('name')
+     @activateSection(firstSection)
+
+  activateSection: (section) ->
+    @showSection(section)
+    @activateSubNavLink(section)

 module?.exports = SubNav


Refactor Player spec with de-structuring.

--- tests/player.coffee
+++ tests/player.coffee
@@ -5,7 +5,10 @@
   'test/fakes'
 ], (Phaser, _, Player, fakes) ->

+  {Direction} = Player
+
   describe 'Player', ->
+    cursors = null
     game = null
     player = null

@@ -23,13 +26,15 @@
       player._initPhysics()
       player._initState()

+      {cursors} = player
+
     endAnimation = ->
       player.animation.isPlaying = no
       player.animation.isFinished = yes

     initialYAcceleration = null
     runJumpUpdatesUntil = (stopAt) ->
-      player.cursors.up.isDown = yes
+      cursors.up.isDown = yes
       initialYAcceleration = player.acceleration.y
       player.update()
       return if stopAt is 'rising'
@@ -37,8 +42,8 @@
       player.update()
       return if stopAt is 'building'

-      player.cursors.up.isDown = no
-      player.cursors.up.isUp = yes
+      cursors.up.isDown = no
+      cursors.up.isUp = yes
       player.velocity.y = 1
       player.update() # End jump.
       player.update() # Fall.
@@ -50,8 +55,8 @@

     runRunUpdatesUntil = (stopAt, options) ->
       if options?.backwards and not (stopAt in ['turn', 'restart'])
-        player.cursors.left.isDown = yes
-      else player.cursors.right.isDown = yes
+        cursors.left.isDown = yes
+      else cursors.right.isDown = yes

       player.update()
       return if stopAt is 'start'
@@ -62,8 +67,8 @@

       unless options?.backwards
         player.velocity.x = 1
-        player.cursors.right.isDown = no
-        player.cursors.right.isUp = yes
+        cursors.right.isDown = no
+        cursors.right.isUp = yes
         player.update()
         return if stopAt is 'stop'

@@ -71,8 +76,8 @@
         player.update()
         return if stopAt is 'still'

-      player.cursors.right.isDown = no
-      player.cursors.left.isDown = yes
+      cursors.right.isDown = no
+      cursors.left.isDown = yes
       player.update()
       return if stopAt is 'turn'

@@ -94,7 +99,7 @@
       it 'is set to still and facing right', ->
         expect(player.state).toBe 'still'
         expect(player._isFullyStill()).toBe yes
-        expect(player.direction).toBe Player.Direction.Right
+        expect(player.direction).toBe Direction.Right
         expect(player.animation).toBeNull()

       it 'has no next state info', ->
@@ -106,8 +111,8 @@
       it 'can get and set the right direction from #_xDirectionInput', ->
         runRunUpdatesUntil 'start'

-        expect(player._xDirectionInput()).toBe Player.Direction.Right
-        expect(player.nextDirection).toBe Player.Direction.Right
+        expect(player._xDirectionInput()).toBe Direction.Right
+        expect(player.nextDirection).toBe Direction.Right

       describe 'when still', ->
         beforeEach -> runRunUpdatesUntil 'start'
@@ -161,15 +166,15 @@
       it 'can get and set the right direction from #_xDirectionInput', ->
         runRunUpdatesUntil 'start', backwards: yes

-        expect(player._xDirectionInput()).toBe Player.Direction.Left
-        expect(player.nextDirection).toBe Player.Direction.Left
+        expect(player._xDirectionInput()).toBe Direction.Left
+        expect(player.nextDirection).toBe Direction.Left

       describe 'when still', ->
         beforeEach -> runRunUpdatesUntil 'start', backwards: yes

         it 'will immediately (end) turn and begin to run', ->
           expect(player._isTurning).toBe yes
-          expect(player.direction).toBe Player.Direction.Left
+          expect(player.direction).toBe Direction.Left
           expect(player._beginRun).toHaveBeenCalled()

         it 'will play start animation', testStartAnimation


fixing typo

fixing typo

--- test/aggregate.coffee
+++ test/aggregate.coffee
@@ -121,7 +121,7 @@
             #   nycBlyeEyedGrouping = (averagesByCityThenEyeColor.filter (averageObject)

 #                       it 'should look like this', ->
-#             expect(JSON.stringify(averagesByCity, null,4)).to.equal("""
+#             expect(JSON.stringify(averagesByCityThenEyeColor, null,4)).to.equal("""
 # [
 #     {
 #         "key": "nyc",


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/collision.coffee
+++ test/collision.coffee
@@ -47,7 +47,7 @@
   Collision.collide player, [enemy, enemy2], (p, e) ->
     ok(true)

-test "Collision.rayRec", ->
+test "Collision.rayRectangle", ->

 module()


comments

comments

--- client/src/index.coffee
+++ client/src/index.coffee
@@ -3,13 +3,11 @@

 SideBar = require './sidebar.coffee'
 MyMap = require './mymap.coffee'
-
+# API CONFIGURATION -> backended -> homedata: @props.homedata
 backend = require './backend.coffee'

-# 'api/configuration'
-#
 # 'api/placesdata'
 geoPlaces =

@@ -21,6 +19,7 @@
                 callback err, res.body

+
 App = React.createClass

     render: ->
@@ -30,6 +29,7 @@
             MyMap

+
 backend.getConfig (err, config) ->

     data =
@@ -37,4 +37,3 @@

     React.render(React.createElement(App, data),
                  document.getElementById('app'))
-


don't need that anymore

don't need that anymore

--- lib/atom-ternjs.coffee
+++ lib/atom-ternjs.coffee
@@ -9,7 +9,6 @@
   grammars: ['JavaScript']
   client: null
   documentationView: null
-  activeTextEditor: null

   # autocomplete-plus
   registration: null


Remove unuseful parenthesis

Remove unuseful parenthesis

--- text-fade-in.coffee
+++ text-fade-in.coffee
@@ -32,9 +32,9 @@
   replace = (element, text, sequence) ->
     index     = sequence.shift()
     prev_text = getText element
-    character = text.charAt(index)
+    character = text.charAt index

-    setText element, "#{prev_text.substr(0, index)}#{character}#{prev_text.substr(index+character.length)}"
+    setText element, "#{prev_text.substr 0, index}#{character}#{prev_text.substr index+character.length}"

   # References: Sizzle.getText
   getText = (element) ->


Query hits the correct endpoint

Query hits the correct endpoint

--- SingularityUI/app/collections/TaskSearchResults.coffee
+++ SingularityUI/app/collections/TaskSearchResults.coffee
@@ -10,8 +10,8 @@
         return $.param(_.pick(@params, _.identity))

     url: ->
-        if @requestId
-            return "#{ config.apiRoot }/history/request/#{ @requestId }/tasks?#{ @getQueryParams() }"
+        if @params.requestId
+            return "#{ config.apiRoot }/history/request/#{ @params.requestId }/tasks?#{ @getQueryParams() }"
         else
             return "#{ config.apiRoot }/history/tasks?#{ @getQueryParams() }"


add hit functionality to character

add hit functionality to character

--- coffee/character.coffee
+++ coffee/character.coffee
@@ -24,4 +24,7 @@
         when @size > 9 then 2
         else 3

+    hitFor: (damage) ->
+      @health = @health - damage
+
   return Character


Cache Textarea Selectors

Cache Textarea Selectors

--- coffeescript/app.coffee
+++ coffeescript/app.coffee
@@ -215,66 +215,69 @@
 		path.join(window.noted.storagedir, "Notebooks", newfile)

 	editorAction: (action) ->
+		# I'm sure that mh0 doesn't know how to code.
+		# Cache Selector
+		$area = $('#contentwrite textarea')
+		sel = $area.getSelection()
+
 		if action is 'bold'
-			sel = $('#contentwrite textarea').getSelection()
-			$('#contentwrite textarea').setSelection(sel.start - 2, sel.end + 2) # Surround the "**".
-			newsel = $('#contentwrite textarea').getSelection()
+			$area.setSelection(sel.start - 2, sel.end + 2) # Surround the "**".
+			newsel = $area.getSelection()
 			if S(newsel.text).endsWith("**") and S(newsel.text).startsWith("**")
-				$('#contentwrite textarea').deleteText(newsel.start, newsel.start+2)
-				$('#contentwrite textarea').deleteText(newsel.end-4, newsel.end-2)
-				$('#contentwrite textarea').setSelection(sel.start-2, sel.end-2)
+				$area.deleteText(newsel.start, newsel.start+2)
+				$area.deleteText(newsel.end-4, newsel.end-2)
+				$area.setSelection(sel.start-2, sel.end-2)
 			else
-				$('#contentwrite textarea').setSelection(sel.start, sel.end)
-				$('#contentwrite textarea').surroundSelectedText("**","**")
+				$area.setSelection(sel.start, sel.end)
+				$area.surroundSelectedText("**","**")
+
 		else if action is 'italics'
-			sel = $('#contentwrite textarea').getSelection()
-			$('#contentwrite textarea').setSelection(sel.start - 1, sel.end + 1) # Surround the "**".
-			newsel = $('#contentwrite textarea').getSelection()
+			$area.setSelection(sel.start - 1, sel.end + 1) # Surround the "**".
+			newsel = $area.getSelection()
 			if S(newsel.text).endsWith("*") and S(newsel.text).startsWith("*")
-				$('#contentwrite textarea').deleteText(newsel.start, newsel.start+1)
-				$('#contentwrite textarea').deleteText(newsel.end-2, newsel.end-1)
-				$('#contentwrite textarea').setSelection(sel.start-1, sel.end-1)
+				$area.deleteText(newsel.start, newsel.start+1)
+				$area.deleteText(newsel.end-2, newsel.end-1)
+				$area.setSelection(sel.start-1, sel.end-1)
 			else
-				$('#contentwrite textarea').setSelection(sel.start, sel.end)
-				$('#contentwrite textarea').surroundSelectedText("*","*")
+				$area.setSelection(sel.start, sel.end)
+				$area.surroundSelectedText("*","*")
+
 		else if action is 'hyperlink'
-			url = prompt("Enter the URLof the hyperlink","")
-			$('#contentwrite textarea').surroundSelectedText("[","]("+url+")")
+			url = prompt("Enter the URL of the hyperlink","")
+			$area.surroundSelectedText("[","]("+url+")")
+
 		else if action is 'heading'
-			sel = $('#contentwrite textarea').getSelection()
-			$('#contentwrite textarea').setSelection(sel.start - 2, sel.end) # Surround the "**".
-			newsel1 = $('#contentwrite textarea').getSelection()
-			$('#contentwrite textarea').setSelection(sel.start - 3, sel.end) # Surround the "**".
-			newsel2 = $('#contentwrite textarea').getSelection()
-			$('#contentwrite textarea').setSelection(sel.start - 4, sel.end) # Surround the "**".
-			newsel3 = $('#contentwrite textarea').getSelection()
-			console.log S(newsel1.text).startsWith("# ")
-			console.log S(newsel2.text).startsWith("## ")
-			console.log S(newsel3.text).startsWith("### ")
+			$area.setSelection(sel.start - 2, sel.end) # Surround the "**".
+			newsel1 = $area.getSelection()
+			$area.setSelection(sel.start - 3, sel.end) # Surround the "**".
+			newsel2 = $area.getSelection()
+			$area.setSelection(sel.start - 4, sel.end) # Surround the "**".
+			newsel3 = $area.getSelection()
+
 			if S(newsel3.text).startsWith("### ")
-				console.log("h0")
-				$('#contentwrite textarea').deleteText(newsel3.start, newsel3.start+4)
-				$('#contentwrite textarea').setSelection(sel.start-4, sel.end-4)
+				$area.deleteText(newsel3.start, newsel3.start+4)
+				$area.setSelection(sel.start-4, sel.end-4)
+
 			else if S(newsel2.text).startsWith("## ")
-				console.log("h3")
-				$('#contentwrite textarea').deleteText(newsel2.start, newsel2.start+3)
-				$('#contentwrite textarea').setSelection(sel.start-3, sel.end-3)
-				$('#contentwrite textarea').surroundSelectedText("### ","")
+				$area.deleteText(newsel2.start, newsel2.start+3)
+				$area.setSelection(sel.start-3, sel.end-3)
+				$area.surroundSelectedText("### ","")
+
 			else if S(newsel1.text).startsWith("# ")
-				console.log("h2")
-				$('#contentwrite textarea').deleteText(newsel1.start, newsel1.start+2)
-				$('#contentwrite textarea').setSelection(sel.start-2, sel.end-2)
-				$('#contentwrite textarea').surroundSelectedText("## ","")
+				$area.deleteText(newsel1.start, newsel1.start+2)
+				$area.setSelection(sel.start-2, sel.end-2)
+				$area.surroundSelectedText("## ","")
+
 			else
-				console.log("h1")
-				$('#contentwrite textarea').setSelection(sel.start, sel.end)
-				$('#contentwrite textarea').surroundSelectedText("# ","")
+				$area.setSelection(sel.start, sel.end)
+				$area.surroundSelectedText("# ","")
+
 		else if action is 'hr'
-			$('#contentwrite textarea').surroundSelectedText("----\n","")
+			$area.surroundSelectedText("----\n","")
+
 		else if action is 'img'
 			url = prompt("Enter the URL of the image","")
-			$('#contentwrite textarea').surroundSelectedText("![","]("+url+")")
-
+			$area.surroundSelectedText("![","]("+url+")")

 	deselect: ->
 		$("#content").addClass("deselected")


useless semicolon

useless semicolon

--- app/assets/js/app.coffee
+++ app/assets/js/app.coffee
@@ -31,7 +31,7 @@
 App.MonitorController = Ember.ArrayController.extend

   init: ->
-    me = this;
+    me = this
     this.set 'content', []

     this.pushObject


remove previous stack log call

remove previous stack log call

--- testify.coffee
+++ testify.coffee
@@ -238,7 +238,6 @@
         line = indent + "#{test.name} ( #{test.failed} )".red
       else
         line = indent + "#{test.name} ( #{test.failed} )".yellow
-        console.log test.failed.stack
       console.log(line)
       if test.failed?.stack
         where = test.failed.stack.split("\n")[1]


:new: Add LinterPlus::onDidChangeProjectMessages

--- lib/linter-plus.coffee
+++ lib/linter-plus.coffee
@@ -65,14 +65,19 @@
   getLinters: ->
     @_linters

+  onDidChangeProjectMessages: (callback)->
+    @_emitter.on 'did-change-project-messages', callback
+
   getProjectMessages: ->
     @_messagesProject

   setProjectMessages: (linter, messages) ->
     @_messagesProject.set(linter, Helpers.validateResults(messages))
+    @_emitter.emit 'did-change-project-messages', @_messagesProject

   deleteProjectMessages: (linter) ->
     @_messagesProject.delete(linter)
+    @_emitter.emit 'did-change-project-messages', @_messagesProject

   getActiveEditorLinter: ->
     return @getEditorLinter atom.workspace.getActiveTextEditor()


Fixes for text justification

Fixes for text justification

--- lib/mixins/text.coffee
+++ lib/mixins/text.coffee
@@ -171,9 +171,10 @@

         when 'justify'
           # calculate the word spacing value
+          words = text.trim().split(/\s+/)
           textWidth = @widthOfString(text.replace(/\s+/g, ''), options)
           spaceWidth = @widthOfString(' ') + characterSpacing
-          wordSpacing = Math.max 0, (options.lineWidth - textWidth) / Math.max(1, options.wordCount - 1) - spaceWidth
+          wordSpacing = Math.max 0, (options.lineWidth - textWidth) / Math.max(1, words.length - 1) - spaceWidth

     # calculate the actual rendered width of the string after word and character spacing
     renderedWidth = options.textWidth + (wordSpacing * (options.wordCount - 1)) + (characterSpacing * (text.length - 1))
@@ -231,7 +232,7 @@
     # since the normal Tw operator only works on character code 32, which isn't
     # used for embedded fonts.
     if wordSpacing
-      words = text.split(/\s+/)
+      words = text.trim().split(/\s+/)
       wordSpacing += @widthOfString(' ') + characterSpacing
       wordSpacing *= 1000 / @_fontSize


Update preferences.coffee

Update preferences.coffee

--- lib/preferences.coffee
+++ lib/preferences.coffee
@@ -6,8 +6,11 @@
   @localize: (defS) ->
     @defS = defS
     @updateSettings()
-    atom.commands.add 'atom-workspace', 'settings-view:open', =>
-      @updateSettings(true)
+    atom.workspace.onDidChangeActivePaneItem (item) =>
+        if item isnt undefined
+          if item.uri isnt undefined
+            if item.uri.indexOf('atom://config') isnt -1
+              @updateSettings(true)

   @updateSettings: (onSettingsOpen = false) ->
     setTimeout(@delaySettings, 0, onSettingsOpen)


fixed up touch methods

fixed up touch methods

--- oridomi.coffee
+++ oridomi.coffee
@@ -738,13 +738,13 @@
     # Set a property to track touch starts.
     @_touchStarted = true
     # Change the cursor to the active `grabbing` state.
-    @stageEl.style.cursor = css.grabbing
+    @stageHolder.style.cursor = css.grabbing
     # Disable tweening to enable instant 1 to 1 movement.
     @_setTweening false
     # Derive the axis to fold on.
     @_touchAxis = if @lastOp.anchor is 'left' or @lastOp.anchor is 'right' then 'x' else 'y'
     # Set a reference to the last folded angle to accurately derive deltas.
-    @["_#{ @_touchAxis }Last"] = @lastAngle
+    @["_#{ @_touchAxis }Last"] = @lastOp.angle

     # Determine the starting tap's coordinate for touch and mouse events.
     if e.type is 'mousedown'
@@ -784,8 +784,11 @@
         delta = @["_#{ @_touchAxis }Last"] - distance
       delta = 0 if delta < 0

+
+    delta = @_normalizeAngle delta
+    @lastOp.angle = delta
     # Invoke the effect method with the delta as an angle argument.
-    @[@lastOp.method] delta, @lastAnchor, @lastOp.options
+    @lastOp.fn.call @, delta, @lastOp.anchor, @lastOp.options
     # Pass the delta to the movement callback.
     @settings.touchMoveCallback delta

@@ -794,8 +797,8 @@
   _onTouchEnd: =>
     return unless @_touchEnabled
     # Restore the initial touch status and cursor.
-    @_touchStarted = false
-    @stageEl.style.cursor = css.grab
+    @_touchStarted = @_inTrans = false
+    @stageHolder.style.cursor = css.grab
     # Enable tweening again.
     @_setTweening true
     # Pass callback final value.


create animation queue

create animation queue

--- oridomi.coffee
+++ oridomi.coffee
@@ -212,6 +212,8 @@

     # Extend any passed options with the defaults map.
     @settings = extendObj options, defaults
+    # Create an array to act as an animation queue.
+    @_queue = []

     # Clone the target element and save a copy of it.
     @cleanEl = @el.cloneNode true


Adds tomdoc documentation to view management mixin

--- lib/mixins/view-management.coffee
+++ lib/mixins/view-management.coffee
@@ -4,23 +4,49 @@
 # Public: Provides methods to manage minimap views per pane.
 module.exports =
 class ViewManagement extends Mixin
-  # We'll be storing each MinimapView using the id of their PaneView
+  # Internal: Stores each MinimapView using the id of their PaneView
   minimapViews: {}

+  # Public: Updates all views currently in use.
   updateAllViews: ->
     view.onScrollViewResized() for id,view of @minimapViews

+  # Public: Returns the {MinimapView} object associated to the pane containing
+  # the passed-in {EditorView}.
+  #
+  # editorView - An {EditorView} instance
+  #
+  # Returns the {MinimapView} object associated to the pane containing
+  # the passed-in {EditorView}.
   minimapForEditorView: (editorView) ->
     @minimapForPaneView(editorView.getPane())

+  # Public: Returns the {MinimapView} object associated to the passed-in
+  # {PaneView} object.
+  #
+  # paneView - A {PaneView} instance
+  #
+  # Returns the {MinimapView} object associated to the passed-in
+  # {PaneView} object.
   minimapForPaneView: (paneView) -> @minimapForPane(paneView.model)
+
+  # Public: Returns the {MinimapView} object associated to the passed-in
+  # {Pane} object.
+  #
+  # pane - A {Pane} instance
+  #
+  # Returns the {MinimapView} object associated to the passed-in
+  # {Pane} object.
   minimapForPane: (pane) -> @minimapViews[pane.id]

+  # Internal: Destroys all views currently in use.
   destroyViews: ->
     view.destroy() for id, view of @minimapViews
     @eachPaneViewSubscription.off()
     @minimapViews = {}

+  # Internal: Registers to each pane view existing or to be created and creates
+  # a {MinimapView} instance for each.
   createViews: ->
     # When toggled we'll look for each existing and future pane thanks to
     # the `eachPaneView` method. It returns a subscription object so we'll


Added log

Added log

--- toggler.coffee
+++ toggler.coffee
@@ -58,8 +58,8 @@
     Promise.all(readHandled).then (->
     ), (err)->
       console.log 'Error checking status', err
-
   , 10
+  console.log 'Setup'

 process.on 'SIGINT', ->
   console.log 'Cleaning up..'


Fix minor syntax mistake

Fix minor syntax mistake

--- library/membrane/preflight.coffee
+++ library/membrane/preflight.coffee
@@ -44,7 +44,7 @@
 # This abstract base class service is an extension of the Screenplay
 # family that does some further environment initialization and set
 # up. These preparations will be nececessary no matter what sort of
-# Screebplay functionality you are going to implement. Currently the
+# Screenplay functionality you are going to implement. Currently the
 # purpose of preflight is drawing in the remoted and Bower packages.
 module.exports.Preflight = class Preflight extends BowerSupport


clean

clean

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -16,5 +16,3 @@
   "go-plus":
     goPath: "~/Code/Go"
   "go-rename": {}
-  "exception-reporting":
-    userId: "530fe4e8-e289-0bd7-1eb5-b30825e2445d"


Config updates

Config updates

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,9 +1,8 @@
-'global':
+'*':
   'editor':
-    'showIndentGuide': true
     'fontFamily': 'Monaco'
     'fontSize': 14
-    'invisibles': {}
+    'showIndentGuide': true
   'core':
     'ignoredNames': [
       '.bundle'
@@ -13,16 +12,15 @@
       'tmp'
       '.tmp'
     ]
-    'hideGitIgnoredFiles': true
     'disabledPackages': [
       'exception-reporting'
       'metrics'
     ]
-    'projectHome': '~/Code'
     'themes': [
       'seti-ui'
       'base16-tomorrow-dark-theme'
     ]
+    'projectHome': '~/Code'
   'spell-check':
     'grammars': [
       'text.plain'
@@ -35,3 +33,4 @@
     'viewedVersion': '0.89.0'
   'autocomplete-plus':
     'autoActivationDelay': 1
+  'linter': {}


Update to atom config

Update to atom config

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -25,9 +25,9 @@
     invisibles: {}
     showIndentGuide: true
     showInvisibles: true
+    softWrapAtPreferredLineLength: false
     tabLength: 4
     tabType: "soft"
-    softWrapAtPreferredLineLength: false
   "release-notes":
     viewedVersion: "0.89.0"
   "spell-check":


further reduce predecence levels.

further reduce predecence levels.

--- src/grammar.coffee
+++ src/grammar.coffee
@@ -570,9 +570,9 @@
   ["left",      '.']
   ["nonassoc",  'INDENT', 'OUTDENT']
   ["right",     '=', ':', 'COMPOUND_ASSIGN', 'RETURN']
-  ["right",     'WHEN', 'LEADING_WHEN', 'FORIN', 'FOROF', 'FROM', 'TO', 'BY', 'THROW']
-  ["right",     'IF', 'UNLESS', 'POST_IF', 'POST_UNLESS', 'ELSE', 'FOR', 'WHILE',
-                'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'EXTENDS']
+  ["right",     'WHEN', 'LEADING_WHEN', 'FORIN', 'FOROF', 'FROM', 'TO', 'BY',
+                'THROW', 'IF', 'UNLESS', 'POST_IF', 'POST_UNLESS', 'ELSE',
+                'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'EXTENDS']
 ]

 # Wrapping Up


fancier strings

fancier strings

--- src/grammar.coffee
+++ src/grammar.coffee
@@ -291,8 +291,11 @@
   ]

   Literal: [
+    o 'String',                                          -> new LiteralValue($1)
     o 'LITERAL',                                          -> new LiteralValue($1)
+    o 'Literal DOT String',                              -> new LiteralValue($1, $3)
     o 'Literal DOT LITERAL',                              -> new LiteralValue($1, $3)
+    o 'Literal DOT STAR',                              -> new LiteralValue($1, $3)
   ]

   Function: [


manager: Default runtime type to msgflo

manager: Default runtime type to msgflo

For cases where the runtime type is not set, especially
.fbp files which currently do not parse it. Ref noflo/fbp#33

--- src/manager.coffee
+++ src/manager.coffee
@@ -34,6 +34,7 @@

   start: (callback) ->
     runtime = @graph.properties?.environment?.runtime
+    runtime = 'msgflo' if not runtime
     return callback null if runtime != 'msgflo' # no-op

     startProcesses @library, @address, runtime, @graph.processes, (err, parts) =>


Handle new neovim UI events.

Handle new neovim UI events.

Replace cursor_{on,off} by busy_{stop,start}. Change done in:
neovim/neovim@c546875daf36936b9a6c0886a71c9edd1fdae6db

--- src/nvim/ui.coffee
+++ src/nvim/ui.coffee
@@ -211,13 +211,14 @@

   nv_bell: -> shell.beep()

+  nv_busy_start: -> @cursor.style.display = 'none'
+  nv_busy_stop: -> @cursor.style.display = 'block'
+
   nv_clear: -> @clear_all()

   nv_cursor_goto: (row, col) ->
     @cursor_row = row
     @cursor_col = col
-  nv_cursor_off: -> @cursor.style.display = 'none'
-  nv_cursor_on: -> @cursor.style.display = 'block'

   nv_eol_clear: -> @clear_block @cursor_col, @cursor_row, @total_col - @cursor_col + 1, 1


Always emit did-change-paths

Always emit did-change-paths

--- src/project.coffee
+++ src/project.coffee
@@ -235,20 +235,17 @@
     watcher.then((w) -> w.dispose()) for _, watcher in @watcherPromisesByPath
     @watcherPromisesByPath = {}

-    added = false
     missingProjectPaths = []
     for projectPath in projectPaths
       try
         @addPath projectPath, emitEvent: false, mustExist: true, exact: options.exact is true
-        added = true
       catch e
         if e.missingProjectPaths?
           missingProjectPaths.push e.missingProjectPaths...
         else
           throw e

-    if added
-      @emitter.emit 'did-change-paths', projectPaths
+    @emitter.emit 'did-change-paths', projectPaths

     if options.mustExist is true and missingProjectPaths.length > 0
       err = new Error "One or more project directories do not exist"


added more to plain text email template

added more to plain text email template

--- src/reports.coffee
+++ src/reports.coffee
@@ -134,9 +134,16 @@
 plainTemplate = (report) ->
   for data in report.data
     do (data) ->
-      "Channel Name : #{ data.channel.name } \r\n
-        Channel Load : #{ data.data[0].load } transactions \r\n
-        Transaction Average Response : #{ data.data[0].avgResp } \r\n
+      " \r\n \r\n <---------- Start Channel  #{data.channel.name} ---------------------------> \r\n \r\n
+          Channel Name: #{data.channel.name} \r\n
+          Channel Load: #{ data.data[0].load } transactions  \r\n
+          Ave response time: #{ data.data[0].avgResp } \r\n
+          Failed:  #{ data.statusData[0].failed }  \r\n
+          Successful:  #{ data.statusData[0].successful }  \r\n
+          Processing: #{ data.statusData[0].processing }  \r\n
+          Completed:  #{ data.statusData[0].completed }  \r\n
+          Completed with errors: #{ data.statusData[0].completedWErrors } \r\n \r\n
+          <---------- End Channel -------------------------------------------------> \r\n \r\n
         \r\n
         \r\n
       "


When loading a class, check that the package name matches.

--- src/runtime.coffee
+++ src/runtime.coffee
@@ -234,11 +234,14 @@
           # bootstrap class loader
           @class_states[cls] = new ClassState null
           class_file = @read_classfile cls
-          unless class_file?
+          if not class_file? or wrong_name = (class_file.this_class.toClassString() != cls)
+            msg = cls
+            if wrong_name
+              msg += " (wrong name: #{class_file.this_class.toClassString()})"
             if dyn
-              java_throw @, 'java/lang/ClassNotFoundException', cls
+              java_throw @, 'java/lang/ClassNotFoundException', msg
             else
-              java_throw @, 'java/lang/NoClassDefFoundError', cls
+              java_throw @, 'java/lang/NoClassDefFoundError', msg
           @loaded_classes[cls] = class_file
     @loaded_classes[cls]


Fix class initialization code.

Fix class initialization code.

--- src/runtime.coffee
+++ src/runtime.coffee
@@ -178,8 +178,12 @@
           obj:  @set_obj(c2t('java/lang/Class'), { $type: type, name: 0 })
         old_loglevel = util.log_level  # suppress logging for init stuff
         util.log_level = util.ERROR
-        # run class initialization code
-        @method_lookup({class: cls, sig: {name: '<clinit>', type: '()V'}}).run(this)
+        # Run class initialization code. We don't want to call this more than
+        # once per class, so don't do dynamic lookup. See spec 5.5.
+        clinit = (m for m in class_file.methods when m.name is '<clinit>')[0]
+        if class_file.super_class
+          @_class_lookup class_file.super_class
+        clinit?.run(this)
         if cls is 'java/lang/System'  # zomg hardcode
           @method_lookup({'class': cls, 'sig': {'name': 'initializeSystemClass'}}).run(this)
         util.log_level = old_loglevel  # resume logging


better handling for routing.

better handling for routing.

--- app/assets/javascripts/habberdash/habberdash.js.coffee
+++ app/assets/javascripts/habberdash/habberdash.js.coffee
@@ -23,8 +23,12 @@
     # setup routes
     @routes
       # base route - display a dashboard based on id
-      '/:id': (params = {}) -> @initializeDashboard(configuration.dashboard(params['id']))
-      # glob route - redirect to the default dashboard
+      '/:id': (params = {}) ->
+        try
+          @initializeDashboard(configuration.dashboard(params['id']))
+        catch e
+          if e == 'Unknown record' then @navigate("/#{configuration.dashboardName()}", true) else throw e
+      # glob route - redirects to the default dashboard
       '*glob': -> @navigate("/#{configuration.dashboardName()}", true)

     # initialize routing


OX-228 fixed garbage collection

OX-228 fixed garbage collection

--- app/assets/javascripts/oxalis/model/binary/cube.coffee
+++ app/assets/javascripts/oxalis/model/binary/cube.coffee
@@ -191,17 +191,20 @@
     if bucketData?

       @bucketCount++
+      @access.push([bucket_x, bucket_y, bucket_z, zoomStep])
+
+      bucket.access++
       bucket.data = bucketData
       bucket.level = 0

       # the bucket with a lower zoomStep can maybe be assembled
       # from buckets with the current zoomStep now
-      @updateBucketChain([
-        bucket_x >> 1
-        bucket_y >> 1
-        bucket_z >> 1
-        zoomStep + 1
-      ])
+      #@updateBucketChain([
+      #  bucket_x >> 1
+      #  bucket_y >> 1
+      #  bucket_z >> 1
+      #  zoomStep + 1
+      #])

       @trigger("bucketLoaded", [bucket_x, bucket_y, bucket_z, zoomStep])

@@ -271,13 +274,13 @@

       # if buckets with a lower zoomStep rely on this bucket
       # they need to get informed
-      @updateBucket([bucket_x, bucket_y, bucket_z, zoomStep])
-      @updateBucketChain([
-        bucket_x >> 1
-        bucket_y >> 1
-        bucket_z >> 1
-        zoomStep + 1
-      ])
+      #@updateBucket([bucket_x, bucket_y, bucket_z, zoomStep])
+      #@updateBucketChain([
+      #  bucket_x >> 1
+      #  bucket_y >> 1
+      #  bucket_z >> 1
+      #  zoomStep + 1
+      #])
       true

     else


Remove unused event listener/handler.

Remove unused event listener/handler.

--- app/assets/javascripts/views/staffplans/show.js.coffee
+++ app/assets/javascripts/views/staffplans/show.js.coffee
@@ -5,7 +5,6 @@
     class: "tall"

   events:
-    "click a[data-change-page]": "changePage"
     "click a.add-client": "onAddClientClicked"
     "change input[data-model=\"Client\"]": "updateProjectTypeAheadOptionList"
     "blur input[data-model=\"Client\"]": "updateProjectTypeAheadOptionList"
@@ -79,12 +78,6 @@
   getYearsAndWeeks: ->
     _.range(@startDate.valueOf(), @startDate.valueOf() + @numberOfBars * 7 * 86400 * 1000, 7 * 86400 * 1000)

-  changePage: (event) ->
-    event.preventDefault()
-    event.stopPropagation()
-
-    @dateChanged event
-
   calculateNumberOfBars: ->
     # calculate usable width for inputs
     @chartContainerWidth = $(document.body).width() - 520 # padding, margin and width of all other elements besides the flex


Async streams

Async streams

--- files.coffee
+++ files.coffee
@@ -146,7 +146,7 @@
         console.info "Meteor.Files Debugger: [MeteorFileUnlink]" if @debug
         self.remove.call cp(_insts[inst._prefix], inst), inst.search

-      _methods[self.methodNames.MeteorFileWrite] = (file, fileData, meta, first, chunksQty, currentChunk, randFileName) ->
+      _methods[self.methodNames.MeteorFileWrite] = (file, fileData, meta, first, chunksQty, currentChunk, totalSentChunks, randFileName, part, partsQty, fileSize) ->
         console.info "Meteor.Files Debugger: [MeteorFileWrite]" if @debug
         # check file, Object
         check fileData, Object
@@ -156,19 +156,25 @@
         check currentChunk, Number
         check randFileName, String

-        console.info 'Receive chunk #' + currentChunk + ' of ' + chunksQty + ' chunks, file: ' + fileData.name or fileData.fileName if self.debug
+        console.info "Received chunk ##{currentChunk} of #{chunksQty} chunks, in part: #{part}, file: #{fileData.name or fileData.fileName}" if self.debug

         i = 0
         binary = ''
+        # console.log file.byteLength
         while i < file.byteLength
           binary += String.fromCharCode(file.buffer[i])
           i++

+        last = (chunksQty * partsQty <= totalSentChunks)
+        # console.log "LAST", last, chunksQty * partsQty, totalSentChunks
+
         cleanName = (str) ->
           str.replace(/\.\./g, '').replace /\//g, ''

         fileName  = cleanName(fileData.name or fileData.fileName)
         ext       = fileName.split('.').pop()
+        pathName  = "#{self.storagePath}/#{randFileName}"
+        pathPart  = "#{self.storagePath}/#{randFileName}_#{part}.#{ext}"
         path      = "#{self.storagePath}/#{randFileName}.#{ext}"
         result    =
           name:       fileName
@@ -178,6 +184,7 @@
           type:       fileData.type
           size:       fileData.size
           chunk:      currentChunk
+          last:       last
           isVideo:    fileData.type.toLowerCase().indexOf("video") > -1
           isAudio:    fileData.type.toLowerCase().indexOf("audio") > -1
           isImage:    fileData.type.toLowerCase().indexOf("image") > -1
@@ -185,17 +192,31 @@
           _collectionName: self.collectionName
           _storagePath:    self.storagePath
           _downloadRoute:  self.downloadRoute
+
+        # console.log "Last, First", last, first

         if first
-          fs.outputFileSync path, binary, 'binary'
+          fs.outputFileSync pathPart, binary, 'binary'
         else
-          fs.appendFileSync path, binary, 'binary'
-
-
-        if chunksQty - 1 is currentChunk
-          delete result.chunk
-          result._id = self.collection.insert result
-          console.info 'The file ' + fileName + ' (binary) was saved to ' + path if self.debug
+          fs.appendFileSync pathPart, binary, 'binary'
+
+        if (chunksQty is currentChunk) and self.debug
+          console.info "The part ##{part} of file #{fileName} (binary) was saved to #{pathPart}"
+
+        if last
+          buffers = []
+          i = 1
+          while i <= partsQty
+            buffers.push fs.readFileSync pathName + '_' + i + '.' + ext
+            fs.unlink pathName + '_' + i + '.' + ext
+            i++
+
+
+          buffer = new Buffer fileSize
+          fs.outputFileSync path, Buffer.concat(buffers), 'binary'
+
+          result._id = self.collection.insert _.clone result
+          console.info "The file #{fileName} (binary) was saved to #{path}" if self.debug

         return result

@@ -274,20 +295,23 @@
   @url https://developer.mozilla.org/en-US/docs/Web/API/FileReader
   @returns {FileReader}
   ###
-  insert: (file, meta, onUploaded, onProgress, onBeforeUpload) ->
+  insert: (config) ->
     console.info "Meteor.Files Debugger: [insert()]" if @debug
+    {file, meta, onUploaded, onProgress, onBeforeUpload, streams} = config
     check meta, Match.Optional Object
     check onUploaded, Match.Optional Function
     check onProgress, Match.Optional Function
     check onBeforeUpload, Match.Optional Function
+    check streams, Match.Optional Number
+
+    streams = 1 if !streams
+    totalSentChunks = 0

     window.onbeforeunload = (e) ->
       message = "Upload in progress..."
       if e
         e.returnValue = message
       return message
-
-    fileReader    = new FileReader
     fileData      =
       size: file.size
       type: file.type
@@ -300,10 +324,24 @@
     console.time('insert') if @debug

     randFileName  = @namingFunction.call null, true
-    currentChunk  = 0
-    first         = true
-    chunksQty     = if @chunkSize < file.size then Math.ceil(file.size / @chunkSize) else 1
     self          = @
+    partSize      = Math.ceil file.size / streams
+    parts         = []
+    uploaded      = 0
+    last          = false
+
+    i = 1
+    while i <= streams
+      parts.push
+        from: partSize * (i-1)
+        to:   partSize * i
+        size: partSize
+        part: i
+        chunksQty: if @chunkSize < partSize then Math.ceil(partSize / @chunkSize) else 1
+      # console.log "if #{@chunkSize} < #{partSize} then Math.ceil(partSize / @chunkSize) else 1", if @chunkSize < partSize then Math.ceil(partSize / @chunkSize) else 1
+      i++
+
+    # console.log parts

     end = (error, data) ->
       console.timeEnd('insert') if self.debug
@@ -311,38 +349,65 @@
       onUploaded and onUploaded.call self, error, data

     if onBeforeUpload
-      if not onBeforeUpload.call file, fileReader
+      if not onBeforeUpload.call file
         end new Meteor.Error(500, "FORBIDDEN"), null
         return false

-    fileReader.onload = (chunk) ->
-      onProgress and onProgress((currentChunk / chunksQty) * 100)
-
-      binary      = chunk.srcElement or chunk.target
-      arrayBuffer = new Uint8Array binary.result
-
-      if chunksQty is 1
-        Meteor.call self.methodNames.MeteorFileWrite, arrayBuffer, fileData, meta, first, chunksQty, currentChunk, randFileName, (error, data) ->
-          end error, data
-      else
-        Meteor.call self.methodNames.MeteorFileWrite, arrayBuffer, fileData, meta, first, chunksQty, currentChunk, randFileName, (error, data)->
-          if data.chunk <= chunksQty
-            currentChunk = data.chunk + 1
-            from         = currentChunk * self.chunkSize
-            to           = from + self.chunkSize
-            fileReader.readAsArrayBuffer file.slice from, to
-          else
-            end error, data
-      first = false
-
-
-
-    if chunksQty is 1
-      fileReader.readAsArrayBuffer file
-    else
-      fileReader.readAsArrayBuffer file.slice 0, @chunkSize
-
-    return fileReader
+    upload = (filePart, part, chunksQtyInPart, fileReader) ->
+      currentChunk = 1
+      first = true
+      console.time("insertPart#{part}") if @debug
+
+      fileReader.onload = (chunk) ->
+        ++totalSentChunks
+        # console.log "currentChunk", currentChunk
+        onProgress and onProgress((uploaded / file.size) * 100)
+        # console.log "PROGRESS: ", (uploaded / file.size) * 100
+
+        uploaded   += self.chunkSize
+        binary      = chunk.srcElement or chunk.target
+        arrayBuffer = new Uint8Array binary.result
+        last        = (part is streams and currentChunk >= chunksQtyInPart)
+
+        # console.log "isLastPart?", last, "#{currentChunk} >= #{chunksQtyInPart}"
+
+        if chunksQtyInPart is 1
+          Meteor.call self.methodNames.MeteorFileWrite, arrayBuffer, fileData, meta, first, chunksQtyInPart, currentChunk, totalSentChunks, randFileName, part, streams, file.size, (error, data) ->
+            if data.last
+              end error, data
+        else
+          Meteor.call self.methodNames.MeteorFileWrite, arrayBuffer, fileData, meta, first, chunksQtyInPart, currentChunk, totalSentChunks, randFileName, part, streams, file.size, (error, data)->
+            # console.log "DATA.last", data.last, error, data
+            if data.chunk + 1 <= chunksQtyInPart
+              from         = currentChunk * self.chunkSize
+              to           = from + self.chunkSize
+
+              # console.log "Send chunk ##{currentChunk} of part ##{part} | #{from} #{to}"
+              fileReader.readAsArrayBuffer filePart.slice from, to
+              currentChunk = ++data.chunk
+            else if data.last
+              end error, data
+        first = false
+
+      # console.log "Send first chunk of part"
+      fileReader.readAsArrayBuffer filePart.slice 0, self.chunkSize
+
+    # for part, index in parts
+    i = parts.length - 1
+    while i >= 0
+      Meteor.setTimeout ((parts, i) ->
+        return () ->
+          part = parts[i]
+          # console.log "Upload part#", part
+          fileReader = new FileReader
+          # console.log "Slice file to parts: #{index}"
+          upload(file.slice(part.from, part.to), i + 1, part.chunksQty, fileReader)
+      )(parts, i)
+      ,
+        0
+      --i
+
+    return undefined

   ###
   @isomorphic


notifications

notifications

--- src/uapanfw.coffee
+++ src/uapanfw.coffee
@@ -37,12 +37,16 @@

 module.exports = (robot) ->

-  data = []
+  fwdata =
+    notify: []
+    blacklist: []
   try
-    fwdata = fs.readFileSync blacklistfile, 'utf-8'
-    if fwdata
-      data = JSON.parse(fwdata)
-      console.log "#{modulename} blacklist loaded: " + data.length + " entries"
+    fwdata = JSON.parse fs.readFileSync blacklistfile, 'utf-8'
+    if Array.isArray(fwdata)
+      fwdata =
+        notify: []
+        blacklist: fwdata
+    #robot.logger.info "#{modulename} data loaded"
   catch error
     console.log('Unable to read file', error) unless error.code is 'ENOENT'

@@ -53,7 +57,7 @@
     robot.logger.info logmsg

     arr = []
-    for obj in data
+    for obj in fwdata.blacklist
       if obj.type == 'url' and moment(obj.expires).isAfter()
         arr.push obj.val
     content = '# nothing here yet! #'
@@ -64,6 +68,8 @@
     logmsg = "#{modulename}: robot responded to web request: sent url blacklist"
     robot.logger.info logmsg

+    return
+
   robot.router.get "/#{robot.name}/#{modulename}/blacklist/cidr", (req, res) ->
     clientip = req.connection.remoteAddress || req.socket.remoteAddress ||
       req.connection.socket.remoteAddress
@@ -71,7 +77,7 @@
     robot.logger.info logmsg

     arr = []
-    for obj in data
+    for obj in fwdata.blacklist
       if obj.type == 'cidr' and moment(obj.expires).isAfter()
         arr.push obj.val
     content = '# nothing here yet! #'
@@ -82,6 +88,8 @@
     logmsg = "#{modulename}: robot responded to web request: " +
       "sent cidr blacklist"
     robot.logger.info logmsg
+
+    return

   robot.respond /fw(?: help|)$/, (msg) ->
     cmds = ['```']
@@ -115,7 +123,7 @@
     arr = []
     fmt = '%-4s %-50s %-15s %s'
     arr.push sprintf fmt, 'Type', 'Value', 'Expiration', 'Creator'
-    for obj in data
+    for obj in fwdata.blacklist
       expires = moment(obj.expires)
       if bl_type and bl_type != obj.type
         #console.log 'skipping type: '+ obj.type
@@ -136,16 +144,20 @@
       "displayed blacklist items and expirations"
     robot.logger.info logmsg

+    return
+
   robot.respond /fw (?:blacklist|b) add (url|cidr) ([^ ]+)(?: ([^ ]+)|)$/i, (msg) ->
     return unless isAuthorized robot, msg
     return unless isSudo robot, msg
+
+    who = msg.envelope.user.name

     bl =
       created: moment().format()
       expires: moment().add(1, 'months').format()
       type: msg.match[1]
       val: msg.match[2]
-      creator: msg.envelope.user.name
+      creator: who

     if bl.val.toLowerCase().indexOf('https://') == 0
       usermsg = "Blacklisting of https links not supported."
@@ -164,34 +176,38 @@
       else if moment(expires).isValid()
         bl.expires = moment(expires).format()
       else
-        failed = true
         usermsg = "invalid expiration date: #{expires}"
-        msg.reply usermsg
+        return msg.reply usermsg

-    unless failed
-      logmsg = "#{modulename}: #{msg.envelope.user.name} requested: " +
-        "blacklist #{bl.type} #{bl.val} expires #{bl.expires}"
-      robot.logger.info logmsg
-
-      data.push bl
-      fs.writeFileSync blacklistfile, JSON.stringify(data), 'utf-8'
-
-      usermsg = "Added #{bl.val} to firewall blacklist, " +
-        "expiring #{bl.expires}.  Change will be applied in < 5 minutes."
-      msg.reply usermsg
-
-      logmsg = "#{modulename}: robot responded to #{msg.envelope.user.name}: " +
-        "added entry to blacklist"
-      robot.logger.info logmsg
+    logmsg = "#{modulename}: #{who} requested: " +
+      "blacklist #{bl.type} #{bl.val} expires #{bl.expires}"
+    robot.logger.info logmsg
+
+    fwdata.blacklist.push bl
+    fs.writeFileSync blacklistfile, JSON.stringify(fwdata), 'utf-8'
+
+    usermsg = "Added #{bl.val} to firewall blacklist, " +
+      "expiring #{bl.expires}.  Change will be applied in < 5 minutes."
+    msg.reply usermsg
+
+    logmsg = "#{modulename}: robot responded to #{who}: " +
+      "added entry to blacklist"
+    robot.logger.info logmsg
+
+    for un in fwdata.notify
+      robot.send { room: un }, usermsg unless un == who
+
+    return

   robot.respond /fw (?:blacklist|b) (?:delete|del|d) (url|cidr) ([^ ]+)$/i, (msg) ->
     return unless isAuthorized robot, msg
     return unless isSudo robot, msg

+    who = msg.envelope.user.name
     bl_type = msg.match[1]
     bl_search = msg.match[2]

-    logmsg = "#{modulename}: #{msg.envelope.user.name} requested: " +
+    logmsg = "#{modulename}: #{who} requested: " +
       "blacklist delete #{bl_type} #{bl_search}"
     robot.logger.info logmsg

@@ -199,7 +215,7 @@
     newdata = []
     fmt = '%-4s %-50s %-15s %s'
     arr.push sprintf fmt, 'Type', 'Value', 'Expiration', 'Creator'
-    for obj in data
+    for obj in fwdata.blacklist
       expires = moment(obj.expires)
       if bl_type and bl_type != obj.type
         newdata.push obj
@@ -214,14 +230,80 @@

     # drop deleted records
     deltaN = data.length - newdata.length
-    data = newdata
-    fs.writeFileSync blacklistfile, JSON.stringify(data), 'utf-8'
-
-    usermsg = "Removed #{deltaN} entries from firewall blacklist.  " +
-      "Change will be applied in < 5 minutes.\n" +
-      "Removed: ```"+ arr.join("\n") + "```"
+    fwdata.blacklist = newdata
+    fs.writeFileSync blacklistfile, JSON.stringify(fwdata), 'utf-8'
+
+    if deltaN > 0
+      usermsg = "Removed #{deltaN} entries from firewall blacklist.  " +
+        "Change will be applied in < 5 minutes.\n" +
+        "Removed: ```"+ arr.join("\n") + "```"
+    else usermsg = "Blacklist delete request did not match any records."
     msg.reply usermsg

     logmsg = "#{modulename}: robot responded to #{msg.envelope.user.name}: " +
       "removed #{deltaN} entries from blacklist"
     robot.logger.info logmsg
+
+    for un in fwdata.notify
+      robot.send { room: un }, usermsg unless un == who or deltaN < 1
+
+    return
+
+  robot.respond /fw (?:blacklist|b) (?:notify|n)(?: ([^ ]+))$/i, (msg) ->
+    user = msg.envelope.user
+    who = user.name
+    who = msg.match[1] if msg.match[1]
+
+    logmsg = "#{modulename}: #{user.name} requested: notify #{who}"
+    robot.logger.info logmsg
+
+    fwdata.notify.push who unless who in fwdata.notify
+
+    usermsg = "Added #{who} to firewall blacklist notifications."
+    msg.reply usermsg
+
+    logmsg = "#{modulename}: robot responded to #{user.name}: " +
+      "added #{who} to blacklist notifications"
+    robot.logger.info logmsg
+
+    fs.writeFileSync blacklistfile, JSON.stringify(fwdata), 'utf-8'
+
+    return
+
+  robot.respond /fw (?:blacklist|b) (?:notify|n) (?:list|l)$/i, (msg) ->
+    who = msg.envelope.user.name
+
+    logmsg = "#{modulename}: #{who} requested: notify list"
+    robot.logger.info logmsg
+
+    usermsg = "Notify list: "+ fwdata.notify.join(', ')
+    msg.reply usermsg
+
+    logmsg = "#{modulename}: robot responded to #{who}: " +
+      fwdata.notify.join(', ')
+    robot.logger.info logmsg
+
+    return
+
+  robot.respond /fw (?:blacklist|b) (?:unnotify|un)(?: ([^ ]+))$/i, (msg) ->
+    user = msg.envelope.user
+    who = msg.envelope.user.name
+    who = msg.match[1] if msg.match[1]
+
+    logmsg = "#{modulename}: #{user.name} requested: unnotify #{who}"
+    robot.logger.info logmsg
+
+    n = fwdata.notify.indexOf(who)
+    fwdata.notify.splice(n, 1) if n > -1
+
+    usermsg = "Removed #{who} from firewall blacklist notifications."
+    msg.reply usermsg
+
+    logmsg = "#{modulename}: robot responded to #{user.name}: " +
+      "removed #{who} from blacklist notifications"
+    robot.logger.info logmsg
+
+    fs.writeFileSync blacklistfile, JSON.stringify(fwdata), 'utf-8'
+
+    return
+


Reverted the no-wrap change.

Reverted the no-wrap change.

--- src/watcher.coffee
+++ src/watcher.coffee
@@ -64,10 +64,6 @@
       # Find a compiler plugin that can handle this file extension
       ext = sysPath.extname(path)
       compiler = @compilerForExt(ext)
-
-      # Don't wrap JavaScript files inside the assets dir
-      if ext is '.js' and (path.indexOf(project.clientAssetsDir) > -1)
-        compiler = null

       if compiler
         # Let the compiler plugin handle it.


Add high-DPI-support for map-markers. Fixes #282.

--- src/widgets.coffee
+++ src/widgets.coffee
@@ -53,18 +53,31 @@
             @options.iconSize = new L.Point @dimension, @dimension
             @options.iconAnchor = @iconAnchor()
             @options.reducedProminence = options.reducedProminence
+            @options.pixelRatio = (el) ->
+                context = el.getContext('2d')
+                devicePixelRatio = window.devicePixelRatio || 1
+                backingStoreRatio = context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio || context.backingStorePixelRatio || 1
+                return devicePixelRatio / backingStoreRatio
         options:
             className: 'leaflet-canvas-icon'
         setupCanvas: ->
             el = document.createElement 'canvas'
+            context = el.getContext('2d')
+            # Set ratio based on device dpi
+            ratio = @options.pixelRatio(el)
             # If the IE Canvas polyfill is installed, the element needs to be specially
             # initialized.
             if G_vmlCanvasManager?
                 G_vmlCanvasManager.initElement el
             @_setIconStyles el, 'icon'
             s = @options.iconSize
-            el.width = s.x
-            el.height = s.y
+            # Set el width based on device dpi
+            el.width = s.x * ratio
+            el.height = s.y * ratio
+            el.style.width = s.x + 'px'
+            el.style.height = s.y + 'px'
+            # Scale down to normal
+            context.scale(ratio, ratio)
             if @options.reducedProminence
                 L.DomUtil.setOpacity el, REDUCED_OPACITY
             el


client: reconfigure initial actions

client: reconfigure initial actions

Signed-off-by: Umut Sirin <4055abbc0e40a1254e715b952ccd414607e0b365@gmail.com>

--- client/app/lib/redux/dispatchInitialActions.coffee
+++ client/app/lib/redux/dispatchInitialActions.coffee
@@ -2,7 +2,7 @@
 isAdmin = require 'app/util/isAdmin'

 { LOAD: BONGO_LOAD } = bongo = require 'app/redux/modules/bongo'
-{ Plan } = require 'app/redux/modules/payment/constants'
+{ Plan, Status } = require 'app/redux/modules/payment/constants'

 { create: createCustomer } = require 'app/redux/modules/payment/customer'
 { load: loadPaymentInfo } = require 'app/redux/modules/payment/info'
@@ -31,61 +31,38 @@
     bongo: (remote) -> remote.api.JUser.fetchUser()
   }

-ensurePaymentDetails = ({ dispatch, getState }) ->
+ensureGroupPayment = ->

-  # NOTE:
-  #
-  # `handleNoPayment{Admin,Member}` functions are for the cases where an
-  # existing team prior to our pricing release. Here are the expected
-  # behaviors:
-  #   - Admin:  First login will trigger the group plan creation process in the
-  #             backend. And don't have to do anything, the next time a new
-  #             member/admin is logged in everything will be ok. First logged
-  #             in will see a notification modal.
-  #
-  #   - Member: First login will trigger a customer/subscription process in
-  #             client side, not in backend. If things go smoothly members
-  #             shouldn't see anything and continue using Koding immediately.
+  if groupPayment = globals.currentGroup.payment
+  then Promise.resolve groupPayment
+  else Promise.reject Status.NEEDS_UPGRADE

-  handleNoPaymentAdmin = ->
-    # do nothing, we will show a modal, and doing any action over there will
-    # trigger a reload which should fix the problem.
-    console.info 'Got an old team, we need to reload'
+ensureCreditCard = ({ dispatch }) ->

-  handleNoPaymentMember = ->
-    # create customer & subscription
-    # then reload the page, in next reload, group will have `payment` object
-    # ready.
-    dispatch(createCustomer())
-      .then -> dispatch(createSubscription getState().customer.id, Plan.UP_TO_10_USERS)
-      .then -> location.reload()
+  if globals.hasCreditCard
+  then Promise.resolve()
+  else Promise.reject Status.NEEDS_UPGRADE
+
+loadPaymentDetails = ({ dispatch }) ->

   if isAdmin()
-
-    promise = dispatch(loadPaymentInfo())
-
-    if globals.currentGroup.payment
-    then promise.then -> dispatch(loadInvoices())
-    else handleNoPaymentAdmin()
-
-  else
-    if globals.currentGroup.payment
-    then dispatch(loadSubscription())
-    else handleNoPaymentMember()
-
+  then dispatch(loadPaymentInfo()).then -> dispatch(loadInvoices())
+  else dispatch(loadSubscription())

 module.exports = dispatchInitialActions = (store) ->

   { getState, dispatch } = store

-  console.log 'dispatching initial actions', store
-
   promise = loadAccount(store)
     .then -> loadGroup(store)
     .then -> loadUserDetails(store)
-    .then -> ensurePaymentDetails(store)
+    .then -> ensureGroupPayment()
+    .then -> loadPaymentDetails(store)
+    .then -> ensureCreditCard(store)

-  promise.then(console.log.bind(console, 'finished dispatching initial actions'))
+  promise
+    .then (args...) -> console.log 'finished dispatching initial actions'
+    .catch (err) -> console.info 'error when dispatching initial actions', err


spelling

spelling

--- tasks/tests.coffee
+++ tasks/tests.coffee
@@ -60,7 +60,7 @@
 mochaWindows = (cb) ->
   # TODO: Fix so Mocha results are shown in Appveyor.
   if _.contains(process.argv, '--appveyor')
-    console.log('Note you can\'t see Mocha tests result in AppVeyor due to how Windows spawns processes')
+    console.log('Note you can\'t see Mocha test results in AppVeyor due to how Windows spawns processes')

   options = {stdio: [process.stdin, process.stdout, process.stderr]}
   env = process.env


remove restrictive test

remove restrictive test

--- test/render.coffee
+++ test/render.coffee
@@ -114,7 +114,7 @@
           content.should.eql 'Hello you'
           next()

-    it.only 'should use `content`', (next) ->
+    it 'should use `content`', (next) ->
       source = "#{scratch}/render.j2"
       destination = "#{scratch}/render.txt"
       fs.writeFile source, 'Hello {{ who }}', (err, content) ->


Readded filesystem to window

Readded filesystem to window

--- www/coffee/blue_carbon.coffee
+++ www/coffee/blue_carbon.coffee
@@ -62,6 +62,14 @@
     @addBaseLayer()

   addBaseLayer: ->
+    window.requestFileSystem LocalFileSystem.PERSISTENT, 0, (fileSystem) =>
+      window.fs = fileSystem
+      file = fs.root.getFile(@localFileName,
+        create: false
+      , undefined
+      , undefined
+      )
+
     tileLayerUrl = 'res/tiles/{z}/{x}/{y}.png'
     tileLayer = new L.TileLayer(tileLayerUrl, {
       maxZoom: 18


refactor references to PiecePattern object

--- views/puzzle.coffee
+++ views/puzzle.coffee
@@ -6,6 +6,7 @@
     @events = new EventHandler(this)

     @puzzle_view = new PuzzleView(this)
+    @piece = new PuzzlePiece(this)
     @colors = new ColorRotation
     @indicator = new Indicator(this)
     @grid_model = new PuzzleGridModel(this)
@@ -190,7 +191,7 @@
   constructor: (puzzle_app) ->
     @puzzle = puzzle_app
     @hex_box = @puzzle.hex_box
-    @piece_mask  = new PiecePattern(this)
+    @pattern  = new PiecePattern(this)
     @redraw = new PieceRedrawBuffer(this)
     @hexes = []
     @bounding_box = [0,0,0,0,]
@@ -198,13 +199,13 @@

   construct_piece: (sym) ->
     @sym = sym
-    @hexes = @get_hexes()
+    @hexes = @pattern.get_hexes()
     @hex_box.set_hex_box(sym)
     wd_ht = @hex_box.get_box_size()
     @width = wd_ht[0]
     @height = wd_ht[1]
     @redraw.reset_size(@width,@height)
-    @piece_mask.draw_piece_pattern()
+    @pattern.draw_piece_pattern()
     @cut_piece_from_photo()
     @draw_piece_ab(-7,5)

@@ -261,13 +262,13 @@
     if x>@left && x<@right && y>@top && y<@bottom then return true else return false

-  # TODO Does this method belong in PuzzlePattern class?
-  get_hexes: () ->
-    hexes = []
-    for bb in [1..10]
-      for aa in [1..24]
-        hexes.push([aa,bb]) if @puzzle.puzzle_pattern.grid[bb][aa] == @sym
-    return hexes
+  # TODO Does this method belong in PiecePattern class?
+  # get_hexes: () ->
+  #   hexes = []
+  #   for bb in [1..10]
+  #     for aa in [1..24]
+  #       hexes.push([aa,bb]) if @puzzle.puzzle_pattern.grid[bb][aa] == @sym
+  #   return hexes

@@ -301,6 +302,14 @@
       if aa%2 != anchor_a%2
         if anchor_a%2 == 0 then yy = yy+10 else yy = yy-10
       @hex_draw.fill_hex_xy(xx,yy,"#000000")
+
+
+  get_hexes: () ->
+    hexes = []
+    for bb in [1..10]
+      for aa in [1..24]
+        hexes.push([aa,bb]) if @grid[bb][aa] == @sym
+    return hexes

@@ -674,7 +683,7 @@
       @pstring = response.pstring
       grid = get_pattern_grid(@pstring)
       @mask = new MissingPiecesMask(app, grid)
-      @piece = new PuzzlePiece(app)
+      app.piece.construct_piece()
       app.pz_status.start_new_puzzle()
   xhr.send()


fixed cypher vote query bug

fixed cypher vote query bug

--- model/Resource._coffee
+++ model/Resource._coffee
@@ -51,9 +51,9 @@
         "MATCH (resource) -[:RELATED_TO]- (connection) -[:RELATED_TO]- (otherResource) -[:CREATED_BY]- (otherResourceCreator),",
         "(otherConnections)-[?:RELATED_TO]-(otherResource),",
         "(connection) -[:CREATED_BY]- (connectionCreator),",
-        "(connection) -[?:COMMENT_OF]- (comments)",
+        "(connection) -[?:COMMENT_OF]- (comments),",
         "(connection) -[?:VOTED_UP]- (upvotes),",
-        "(connection) -[?:VOTED_DOWN]- (downvotes),"
+        "(connection) -[?:VOTED_DOWN]- (downvotes)",
         "WHERE otherResource <> resource AND otherConnections <> connection ",
         "RETURN otherResource, otherResourceCreator, connection, connectionCreator, count(comments) AS commentCount, count(otherConnections) AS otherConnectionsCount,",
         "count(upvotes) AS upvotesCount,",


favicon from theme

favicon from theme

--- vue/src/main.coffee
+++ vue/src/main.coffee
@@ -23,6 +23,13 @@

 boot ->
   Session.fetch().then (data) ->
+
+    ['shortcut icon', 'apple-touch-icon'].forEach (name) =>
+      link = document.createElement('link')
+      link.rel = name
+      link.href = AppConfig.theme.icon_src
+      document.getElementsByTagName('head')[0].appendChild(link)
+
     Session.apply(data)

     new Vue(


keepin it clean

keepin it clean

--- app/coffee/tag.coffee
+++ app/coffee/tag.coffee
@@ -170,11 +170,12 @@
   constructor: (name, id = '') ->
     @name = name
     @id = id
+    @showEntry = $('#showEntry')
     #@attachToEntry()
   setId: (id) ->
     @id = id
   create: ->
-    @entry_id = $('#showEntry').data('id')
+    @entry_id = @showEntry.data('id')
     $.ajax {
       type: 'POST'
       url: '/tags'
@@ -188,7 +189,8 @@
     #$.post "/tags", { entry_id: @entry_id, what_name: @name }, (data) -> alert "Data Loaded: " + data
   destroy: ->
     $.publish 'tags:remove', [@id]
-    @entry_id = $('#showEntry').data('id')
+    @entry_id = @showEntry.data('id')
+
     $.ajax {
       type: 'DELETE'
       url: '/tags/what'


Compacted code a little

Compacted code a little

--- core/app/backbone/views/topics/sidebar_view.coffee
+++ core/app/backbone/views/topics/sidebar_view.coffee
@@ -12,9 +12,7 @@
     @model.bind('deactivate', @activeOff, this)
     @model.bind('change',@render,this)

-  onRender: ->
-    @activeOn() if @model.isActive()
-
+  onRender: -> @activeOn() if @model.isActive()

 class window.TopicHeaderView extends Backbone.Marionette.ItemView
   tagName: 'ul'


rename item to line.

rename item to line.

--- content_manifest.coffee
+++ content_manifest.coffee
@@ -23,18 +23,18 @@

 	compile: ->
 		content = ""
-		for item in @list
+		for line in @list
 			# strip comments
-			continue unless item
-			continue if item.match /^\s*#/
-			item.replace /#.*/,""
+			continue unless line
+			continue if line.match /^\s*#/
+			line.replace /#.*/,""
 			unless fs.existsSync(f)
 				console.warn "File #{ f } does not exist."
 				continue

 			for f in @filters
-				if item.match f.pattern
-					content += f.filter(item)
+				if line.match f.pattern
+					content += f.filter(line)
 					break
 		for f in @finalizeFilters
 			content = f(content)


FIX: object clone bug in umd helper

FIX: object clone bug in umd helper

--- build/helpers/umd.coffee
+++ build/helpers/umd.coffee
@@ -4,7 +4,9 @@
 pkg = require '../../package'

 module.exports = (opts) ->
-  opts = _.extend {}, pkg.umd, opts
+  umdConfig = _.cloneDeep pkg.umd
+  opts = _.extend umdConfig, opts
+
   opts.dependencies.cjs = opts.dependencies.cjs.map (name) ->
     "require('#{name}')"
   .join ','


feat: more debugging by default

feat: more debugging by default

--- app/config/app.coffee
+++ app/config/app.coffee
@@ -4,10 +4,10 @@
   options =
     LOG_TRANSITIONS:                true
     LOG_TRANSITIONS_INTERNAL:       false
-    LOG_STACKTRACE_ON_DEPRECATION:  false
-    LOG_BINDINGS:                   false
+    LOG_STACKTRACE_ON_DEPRECATION:  true
+    LOG_BINDINGS:                   true
     LOG_VIEW_LOOKUPS:               true
-    LOG_ACTIVE_GENERATION:          false
+    LOG_ACTIVE_GENERATION:          true

   # From http://git.io/HPjymw
   Ember.RSVP.configure 'onerror', (e) ->


bugfix. Check if we're at the last step.

--- overrides.coffee
+++ overrides.coffee
@@ -97,9 +97,9 @@
       task.reset
         index: index
         details: tool.mark.details
-    LAST_TASK = index == rectangles.length - 1

   if task.key is 'parts'
+    LAST_TASK = rect_index == rectangles.length - 1
     if LAST_TASK
       task.next = null
     else


Fix port problem

Fix port problem

--- client/views/instances/instances.coffee
+++ client/views/instances/instances.coffee
@@ -28,7 +28,8 @@
       (parseInt(@meta.progress)/parseInt(@meta.totalSteps))*100
   stopButtonText: -> if @meta.state isnt 'active' then 'Destroy' else 'Stop'
   instanceLink: ->
-    endpoint = @services?.www?.endpoint or ":" + findWebPort @services?.www
+    port = findWebPort @services?.www
+    endpoint = @services?.www?.endpoint or ":" + port
     protocol = @services?.www?.protocol or determineProtocol port
     if @services?.www?.hostname
       "#{protocol}://#{@services?.www?.hostname}#{endpoint}"


Constrain points to integers

Constrain points to integers

--- app/js/display.coffee
+++ app/js/display.coffee
@@ -7,10 +7,9 @@
     dx = @ctx.width/2
     dy = @ctx.height/2
     for [x, y] in points
-      # TODO constrain to integers? | 0, etc.?
       [
-        (x - @center[0]) + dx
-        (-y + @center[1]) + dy
+        Math.round((x - @center[0]) + dx)
+        Math.round((-y + @center[1]) + dy)
       ]

   drawPolygon: (vertices, color, alpha = 0.5) ->
@@ -62,13 +61,12 @@
   # sizeY  - size of display (world, not pixels)
   constructor: (@ctx, @center, @sizeX, @sizeY) ->

-  # TODO constrain to integers? | 0, etc.?
   transform: (points, offset = [0, 0]) ->
     dx = @ctx.width/2
     dy = @ctx.height/2
     for [x, y] in points
-      [ ( x - @center[0] + offset[0] * @sizeX) + dx
-        (-y + @center[1] + offset[1] * @sizeY) + dy ]
+      [ Math.round(( x - @center[0] + offset[0] * @sizeX) + dx)
+        Math.round((-y + @center[1] + offset[1] * @sizeY) + dy) ]

   drawPolygons: (polygons, color, lineColor, alpha = 1) ->
     @ctx.beginPath()


back to production

back to production

--- app/lib/config.coffee
+++ app/lib/config.coffee
@@ -13,4 +13,4 @@
 else
   'production'

-module.exports = Config['development']
+module.exports = Config['production']


Clean the router form default data

Clean the router form default data

--- app/lib/router.coffee
+++ app/lib/router.coffee
@@ -84,6 +84,6 @@
     view = new VirtualMachineSaveView({model: model})
     application.layout.content.show(view)
   reference: ()=>
-    model = new References([{name: "valeur1", translationKey: "t_valeur1"}, {name: "valeur2", translationKey: "t_valeur2"}, {name: "valeur3", translationKey: "t_valeur3"}])
+    model = new References()
     view = new ReferencesView({model: model})
     application.layout.content.show(view)


Replace requiring of models within models with mongoose.model

Signed-off-by: Ian Macalinao <08370e385f4778cad8fe504ec5445edd3d45bd9a@gmail.com>

--- app/models/ban.coffee
+++ app/models/ban.coffee
@@ -1,6 +1,4 @@
 mongoose = require 'mongoose'
-Player = require './player'
-Server = require './server'

 schema = new mongoose.Schema
   # Player banned
@@ -47,6 +45,8 @@
     default: 'pending'

 schema.statics.fromJSON = (server, json, cb) ->
+  Player = mongoose.model 'Player'
+
   isValidDate = (d) ->
     return false if Object::toString.call(d) isnt '[object Date]'
     return !isNaN d.getTime()


fix order in extend, remove unnecessary assignment

--- pie_chart.coffee
+++ pie_chart.coffee
@@ -45,6 +45,6 @@
     if @myChart
       if data.labels then @myChart.data.labels = data.labels
       if data.datasets then @myChart.data.datasets = data.datasets
-      if data.options then @myChart.options = $.extend(data.options, @myChart.options)
+      if data.options then $.extend(@myChart.options, data.options)

       @myChart.update()


Remove the beta feedback link

Remove the beta feedback link

--- project.coffee
+++ project.coffee
@@ -36,7 +36,6 @@
   externalLinks:
     Blog: 'http://blog.biodiversitylibrary.org/'
     '<i class="fa fa-twitter fa-lg">Twitter</i>': 'http://twitter.com/the_zooniverse'
-    Feedback: 'https://docs.google.com/forms/d/1Ce3OeHM_PlCOIYQCLeBvrVSoxB7Mwku7g-GAD5_-xUc/viewform?c=0&w=1'

   tasks:
     illustrations:


Switch UserSessions insert/update logic to use upsert

--- user_status.coffee
+++ user_status.coffee
@@ -40,16 +40,12 @@
     TODO serious bug here when sessionId already exists in local collection
     Happens when userId exists but session has already been recorded with the same sessionId
   ###
-  if UserSessions.findOne(sessionId)
-    UserSessions.update sessionId,
-      userId: userId
-      ipAddr: ipAddr
-  else
-    # Only this part should actually be necessary
-    UserSessions.insert
-      _id: sessionId
-      userId: userId
-      ipAddr: ipAddr
+  UserSessions.upsert
+    _id: sessionId
+  ,
+    userId: userId
+    ipAddr: ipAddr
+
   UserStatus.emit("sessionLogin", userId, sessionId, ipAddr)

   Meteor.users.update userId,


Temporary fix, plugin not started if atom is starting without php project

--- lib/peekmo-php-atom-autocomplete.coffee
+++ lib/peekmo-php-atom-autocomplete.coffee
@@ -52,16 +52,15 @@
     # if not config.testConfig()
     #   return
     config.init()
-    if @registerProviders()
-      @registerProviders()
+    @registerProviders()

-      @gotoManager = new GotoManager()
-      @gotoManager.init()
+    @gotoManager = new GotoManager()
+    @gotoManager.init()

-      @tooltipManager = new TooltipManager()
-      @tooltipManager.init()
+    @tooltipManager = new TooltipManager()
+    @tooltipManager.init()

-      proxy.init()
+    proxy.init()

   deactivate: ->
     @providers = []
@@ -76,7 +75,8 @@
     try
         proxy.composer()
     catch err
-        return false
+        console.log "No composer"
+        #return false

     @providers.push new ClassProvider()
     @providers.push new AutocompleteProvider()
@@ -84,6 +84,6 @@
     @providers.push new SelfProvider()
     @providers.push new ParentProvider()

-    return true
+    #return true
   getProvider: ->
     @providers


Store scroll position in sessionStorage. Fix #139

Including fancy IronRouter "ready" detection

--- client/autoscroll.coffee
+++ client/autoscroll.coffee
@@ -5,16 +5,25 @@

 lastURL = null
 pastTops = {}
+loadedPastTops = false
 transitioning = false
+
+saveTops = _.debounce ->
+  sessionStorage?.setItem? 'pastTops', JSON.stringify pastTops
+, 100

 $(window).scroll ->
   return if transitioning
   lastURL = document.URL
   pastTops[lastURL] = $(window).scrollTop()
   #console.log lastURL, $(window).scrollTop()
+  saveTops()

 Router.onBeforeAction ->
   transitioning = true
+  if stored = sessionStorage?.getItem? 'pastTops'
+    pastTops = JSON.parse stored
+    #console.log 'loaded', pastTops
   @next()

 Router.onAfterAction ->
@@ -24,7 +33,13 @@
     #console.log url, lastURL, pastTops[url] or 0
     return if url == lastURL
     lastURL = url
-    $('html, body').animate
-      scrollTop: pastTops[url] or 0
-    , 200
+    top = pastTops[url] or 0  ## prevent from changing while page loads
+    scroll = ->
+      $('html, body').animate
+        scrollTop: top
+      , 200
+    Tracker.autorun (computation) ->
+      if Router.current().ready()
+        scroll()
+        computation.stop()
   , 100


Routes: Fixed collaboration host username.

--- client/ide/routes.coffee
+++ client/ide/routes.coffee
@@ -127,11 +127,19 @@
         .then (workspaces) ->

           try
-            for workspace in workspaces when workspace.channelId is channel.id
-              machine   = (KD.userMachines.filter (m) -> m.uid is workspace.machineUId)[0]
-              username  = KD.nick()
-              channelId = channel.id
-              return loadIDE { machine, workspace, username, channelId }
+            workspaces.forEach (workspace) =>
+
+              return  unless workspace.channelId is channel.id
+
+              machine = (KD.userMachines.filter (m) -> m.uid is workspace.machineUId)[0]
+
+              query  = socialApiId: channel.creatorId
+              KD.remote.api.JAccount.some query, {}, (err, account) =>
+                return throw new Error err  if err
+
+                username  = account.first.profile.nickname
+                channelId = channel.id
+                return loadIDE { machine, workspace, username, channelId }

           catch e
             return routeToLatestWorkspace()


removed cached .gitignore file

removed cached .gitignore file

--- client/test/tests.coffee
+++ client/test/tests.coffee
@@ -1,133 +0,0 @@
-assert = chai.assert
-
-suite('Dashboard')
-
-test("Can view my work-in-progress")
-test("Can view my notifications")
-test("Can view my recent reports")
-test("Can view my recent indicators")
-test("Can navigate to Dashboard, Reports, Indicators and Bookmarks")
-
-suite('Dashboard: notifications')
-test("Can see requests for me to write sections")
-test("Requests to write sections have title and requester and date")
-
-suite('Dashboard: work-in-progress')
-
-suite('Dashboard: reports')
-
-suite('Dashboard: indicators')
-
-assert = chai.assert
-
-suite('Indicator Index')
-
-test("List titles of all indicators")
-test("Can see owner for each report")
-test("Can see latest data available for each report")
-test("Can see latest data updated_at for each report")
-test("Can see if indicator is bookmarked/favourited")
-test("Can navigate to all related reports")
-test("Can navigate to Dashboard, Reports, Indicators and Bookmarks")
-
-assert = chai.assert
-
-suite('Report Index')
-
-test("List titles of all reports")
-test("Can see creator and completed_at date for each report")
-test("Can see if report is bookmarked/favourited")
-test("Can navigate to report view")
-test("Can navigate to Dashboard, Reports, Indicators and Bookmarks")
-
-assert = chai.assert
-
-suite('Backbone.Models.Report')
-
-assert = chai.assert
-
-createAndShowReportViewForReport = (report) ->
-  view = new Backbone.Views.ReportView(report: report)
-  $('#test-container').html(view.el)
-  return view
-
-suite('Report View')
-
-test("Can see a report's title", ->
-  title = "My Lovely Report"
-  report = new Backbone.Models.Report(title: title)
-
-  view = createAndShowReportViewForReport(report)
-
-  assert.match(
-    $('#test-container').text(),
-    new RegExp(".*#{title}.*")
-  )
-
-  view.close()
-)
-
-test("Can see a report's brief", ->
-  briefText = "Hey, I'm the brief"
-  report = new Backbone.Models.Report(brief: briefText)
-
-  view = createAndShowReportViewForReport(report)
-
-  assert.match(
-    $('#test-container').text(),
-    new RegExp(".*#{briefText}.*")
-  )
-
-  view.close()
-)
-
-test("If report cover image exists, can view")
-test("If report cover image doesn't exist, can see no image")
-
-test("Report sections views are rendered", ->
-  section = new Backbone.Models.Section()
-  report = new Backbone.Models.Report(sections: [section])
-
-  view = createAndShowReportViewForReport(report)
-
-  subViewExists = false
-  for subView in view.subViews
-    if subView.constructor.name == "SectionView"
-      subViewExists = true
-
-  assert subViewExists
-
-  view.close()
-)
-
-test("Can navigate to Dashboard, Reports, Indicators and Bookmarks")
-
-assert = chai.assert
-
-createAndShowSectionViewForSection = (section) ->
-  view = new Backbone.Views.SectionView(section: section)
-  view.render()
-  $('#test-container').html(view.el)
-  return view
-
-suite('Section View')
-
-test("Can see the section title", ->
-  title = "My Lovely Section"
-  section = new Backbone.Models.Section(title: title)
-
-  view = createAndShowSectionViewForSection(section)
-
-  assert.match(
-    $('#test-container').text(),
-    new RegExp(".*#{title}.*")
-  )
-
-  view.close()
-)
-
-test("Can see the section visualisation")
-test("Can see the section narrative")
-test("Can edit the section")
-test("Can view report containing this section")
-test("Can navigate to Dashboard, Reports, Indicators and Bookmarks")


improve doc on app.cofee @ skel

improve doc on app.cofee @ skel

--- cli/templates/app_skel/src/app/app.coffee
+++ cli/templates/app_skel/src/app/app.coffee
@@ -6,7 +6,7 @@
 module.exports = class App extends Theoricus

   constructor:( Settings, Routes )->
-    # don't forget to extend Theoricus
+    # don't forget to extend Theoricus and pass Settings and Routes !
     super Settings, Routes
     @start()


Initial notification controller event listener

--- client/app/lib/socialapicontroller.coffee
+++ client/app/lib/socialapicontroller.coffee
@@ -20,6 +20,13 @@
     @_inScreenMap   = {}

     super options, data
+
+    @bindNotificationEvents()
+
+
+  bindNotificationEvents: ->
+
+    kd.singletons.notificationController

   getPrefetchedData: (dataPath) ->


adding some initial comments

adding some initial comments

--- backbone.debug.coffee
+++ backbone.debug.coffee
@@ -6,6 +6,7 @@
     @_hookEvents()
     @_hookSync()

+  ##### Object Accessors
   collections: =>
     @_objects.Collections

@@ -18,18 +19,20 @@
   routers: =>
     @_objects.Router

-  on: =>
+  ##### Toggle Logging
+  on: (option) =>
     true

-  off: =>
+  off: (option)=>
     true

+  ##### Relevant Version Info
   info:
     'Backbone.debug': '0.1.0'
     'Backbone': window.Backbone.VERSION
     'Underscore': window._.VERSION

-
+  ##### Console Log Wrappers
   _logObj: (obj) =>
     console.log obj, _.keys(obj._callbacks)

@@ -39,9 +42,11 @@
   _logSync: (obj, method, model, options) =>
     console.log "Sync - #{method}", obj

+  ##### Hook Backbone.sync
   _hookSync: =>
     @_hookMethod('sync', @_logSync)

+  ##### Hook Backbone Events
   _hookEvents: =>
     @_hookPrototype('Collection', 'trigger', @_logEvent)
     @_hookPrototype('Model', 'trigger', @_logEvent)
@@ -51,9 +56,11 @@
   _saveObjects: (type, method, object) =>
     @_objects[type][object.constructor.name + ':' + object.cid] = object

+  ##### Track Object Creation
   _trackObjects: =>
     @_hookPrototype('Model', 'constructor', @_saveObjects)

+  # Hook Backbone Method
   _hookMethod: (method, action) =>
     original = window.Backbone[method]

@@ -61,6 +68,7 @@
       original.apply(this, arguments)
       action(method, this, arguments)

+  # Hook Backbone Prototye Method
   _hookPrototype: (object, method, action) =>
     original = window.Backbone[object].prototype[method]

@@ -68,4 +76,5 @@
       original.apply(this, arguments)
       action(object, method, this, arguments)

+# Initialize Backbone.debug
 window.Backbone.debug = new Backbone.Debug()


:police_car::snail: Updated in browser at strd6.github.io/editor

--- pixie.cson
+++ pixie.cson
@@ -8,7 +8,7 @@
 dependencies:
   "jquery-utils": "STRd6/jquery-utils:v0.1.2"
   runtime: "STRd6/runtime:v0.1.1"
-  "touch-canvas": "STRd6/touch-canvas:v0.2.0-alpha.10"
+  "touch-canvas": "STRd6/touch-canvas:v0.2.0-alpha.11"
   "commando": "STRd6/commando:v0.9.0"
 width: 480
 height: 320


editSummaryView: add placeholder text

editSummaryView: add placeholder text

--- coffee/src/views/edit_summary_view.coffee
+++ coffee/src/views/edit_summary_view.coffee
@@ -15,8 +15,8 @@

-      <input type="text" class="title">
-      <textarea class="description"></textarea>
+      <input type="text" placeholder="title" class="title">
+      <textarea placeholder="description" class="description"></textarea>

     '''


EditorView.spec: render it

EditorView.spec: render it

--- coffee/test/views/editor_view.spec.coffee
+++ coffee/test/views/editor_view.spec.coffee
@@ -5,8 +5,35 @@
 describe 'acorn.player.EditorView', ->
   EditorView = acorn.player.EditorView

+  # model for ContentView contruction
+  model =
+    acornModel: new Backbone.Model
+      thumbnail: acorn.config.img.acorn
+      acornid: 'nyfskeqlyx'
+      title: 'The Differential'
+    shellModel: new Backbone.Model
+
+  # emulate shell, object with a ContentView property
+  shell = ContentView: athena.lib.View
+  model.shellModel.shell = shell
+
+  # options for ContentView contruction
+  options = model: model
+
   it 'should be part of acorn.player', ->
     expect(acorn.player.EditorView).toBeDefined()

   it 'should derive from athena.lib.View', ->
     expect(athena.lib.util.derives EditorView, athena.lib.View).toBe true
+
+  it 'should look good', ->
+    # setup DOM
+    acorn.util.appendCss()
+    $player = $('<div>').addClass('acorn-player').appendTo('body')
+
+    # add a SplashView into the DOM to see how it looks.
+    view = new EditorView options
+    view.$el.width 600
+    view.$el.height 600
+    view.render()
+    $player.append view.el