stabilizing commands.

stabilizing commands.

--- lib/marie.coffee
+++ lib/marie.coffee
@@ -54,7 +54,7 @@
 				'remove': @removeApi
 			'list': @list
 			'db':
-				'configure': @configure
+				'set': @configureStorage
 			'module':
 				'add': @addModule
 				'remove': @removeModule
@@ -65,30 +65,21 @@
 	route: ->
 		len = @args.length - 1
 		route = @args[2]
-
 		if @routes[route]?
 			arg = @args[3] or null
-			if @routes[route]? then @routes[route](arg)
+			opt = @args[4] or null
+			if @routes[route]? then @routes[route] arg, opt
 		else
 			cmd = @args[3] or null
 			arg = @args[4] or null
 			key = @args[5] or null
 			opt = @args[6] or null
-
-			if cmd is 'list' then @list route, arg, key, opt
-			else if @commands[arg][cmd] then @commands[arg][cmd] route, key, opt
+			if cmd and cmd is 'list' then @list route, arg, key, opt
+			else if cmd and cmd is 'set' then @configureMore route, arg, key, opt
+			else if cmd and arg and @commands[arg][cmd]? then @commands[arg][cmd] route, key, opt
 			else
 				ui.notice 'Invalid command.'
 				ui.notice 'load help'
-
-			# console.log ''
-			# ui.notice 'app command'
-			# ui.notice "route: #{route}"
-			# ui.notice "command: #{cmd}"
-			# ui.notice "arg: #{arg}"
-			# ui.notice "key: #{key}"
-			# ui.notice "opt: #{opt}"
-			# console.log ''

 	###
 	Confgiure the default express/sails application framework
@@ -450,9 +441,9 @@
 	Configure `remove` app command handler. Remove app from system
 	@example `marie remove dc-web`
 	###
-	remove: =>
-		if not not @args[3]
-			if not not @args[4] and @args[4].match /\-f/ then @_remove()
+	remove: (arg, opt) =>
+		if not not arg
+			if not not opt and opt.match /\-f/ then @_remove arg
 			else
 				ui.warn 'Are you sure?'
 				utils.prompt.start()
@@ -460,14 +451,14 @@
 				ui.line()
 				utils.prompt.get [input], (err, result) =>
 					ui.line()
-					if result[input].match(/^y/i) then @_remove()
+					if result[input].match(/^y/i) then @_remove arg
 		else
 			ui.error 'Missing argument.'
 	###
 	remove
 	###
-	_remove: =>
-		App.remove @args[3], (err, success) =>
+	_remove: (arg) =>
+		App.remove arg, (err, success) =>
 			if err then utils.throwError err
 			else ui.ok success

@@ -566,16 +557,14 @@
 	@example `marie dc-web add api user`
 	###
 	addApi: (arg, api) =>
-		# console.log arg
-		# console.log api
-		# console.log key
-		# console.log opt
-		App.addApi arg, api, (err, app) =>
-			if err then utils.throwError err
-			else
-				@app = app
-				@restart()
-				ui.ok "Added api #{api}"
+		if not not api
+			App.addApi arg, api, (err, app) =>
+				if err then utils.throwError err
+				else
+					@app = app
+					@restart()
+					ui.ok "Added api #{api}"
+		else ui.error 'Missing argument.'

 	###
 	Configure remove api method
@@ -583,12 +572,14 @@
 	@example `marie dc-web remove api user`
 	###
 	removeApi: (arg, api) =>
-		App.removeApi arg, api, (err, app) =>
-			if err then utils.throwError err
-			else
-				@app = app
-				@restart()
-				ui.ok "Removed api #{api}"
+		if not not api
+			App.removeApi arg, api, (err, app) =>
+				if err then utils.throwError err
+				else
+					@app = app
+					@restart()
+					ui.ok "Removed api #{api}"
+		else ui.error 'Missing argument.'

 	###
 	Configure add module method
@@ -596,16 +587,15 @@
 	@example `marie dc-web add module bower`
 	###
 	addModule: (arg, pkg, opt) =>
-		# console.log arg
-		# console.log pkg
-		# console.log opt
-		ui.write "Adding `#{pkg}` module..."
-		App.addModule arg, pkg, opt, (err, app) =>
-			if err then utils.throwError err
-			else
-				@app = app
-				@restart()
-				ui.ok "Added module #{pkg}"
+		if not not pkg
+			ui.write "Adding `#{pkg}` module..."
+			App.addModule arg, pkg, opt, (err, app) =>
+				if err then utils.throwError err
+				else
+					@app = app
+					@restart()
+					ui.ok "Added module #{pkg}"
+		else ui.error 'Missing argument.'

 	###
 	Configure remove module method
@@ -613,13 +603,15 @@
 	@example `marie dc-web remove module bower`
 	###
 	removeModule: (arg, pkg, opt) =>
-		ui.write "Removing `#{pkg}` module..."
-		App.removeModule arg, pkg, opt, (err, app) =>
-			if err then utils.throwError err
-			else
-				@app = app
-				@restart()
-				ui.ok "Removed module #{pkg}"
+		if not not pkg
+			ui.write "Removing `#{pkg}` module..."
+			App.removeModule arg, pkg, opt, (err, app) =>
+				if err then utils.throwError err
+				else
+					@app = app
+					@restart()
+					ui.ok "Removed module #{pkg}"
+		else ui.error 'Missing argument.'

 	###
 	Configure list module method
@@ -655,9 +647,9 @@
 	###
 	Display system log method
 	###
-	log: =>
+	log: (arg) =>
 		file = "#{utils.root}/config/.log"
-		if @args[3] and @args[3].match /clear/i
+		if arg and arg.match /clear/i
 			utils.fs.stat file, (err, stats) ->
 				if err then ui.notice 'Log is empty'
 				else
@@ -673,9 +665,7 @@
 	###
 	cli configure command handler
 	###
-	configure: (arg, key) =>
-		# name = @args[3]
-		# key = @args[4]
+	configureMore: (arg, key, opt) =>
 		App.find arg, (error, app) =>
 			if error then utils.throwError error
 			else if app


handle no callback being passed to save() and delete() methods

--- lib/model.coffee
+++ lib/model.coffee
@@ -94,7 +94,7 @@

   save: (callback) ->
     if @_dirty.length == 0
-      callback false
+      callback false if callback
       return

     @fire "beforeSave"
@@ -103,7 +103,7 @@
       @_dirty = []

       @fire "afterSave"
-      callback success
+      callback success if callback

   delete: (callback) ->
     @fire "beforeDelete"
@@ -111,7 +111,7 @@
       if success
         @fire "afterDelete"

-      callback success, err
+      callback success, err if callback

   type: -> @constructor.type()


Add integration tests for smalldatetime type.

--- test/integration/datatypes-in-results-test.coffee
+++ test/integration/datatypes-in-results-test.coffee
@@ -71,6 +71,12 @@
 exports.datetimeNull = (test) ->
   execSql(test, "select cast(null as datetime)", null)

+exports.smallDatetime = (test) ->
+  execSql(test, "select cast('2011-12-4 10:04:23' as smalldatetime)", new Date('December 4, 2011 10:04:00'))
+
+exports.smallDatetimeNull = (test) ->
+  execSql(test, "select cast(null as smalldatetime)", null)
+
 exports.numericSmallValue = (test) ->
   execSql(test, "select cast(9.3 as numeric(3,2))", 9.3)


Fix describe text in spec.

Fix describe text in spec.

--- spec/javascripts/disable_checker_spec.coffee
+++ spec/javascripts/disable_checker_spec.coffee
@@ -47,7 +47,7 @@
       it "leaves input enabled", ->
         expect(@inputToDisable).not.toBeDisabled()

-    describe "radio is checked", ->
+    describe "checkbox is checked", ->
       it "disables input", ->
         @disableCheckbox.trigger("click")
         expect(@inputToDisable).toBeDisabled()
@@ -59,13 +59,13 @@
         @disableCheckbox.trigger("click")
         expect(@inputToDisable.val()).toEqual ""

-    describe "radio is checked then unchecked", ->
+    describe "checkbox is checked then unchecked", ->
       it "enables input", ->
         @disableCheckbox.trigger("click")
         @disableCheckbox.trigger("click")
         expect(@inputToDisable).not.toBeDisabled()

-  describe "when radio checked", ->
+  describe "when checkbox checked", ->
     describe "after initialization", ->
       it "disables input", ->
         element = fixtureHtml(true)


Update atom prefs

Update atom prefs

--- apps/atom/atom.symlink/config.cson
+++ apps/atom/atom.symlink/config.cson
@@ -18,10 +18,5 @@
     'monokai-tweaked-syntax'
   ]
   'projectHome': '/Users/MoOx/Sync/Development'
-  'disabledPackages': [
-    'autocomplete-plus'
-  ]
-'autosave':
-  'enabled': true
-'jshint':
-  'validateOnlyOnSave': true
+'autosave': {}
+'autocomplete-plus': {}


Help dialog; re-order and tweak command descriptions.

- Re-order commands such that we keep like with like, and have the more
  important commands nearer the top.

- Re-word some command descriptions such that we use the same words for
  the the same thing consistently.

- Move "View Source" to the "Miscellaneous" category.

- Make some commands "advanced commands".

--- background_scripts/commands.coffee
+++ background_scripts/commands.coffee
@@ -118,27 +118,26 @@
     pageNavigation:
       ["scrollDown",
       "scrollUp",
-      "scrollLeft",
-      "scrollRight",
       "scrollToTop",
       "scrollToBottom",
-      "scrollToLeft",
-      "scrollToRight",
       "scrollPageDown",
       "scrollPageUp",
       "scrollFullPageUp",
       "scrollFullPageDown",
+      "scrollLeft",
+      "scrollRight",
+      "scrollToLeft",
+      "scrollToRight",
       "reload",
-      "toggleViewSource",
       "copyCurrentUrl",
       "openCopiedUrlInCurrentTab",
       "openCopiedUrlInNewTab",
       "goUp",
       "goToRoot",
       "enterInsertMode",
-      "passNextKey",
       "enterVisualMode",
       "enterVisualLineMode",
+      "passNextKey",
       "focusInput",
       "LinkHints.activateMode",
       "LinkHints.activateModeToOpenInNewTab",
@@ -156,32 +155,33 @@
     vomnibarCommands:
       ["Vomnibar.activate",
       "Vomnibar.activateInNewTab",
-      "Vomnibar.activateTabSelection",
       "Vomnibar.activateBookmarks",
       "Vomnibar.activateBookmarksInNewTab",
+      "Vomnibar.activateTabSelection",
       "Vomnibar.activateEditUrl",
       "Vomnibar.activateEditUrlInNewTab"]
     findCommands: ["enterFindMode", "performFind", "performBackwardsFind"]
     historyNavigation:
       ["goBack", "goForward"]
     tabManipulation:
-      ["nextTab",
+      ["createTab",
       "previousTab",
+      "nextTab",
       "visitPreviousTab",
       "firstTab",
       "lastTab",
-      "createTab",
       "duplicateTab",
+      "togglePinTab",
       "removeTab",
       "restoreTab",
       "moveTabToNewWindow",
-      "togglePinTab",
       "closeTabsOnLeft","closeTabsOnRight",
       "closeOtherTabs",
       "moveTabLeft",
       "moveTabRight"]
     misc:
-      ["showHelp"]
+      ["showHelp",
+      "toggleViewSource"]

   # Rarely used commands are not shown by default in the help dialog or in the README. The goal is to present
   # a focused, high-signal set of commands to the new and casual user. Only those truly hungry for more power
@@ -192,12 +192,12 @@
     "moveTabToNewWindow",
     "goUp",
     "goToRoot",
-    "focusInput",
     "LinkHints.activateModeWithQueue",
     "LinkHints.activateModeToDownloadLink",
     "Vomnibar.activateEditUrl",
     "Vomnibar.activateEditUrlInNewTab",
     "LinkHints.activateModeToOpenIncognito",
+    "LinkHints.activateModeToCopyLinkUrl",
     "goNext",
     "goPrevious",
     "Marks.activateCreateMode",
@@ -207,6 +207,8 @@
     "closeTabsOnLeft",
     "closeTabsOnRight",
     "closeOtherTabs",
+    "enterVisualLineMode",
+    "toggleViewSource",
     "passNextKey"]

 defaultKeyMappings =
@@ -306,8 +308,8 @@
   scrollToLeft: ["Scroll all the way to the left", { noRepeat: true }]
   scrollToRight: ["Scroll all the way to the right", { noRepeat: true }]

-  scrollPageDown: ["Scroll a page down"]
-  scrollPageUp: ["Scroll a page up"]
+  scrollPageDown: ["Scroll a half page down"]
+  scrollPageUp: ["Scroll a half page up"]
   scrollFullPageDown: ["Scroll a full page down"]
   scrollFullPageUp: ["Scroll a full page up"]

@@ -323,7 +325,7 @@
   enterVisualMode: ["Enter visual mode", { noRepeat: true }]
   enterVisualLineMode: ["Enter visual line mode", { noRepeat: true }]

-  focusInput: ["Focus the first text box on the page. Cycle between them using tab"]
+  focusInput: ["Focus the first text input on the page"]

   "LinkHints.activateMode": ["Open a link in the current tab"]
   "LinkHints.activateModeToOpenInNewTab": ["Open a link in a new tab"]
@@ -370,16 +372,16 @@
   moveTabLeft: ["Move tab to the left", { background: true }]
   moveTabRight: ["Move tab to the right", { background: true }]

-  "Vomnibar.activate": ["Open URL, bookmark, or history entry", { topFrame: true }]
-  "Vomnibar.activateInNewTab": ["Open URL, bookmark, history entry, in a new tab", { topFrame: true }]
+  "Vomnibar.activate": ["Open URL, bookmark or history entry", { topFrame: true }]
+  "Vomnibar.activateInNewTab": ["Open URL, bookmark or history entry in a new tab", { topFrame: true }]
   "Vomnibar.activateTabSelection": ["Search through your open tabs", { topFrame: true }]
   "Vomnibar.activateBookmarks": ["Open a bookmark", { topFrame: true }]
   "Vomnibar.activateBookmarksInNewTab": ["Open a bookmark in a new tab", { topFrame: true }]
   "Vomnibar.activateEditUrl": ["Edit the current URL", { topFrame: true }]
   "Vomnibar.activateEditUrlInNewTab": ["Edit the current URL and open in a new tab", { topFrame: true }]

-  nextFrame: ["Cycle forward to the next frame on the page", { background: true }]
-  mainFrame: ["Select the tab's main/top frame", { topFrame: true, noRepeat: true }]
+  nextFrame: ["Select the next frame on the page", { background: true }]
+  mainFrame: ["Select the page's main/top frame", { topFrame: true, noRepeat: true }]

   "Marks.activateCreateMode": ["Create a new mark", { noRepeat: true }]
   "Marks.activateGotoMode": ["Go to a mark", { noRepeat: true }]


Improve global detection to handle web workers, and clarify logic

--- lib/resin.coffee
+++ lib/resin.coffee
@@ -30,6 +30,15 @@
 RESIN_SDK_HAS_USED_SHARED_OPTIONS = 'RESIN_SDK_HAS_USED_SHARED_OPTIONS'
 RESIN_SDK_HAS_SET_SHARED_OPTIONS = 'RESIN_SDK_HAS_SET_SHARED_OPTIONS'

+# Use window (web)/self (web worker)/global (node) as appropriate
+globalEnv = if typeof window != 'undefined'
+	window
+else if typeof self != 'undefined'
+	self
+else if typeof global != 'undefined'
+	global
+else null
+
 ###*
 # @namespace resin
 # @description
@@ -251,16 +260,14 @@
 # });
 ###
 getSdk.setSharedOptions = (opts) ->
-	root = if window? then window else global
-
-	if root[RESIN_SDK_HAS_USED_SHARED_OPTIONS]
+	if globalEnv[RESIN_SDK_HAS_USED_SHARED_OPTIONS]
 		console.error('Shared SDK options have already been used. You may have a race condition in your code.')

-	if root[RESIN_SDK_HAS_SET_SHARED_OPTIONS]
+	if globalEnv[RESIN_SDK_HAS_SET_SHARED_OPTIONS]
 		console.error('Shared SDK options have already been set. You may have a race condition in your code.')

-	root[RESIN_SDK_SHARED_OPTIONS] = opts
-	root[RESIN_SDK_HAS_SET_SHARED_OPTIONS] = true
+	globalEnv[RESIN_SDK_SHARED_OPTIONS] = opts
+	globalEnv[RESIN_SDK_HAS_SET_SHARED_OPTIONS] = true

 ###*
 # @summary Create an SDK instance using shared default options
@@ -280,11 +287,9 @@
 # const sdk = resin.fromSharedOptions();
 ###
 getSdk.fromSharedOptions = ->
-	root = if window? then window else global
-
-	sharedOpts = root[RESIN_SDK_SHARED_OPTIONS]
-
-	root[RESIN_SDK_HAS_USED_SHARED_OPTIONS] = true
+	sharedOpts = globalEnv[RESIN_SDK_SHARED_OPTIONS]
+
+	globalEnv[RESIN_SDK_HAS_USED_SHARED_OPTIONS] = true

 	getSdk(sharedOpts)


adds exclude_from_indexes setting

adds exclude_from_indexes setting

--- lib/setup.coffee
+++ lib/setup.coffee
@@ -111,7 +111,8 @@
       'receive_newsletter',
       'post_address',
       'show_tour',
-      'is_pro'
+      'is_pro',
+      'exclude_from_indexes'
     ]

   app.use artsyError.helpers


fix store room deletions

fix store room deletions

--- both/methods/store/language.coffee
+++ both/methods/store/language.coffee
@@ -41,9 +41,10 @@
 		if Meteor.isServer
 			check { userId: Meteor.userId(), projectId: projectId }, isStoreAdmin
 			check short, String
+			check language, String

 		Projects.update
 			_id: projectId
-			'items.short': short
+			'store.items.short': short
 		,
 			$pull: 'store.items.$.languages': short: language


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/core_object.coffee
+++ src/core_object.coffee
@@ -150,6 +150,7 @@
           # Attempt to discover module name

         unless I.included_modules.include moduleName
+          I.in
           self.extend Module(I, self)

       return self


:bug: overlook when utils code layout changed.

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -90,7 +90,7 @@
   getKeystrokeForEvent
   isLinewiseRange
   rangeToBeginningOfFileFromPoint
-  rangeToBeginningOfFileFromPoint
+  rangeToEndOfFileFromPoint
   isIncludeNonEmptySelection
   sortRanges
   setSelectionBufferRangeSafely


add pick() utility function

add pick() utility function

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -272,6 +272,14 @@
     when (row < 0) then 0
     when (row > vimLastBufferRow) then vimLastBufferRow
     else row
+
+# Compensate lack of ternaly operator
+# e.g. pick(['one', 'two'], true) get 'one'
+pick = (choice, boolean) ->
+  if boolean
+    choice[0]
+  else
+    choice[1]

 module.exports = {
   include
@@ -314,4 +322,5 @@
   getValidVimRow
   moveCursorToFirstCharacterAtRow
   countChar
+  pick
 }


using path.join to convert forward-slashes to OS-sepcific path separator

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -32,7 +32,7 @@
     # Ensure that we're dealing with absolute paths across the board
     files = files.map (f) -> path.resolve resolveRoot, f
     # And that the strip prefixes all end with a /, to avoid a target path being absolute.
-    stripPrefixes = stripPrefixes.map (p) -> "#{path.resolve resolveRoot, p}/"
+    stripPrefixes = stripPrefixes.map (p) -> path.join( "#{path.resolve resolveRoot, p}/" )

     # Prefixes are stripped in order of most specific to least (# of directories deep)
     prefixes = stripPrefixes.sort (a,b) => @pathDepth(b) - @pathDepth(a)


Cleaned up binary detection.

Cleaned up binary detection.

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -31,22 +31,21 @@

   @detectBinaries: ->
     for pkg in ["cargo", "racer", "multirust", "rustc"]
-      console.log(pkg)
-      data = @runCommandOut("which", [pkg])
-      console.log(data)
-      if data.status == 0 && data.stdoutData.length >= 0
+      data = @findBinary([pkg])
+
+      if data.status == 0 && data.stdoutData.length > 0
         switch pkg
           when "cargo"
-            atom.config.set("tokamak.cargoBinPath", data.stdoutData.replace(/^\s+|\s+$/g, ""))
-            atom.config.set("linter-rust.cargoPath", data.stdoutData.replace(/^\s+|\s+$/g, ""))
+            atom.config.set("tokamak.cargoBinPath", data.stdoutData)
+            atom.config.set("linter-rust.cargoPath", data.stdoutData)
           when "racer"
-            atom.config.set("tokamak.racerBinPath", data.stdoutData.replace(/^\s+|\s+$/g, ""))
-            atom.config.set("racer.racerBinPath", data.stdoutData.replace(/^\s+|\s+$/g, ""))
+            atom.config.set("tokamak.racerBinPath", data.stdoutData)
+            atom.config.set("racer.racerBinPath", data.stdoutData)
           when "multirust"
-            atom.config.set("tokamak.multirustBinPath", data.stdoutData.replace(/^\s+|\s+$/g, ""))
+            atom.config.set("tokamak.multirustBinPath", data.stdoutData)
           when "rustc"
-            atom.config.set("tokamak.rustcBinPath", data.stdoutData.replace(/^\s+|\s+$/g, ""))
-            atom.config.set("linter-rust.rustcPath", data.stdoutData.replace(/^\s+|\s+$/g, ""))
+            atom.config.set("tokamak.rustcBinPath", data.stdoutData)
+            atom.config.set("linter-rust.rustcPath", data.stdoutData)
       else
         atom.notifications.addError("Tokamak: #{pkg} is not installed or not found in PATH",
         {
@@ -56,6 +55,17 @@
           ERROR: #{data.stderrData}"
           dismissable: true
         })
+
+  @findBinary: (pkg) ->
+    if process.platform is "win32"
+      return @runCommandOut("where", [pkg]);
+    else
+      data = @runCommandOut("which", [pkg]);
+
+      if data.status == 0 && data.stdoutData.length >= 0
+        data.stdoutData = data.stdoutData.replace(/^\s+|\s+$/g, "")
+
+      return data

   @watchConfig: ->
     atom.config.onDidChange "tokamak.autocompleteBlacklist", ({newValue, oldValue}) ->


use close event for pygmentize child process

this event is not called until all stdio pipes for the child have closed
and the process has exit, thereby ensuring all output from pygmentize is
captured

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -144,7 +144,7 @@
     pygmentize.stdout.addListener 'data', (data) =>
       result += data.toString()

-    pygmentize.addListener 'exit', (args...) =>
+    pygmentize.addListener 'close', (args...) =>
       # pygments spits it out wrapped in `<div class="highlight"><pre>...</pre></div>`.  We want to
       # manage the styling ourselves, so remove that.
       result = result.replace('

', '').replace('

', '')


adjusted modal to be better for subclasses.

--- app/assets/javascripts/habberdash/lib/modal.js.coffee
+++ app/assets/javascripts/habberdash/lib/modal.js.coffee
@@ -2,10 +2,6 @@
   minWidth: 400

   @instance: null
-
-  events:
-    'tap .modal-close': 'hide'
-

   constructor: (options) ->
     if Habberdash.Modal.instance
@@ -38,6 +34,7 @@
       options.success = (content) =>
         @loadContent(content)

+    @$('.modal-close').on('click', @onClose)
     @$overlay.on('click', @onClose)
     $(document).on('keydown', @onClose)
     $(window).on('resize', @position)


Add last_digits, month + year to response

Related to #113

--- app/assets/javascripts/store/gateway/stripe.js.coffee
+++ app/assets/javascripts/store/gateway/stripe.js.coffee
@@ -33,4 +33,7 @@
     # insert the token into the form so it gets submitted to the server
     paymentMethodId = Spree.stripePaymentMethod.prop('id').split("_")[2]
     Spree.stripePaymentMethod.append("<input type='hidden' class='stripeToken' name='payment_source[" + paymentMethodId  + "][gateway_payment_profile_id]' value='" + token + "'/>");
+    Spree.stripePaymentMethod.append("<input type='hidden' class='stripeToken' name='payment_source[" + paymentMethodId  + "][last_digits]' value='" + response.card.last4 + "'/>");
+    Spree.stripePaymentMethod.append("<input type='hidden' class='stripeToken' name='payment_source[" + paymentMethodId  + "][month]' value='" + response.card.exp_month + "'/>");
+    Spree.stripePaymentMethod.append("<input type='hidden' class='stripeToken' name='payment_source[" + paymentMethodId  + "][year]' value='" + response.card.exp_year + "'/>");
     Spree.stripePaymentMethod.parents("form").get(0).submit();


Made script/rerun more awesomer

Made script/rerun more awesomer

--- script/rerun.coffee
+++ script/rerun.coffee
@@ -55,7 +55,14 @@
       throw err if err
       value = msgpack.unpack(buf) if buf
       console.log 'Done. Got:', value
-      r.end()
+      r.lrange 'errors', 0, 0, (err, list) ->
+        throw err if err
+        if list.length
+          err = JSON.parse list[0].toString()
+          console.log "An error:", err
+        else
+          console.log "No errors!"
+        r.end()

 listen_for_completion = ->
   manager.request seed
@@ -69,12 +76,12 @@

 # Delete all the collected intermediate keys, then call `rerun`.
 delete_keys = ->
+  to_delete.push 'errors'
   if to_delete.length
     chunks = _(to_delete).in_groups_of(10000)
     wrap_up = ->
-      console.log "Deleted #{to_delete.length/4} keys"
+      console.log "Deleted #{(to_delete.length-1)/4} keys"
       rerun()
-    console.log chunks
     each chunks, wrap_up, (chunk, next) ->
       r.del chunk..., next
   else


Dickbutt

Dickbutt

--- scripts/dees.coffee
+++ scripts/dees.coffee
@@ -2,7 +2,7 @@

 module.exports = (robot) ->
   robot.enter (msg) ->
-    msg.send JSON.stringify(msg)
+    msg.send inspect(msg)
     # If its dusya optionally follwed by ANYTHING
     # if /^dusya/.test(msg.user.name.toLowerCase())
     #  msg.send "YOUR NUTS"


shuffle

shuffle

--- scripts/food.coffee
+++ scripts/food.coffee
@@ -37,12 +37,14 @@
 module.exports = (robot) ->

   robot.respond /feed me (.+)/i, (msg) ->
-    gmap.keyword = msg.match[0] or '便當'
-
     param = ("#{k}=#{v}" for k, v of gmap).join '&'

     getJSON("#{url}#{param}")
       .fail (e) ->
         print e
       .done ({results}) ->
-        msg.send _.pluck results, 'name'
+        msg.send _.chain(results)
+          .pluck('name')
+          .shuffle()
+          .first(3)
+          .value()


Add test for ignoring name anchors

Add test for ignoring name anchors

--- test/src/link_grabber_test.coffee
+++ test/src/link_grabber_test.coffee
@@ -1,9 +1,13 @@
 describe 'LinkGrabber', ->

-	describe 'with links', ->
+	describe 'with html input', ->

 		it 'should find all links', ->
 			links = LinkGrabber.fromHTMLString('
Lorem ipsum dolor lorem ipsum
').allLinks()
 			links.should.have.lengthOf(2)
 			links[0].should.equal("http://foo/")
-			links[1].should.equal("http://bar/")+			links[1].should.equal("http://bar/")
+
+		it 'should ignore anchor name tags', ->
+			links = LinkGrabber.fromHTMLString('foo').allLinks()
+			links.should.have.lengthOf(0)


Add a failsafe in case this ever gets required in the browser

--- tests/batman/node_request_test.coffee
+++ tests/batman/node_request_test.coffee
@@ -1,3 +1,5 @@
+return unless IN_NODE
+
 oldGetModule = Batman.Request::getModule

 QUnit.module 'Batman.Request'


&R -> &s

&R -> &s

--- menus/linux.cson
+++ menus/linux.cson
@@ -127,7 +127,7 @@
       { type: 'separator' }
       { label: '&Increase Font Size', command: 'window:increase-font-size' }
       { label: '&Decrease Font Size', command: 'window:decrease-font-size' }
-      { label: '&Reset Font Size', command: 'window:reset-font-size' }
+      { label: 'Re&set Font Size', command: 'window:reset-font-size' }
       { type: 'separator' }
       { label: 'Toggle Soft &Wrap', command: 'editor:toggle-soft-wrap' }
     ]


Add a comma

Add a comma

--- src/webpack.config.coffee
+++ src/webpack.config.coffee
@@ -539,7 +539,7 @@
                     { loader: 'coffee-loader' }
                 ]
             },
-            { test: /\.(js|jsx)$/, loader: 'babel-loader' }
+            { test: /\.(js|jsx)$/, loader: 'babel-loader' },
             { test: /\.less$/,   use: ["style-loader", "css-loader", "less-loader?#{cssConfig}"] },
             { test: /\.scss$/,   use: ["style-loader", "css-loader", "sass-loader?#{cssConfig}"] },
             { test: /\.sass$/,   use: ["style-loader", "css-loader", "sass-loader?#{cssConfig}&indentedSyntax"] },


Add items schemas to arrays in workspaceView

--- src/workspace-view.coffee
+++ src/workspace-view.coffee
@@ -71,15 +71,21 @@
     ignoredNames:
       type: 'array'
       default: [".git", ".hg", ".svn", ".DS_Store", "Thumbs.db"]
+      items:
+        type: 'string'
     excludeVcsIgnoredPaths:
       type: 'boolean'
       default: true
     disabledPackages:
       type: 'array'
       default: []
+      items:
+        type: 'string'
     themes:
       type: 'array'
       default: ['atom-dark-ui', 'atom-dark-syntax']
+      items:
+        type: 'string'
     projectHome:
       type: 'string'
       default: path.join(fs.getHomeDirectory(), 'github')


Implement method to detection for watching the owner

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -1262,17 +1262,28 @@
         @mySnapshot.delete paneHash  if paneHash

+  ###*
+   * Am I watching to change's owner?
+   *
+   * @param {string} origin  Nickname of the change's owner
+   * @return {boolean}
+  ###
+  amIWatchingChangeOwner: (origin) ->
+
+    return  if not @myWatchMap or not @myWatchMap.keys()
+
+    @myWatchMap.keys().indexOf(origin) > -1
+
+
   handleChange: (change) ->

     { context, origin, type, rtmHash } = change

     return if not context or not origin or (origin is nick() and rtmHash is @rtm.hash)

-    amIWatchingChangeOwner = @myWatchMap.keys().indexOf(origin) > -1
-
     mustSyncChanges = [ 'CursorActivity', 'FileSaved' ]

-    if amIWatchingChangeOwner or type in mustSyncChanges
+    if @amIWatchingChangeOwner(origin) or type in mustSyncChanges
       targetPane = @getPaneByChange change

       if type is 'NewPaneCreated'


Exclude player controls from scroll interactions (#632)

--- app/views/play/level/PlayGameDevLevelView.ozar.coffee
+++ app/views/play/level/PlayGameDevLevelView.ozar.coffee
@@ -47,11 +47,6 @@
       creatorString: ''
       isOwner: false
     })
-
-    $(window).keydown (event) ->
-      # prevent space from scrolling on the page since it can be used as a control in the game.
-      if (event.keyCode == 32 && event.target == document.body)
-        event.preventDefault()

     if utils.getQueryVariable 'dev'
       @supermodel.shouldSaveBackups = (model) ->  # Make sure to load possibly changed things from localStorage.
@@ -152,7 +147,7 @@
       worldCreationOptions = {spells: @spells, preload: false, realTime: true, justBegin: false, keyValueDb: @session.get('keyValueDb') ? {}, synchronous: true}
       @god.createWorld(worldCreationOptions)
       @willUpdateFrontEnd = true
-
+      @subscribeShortcuts()
     .catch (e) =>
       throw e if e.stack
       @state.set('errorMessage', e.message)
@@ -249,12 +244,23 @@
       @session.updateKeyValueDb(_.cloneDeep(@surface.world.keyValueDb))
       @session.saveKeyValueDb()

+  subscribeShortcuts: ->
+    # Prevent controls (space and arrow keys) from scrolling the page
+    # since they can be used controls when playing the game
+    key?('space, left, up, right, down', 'play-game-dev-level-view-shortcut-scope', (event) ->
+      if event.target == document.body
+        event.preventDefault()
+    )
+
+  unsubscribeShortcuts: ->
+    key?.deleteScope('play-game-dev-level-view-shortcut-scope')
+
   destroy: ->
+    @unsubscribeShortcuts()
     @levelLoader?.destroy()
     @surface?.destroy()
     @god?.destroy()
     @goalManager?.destroy()
     @scriptManager?.destroy()
     delete window.world # not sure where this is set, but this is one way to clean it up
-    $(window).off("keydown")
     super()


tested restricted redirect

tested restricted redirect

--- ui-menu.spec.coffee
+++ ui-menu.spec.coffee
@@ -33,6 +33,14 @@
       state.go 'app.one'
       element = compile('<ui-nav-menu></ui-nav-menu>')(scope)
       scope.$digest()
+
+    it 'restricted redirect', ->
+      state.go 'app.tree'
+      timeout.flush()
+      (state.get 'app.tree').controller()
+      scope.$digest()
+      expect state.current.name
+      .toBe 'custom'

     it 'state name', ->
       expect state.current.name


export mathRandomBytes

export mathRandomBytes

--- builtin/crypto.coffee
+++ builtin/crypto.coffee
@@ -27,4 +27,5 @@
   ary

 module.exports =
-  randomBytes: randomBytes+  randomBytes: randomBytes
+  mathRandomBytes: mathRandomBytes


Version bump

Version bump

--- bin/heyu-run.coffee
+++ bin/heyu-run.coffee
@@ -1,8 +1,10 @@
 # Script for HEYU runner with state machine (target spidermonkey javascript interpreter)
+#
+# See README for more information
 #
 # by Pjotr Prins (c) 2013

-VERSION = '0.1.0'
+VERSION = '0.1.1'

 print "# Heyu-run #{VERSION} by Pjotr Prins"
 time=new Date()


couple console.logs for debugging

couple console.logs for debugging

--- views/index.coffee
+++ views/index.coffee
@@ -70,13 +70,11 @@

     setPosition = (className, top, left) ->
       $("#messages").show()
-      now.distributeMessage('has moved')
       now.updateElement(className, top, left)

     className = ""
     $( ".chess_piece" ).draggable(
       opacity: 0.55
-      refreshPositions: true
       start: (event, ui) ->
         className = ui.helper.context.className.toString()
         startTop = ui.offset.top
@@ -85,7 +83,7 @@
         piecePath= ui.helper.context.src.match(/chess_pieces*.*/)
         pieceName = piecePath.toString().replace("chess_pieces/", "")
         setPosition(className, ui.position.top, ui.position.left)
-        now.distributeMessage('has moved a piece')
+        now.distributeMessage('has moved')
       )

     if $.cookie('klop_name')
@@ -113,6 +111,10 @@
       if message
         $("#messages").append("<p>" + name + ": " + message + "</p>")
     now.receiveElement= (className, top, left) ->
+      console.log className
+      console.log top
+      console.log left
+
       $(".#{className.replace(" ",  ".").replace(" ui-draggable", "")}").css({"position":"relative","left":"#{left}px","top":"#{top}px"})


<debug> Correcting logic error in test driver.

--- tests/fixtures/basicDriver.coffee
+++ tests/fixtures/basicDriver.coffee
@@ -11,6 +11,8 @@

 areDevicesRemovable = true
 module.exports.setRemovableFlag = (flag) -> areDevicesRemovable = flag
+
+module.exports.getSensor = (customId) -> return sensors[customId]

 module.exports.init = (callback) ->
 	return callback null
@@ -39,8 +41,8 @@

 		if isCustomIDValidExample newCustomId
 			# console.log("DRIVER - UPDATE IS VALID: " + newCustomId)
-			sensors[oldCustomId] = sensors[newCustomId]
-			sensors[newCustomId] = null
+			sensors[newCustomId] = sensors[oldCustomId]
+			sensors[oldCustomId] = null
 			callback null
 		else
 			# console.log("DRIVER - UPDATE IS NOT VALID: " + newCustomId)


terminal: set focus state in `WebTermView#setFocus` method

--- client/Terminal/webtermview.coffee
+++ client/Terminal/webtermview.coffee
@@ -39,8 +39,7 @@
     @listenWindowResize()

     @on "ReceivedClickElsewhere", =>
-      @focused = false
-      @terminal.setFocused false
+      @setFocus no
       KD.getSingleton('windowController').removeLayer this

     @on "KDObjectWillBeDestroyed", @bound "clearConnectionAttempts"
@@ -221,9 +220,13 @@

   setKeyView: ->
     KD.getSingleton('windowController').addLayer this
-    @focused = true
-    @terminal.setFocused true
+    @setFocus()
     @emit 'KeyViewIsSet'
+    @once "ReceivedClickElsewhere", => @setFocus no
+
+  setFocus: (state = yes) ->
+    @focused = state
+    @terminal.setFocused state

   click: ->
     @setKeyView()


collaboration: removed initial notification

--- client/app/lib/routehandler.coffee
+++ client/app/lib/routehandler.coffee
@@ -149,10 +149,10 @@
       senderUserId: whoami()._id
       senderAccountId: whoami().socialApiId
     , (err) ->
+
       # FIXME: better error message
       return new kd.NotificationView title: 'There is an error'  if err

-      new kd.NotificationView title: 'Collaboration request sent.'
       kd.singletons.router.back()


Sort arrivals by arrival time

Sort arrivals by arrival time

--- client/rider/eta/displayETA.coffee
+++ client/rider/eta/displayETA.coffee
@@ -2,5 +2,5 @@
   stop = Session.get 'etaStop'
   if not stop
     return
-  return Arrivals.find({ station: stop, direction: direction })
+  return Arrivals.find({ station: stop, direction: direction },{ sort: ['next_arr'] })


window.getWidth and window.getHeight

window.getWidth and window.getHeight

--- coffeescript/love.js/window.coffee
+++ coffeescript/love.js/window.coffee
@@ -11,7 +11,8 @@

   getFullscreenModes: () =>

-  getHeight: () =>
+  getHeight: =>
+    @graphics.getHeight()

   getIcon: () =>

@@ -21,7 +22,8 @@

   getTitle: () =>

-  getWidth: () =>
+  getWidth: =>
+    @graphics.getWidth()

   hasFocus: () =>


address sticky tests

address sticky tests

--- src/mobile/apps/auth/test/client.test.coffee
+++ src/mobile/apps/auth/test/client.test.coffee
@@ -9,7 +9,9 @@
   describe 'PasswordResetView', ->
     beforeEach (done) ->
       benv.setup =>
-        benv.expose { $: benv.require 'jquery' }
+        benv.expose
+          $: benv.require 'jquery'
+          jQuery: benv.require 'jquery'
         Backbone.$ = $
         sinon.stub Backbone, 'sync'
         benv.render resolve(__dirname, '../templates/reset_password.jade'), { sd: { AP: {} }, asset: (->) }, =>
@@ -56,6 +58,7 @@
     benv.setup =>
       benv.expose {
         $: benv.require 'jquery'
+        jQuery: benv.require 'jquery'
         analyticsHooks: { trigger: sinon.stub() }
       }
       Backbone.$ = $
@@ -98,7 +101,9 @@
   beforeEach (done) ->
     global.location.search = ''
     benv.setup =>
-      benv.expose { $: benv.require 'jquery' }
+      benv.expose
+        $: benv.require 'jquery'
+        jQuery: benv.require 'jquery'
       Backbone.$ = $
       sinon.stub Backbone, 'sync'
       benv.render resolve(__dirname, '../templates/login.jade'), { sd: { AP: {} }, asset: (->) }, =>
@@ -131,6 +136,7 @@
     benv.setup =>
       benv.expose {
         $: benv.require 'jquery'
+        jQuery: benv.require 'jquery'
         analyticsHooks: { trigger: sinon.stub() }
       }
       Backbone.$ = $


Assert, not print

Assert, not print

--- coffeescript/animals.coffee
+++ coffeescript/animals.coffee
@@ -3,16 +3,17 @@
   speak: -> "#{@name} says #{@sound()}"

 class Cow extends Animal
-  sound: -> "moooo"
+  sound: -> 'moooo'

 class Horse extends Animal
-  sound: -> "neigh"
+  sound: -> 'neigh'

 class Sheep extends Animal
-  sound: -> "baaaa"
+  sound: -> 'baaaa'

-s = new Horse "CJ"
-console.log s.speak()
-c = new Cow "Bessie"
-console.log c.speak()
-console.log new Sheep("Little Lamb").speak()
+assert = require 'assert'
+s = new Horse 'CJ'
+assert s.speak() is 'CJ says neigh'
+c = new Cow 'Bessie'
+assert c.speak() is 'Bessie says moooo'
+assert new Sheep('Little Lamb').speak() is 'Little Lamb says baaaa'


- Added method to retrieve the one time code in case of hybrid flow - getCode return null if the code is not present i.e. for implicit flow.

--- src/gamifyd_sso.coffee
+++ src/gamifyd_sso.coffee
@@ -9,12 +9,12 @@
         scope: 'openid+profile'
         response_type: 'id_token token'

-    access_token = id_token = access_hash = identity_obj = discovery_obj = jwks = null
+    access_token = id_token = access_hash = identity_obj = discovery_obj = jwks = code = null

     disconnect = (callback) ->
         callback ?= false
         window.localStorage.clear()
-        access_token = id_token = access_hash = identity_obj = null
+        access_token = id_token = access_hash = identity_obj = code = null
         if callback
             callback()
         else
@@ -46,6 +46,8 @@
         access_hash = access_hash_clt
         access_token = access_hash.access_token
         id_token = access_hash.id_token
+        if access_hash.code
+            code = access_hash.code

     checkTokens = (nonce, hash) ->
         if hash.access_token
@@ -85,6 +87,7 @@
     getIdToken: () -> id_token
     getAccessHash: () -> access_hash
     getDiscovery: () -> discovery_obj
+    getCode: () -> code

     auth_endpoint: () ->
         return discovery_obj.authorization_endpoint if discovery_obj


Fixed: version number was not updated in the UI during app update. Close #253

--- client/app/views/config_application.coffee
+++ client/app/views/config_application.coffee
@@ -23,6 +23,9 @@
     constructor: (options) ->
         @id = "app-btn-#{options.model.id}"
         super
+
+    initialize: ->
+        @listenTo @model, 'change:version', @render

     afterRender: =>
         @updateButton = new ColorButton @$ ".update-app"


Move tests on updated items to a different function

Hopefully it's a little more readable.

--- src/local/operations.coffee
+++ src/local/operations.coffee
@@ -520,20 +520,13 @@
                                 else
                                     cb4 err, item
                     , (oldItem, cb4) =>
+                        normalizeItem @req, oldItem, item, (err, newItem) ->
+                            cb4 err, oldItem, newItem
+                    , (oldItem, newItem, cb4) =>
                         if oldItem?
-                            if oldItem.name is 'deleted-entry'
-                                return cb4 new errors.NotAcceptable "You can't update a deleted item"
-
-                            # Only the original author can update an item
-                            itemActor = oldItem.getChild("author")?.getChild("uri")?.getText()
-                            if itemActor is "acct:#{@req.actor}"
-                                cb4 null, oldItem
-                            else
-                                cb4 new errors.Forbidden "You're not allowed to update this item"
+                            @checkUpdatedItem oldItem, newItem, cb4
                         else
-                            cb4 null, oldItem
-                    , (oldItem, cb4) =>
-                        normalizeItem @req, oldItem, item, cb4
+                            cb4 null, newItem
                     , (newItem, cb4) =>
                         # When replying, the original item must exist
                         irtEl = newItem.el.getChild('in-reply-to', 'http://purl.org/syndication/thread/1.0')
@@ -551,6 +544,17 @@
                     ], cb3
             ), cb2
         ], cb
+
+    checkUpdatedItem: (oldItem, newItem, cb) ->
+        if oldItem.name is 'deleted-entry'
+            return cb new errors.NotAcceptable "You can't update a deleted item"
+
+        # Only the original author can update an item
+        itemActor = oldItem.getChild("author")?.getChild("uri")?.getText()
+        if itemActor isnt "acct:#{@req.actor}"
+            return cb new errors.Forbidden "You're not allowed to update this item"
+
+        cb null, newItem

     notification: ->
         [{


more descriptive text for case of boarding train

--- src/hubot-marta.coffee
+++ src/hubot-marta.coffee
@@ -45,8 +45,10 @@
       )
       train = trains.shift()
       if train
+        arrival_text = "will arrive"
+        arrival_text = "started boarding" if train.WAITING_TIME == 'Boarding'
         direction = dirMap[train.DIRECTION]
         next_arrival = moment().add(parseInt(train.WAITING_SECONDS),'seconds')
-        msg.send "#{direction}bound #{train.LINE.toLowerCase()} train will arrive at #{train.STATION} #{next_arrival.fromNow()}"
+        msg.send "#{direction}bound #{train.LINE.toLowerCase()} train #{arrival_text} at #{train.STATION} #{next_arrival.fromNow()}"
       else
         msg.send "no train match :("


Allow modifier key for block clicks (closes #244)

--- components/layout/body/view.coffee
+++ components/layout/body/view.coffee
@@ -78,7 +78,9 @@
     clientRoute = $(e.currentTarget).data('client')
     url = $(e.currentTarget).attr('href')

-    if clientRoute and clientRoute isnt 'Channel' and clientRoute isnt 'User'
+    modifier = e.metaKey || e.ctrlKey
+
+    if clientRoute and clientRoute isnt 'Channel' and clientRoute isnt 'User' and !modifier
       Backbone.history.navigate "#{url}", trigger: true, replace: false
     else
       trackOutboundLink(url) if url.indexOf('http')


Fix uri hash

Fix uri hash

If:
```
{{urlFor '/:routeParam' routeParam='myRoute' hash='main'}}
```
returns: `http://example.com/myRoutemain`
__Fix__: `http://example.com/myRoute#main`

--- client/helpers.coffee
+++ client/helpers.coffee
@@ -17,7 +17,7 @@
     delete view.hash.route
   query = if view.hash.query then FlowRouter._qs.parse(view.hash.query) else {}
   hashBang = if view.hash.hash then view.hash.hash else ''
-  FlowRouter.path(path, view.hash, query) + hashBang
+  FlowRouter.path(path, view.hash, query) + (if hashBang then "##{hashbang}" else '')

 # return absolute url
 urlFor = (path, view) ->
@@ -56,4 +56,4 @@
 if Meteor.isServer
   FlowRouterHelpers =
     pathFor: pathFor
-    urlFor: urlFor+    urlFor: urlFor


Fix message drag to later numbered child with same parent

--- client/message.coffee
+++ client/message.coffee
@@ -921,10 +921,15 @@
   parentMsg = Messages.findOne parent
   oldParent = findMessageParent child
   oldIndex = oldParent?.children.indexOf child
-  ## Ignore drag to same place
   if parentMsg?._id == oldParent?._id
+    ## Ignore drag to same place
     return if index == oldIndex or
       (not index? and oldIndex == oldParent.children.length - 1)
+    ## If dragging within same parent to a later-numbered child,
+    ## need to decrease index by 1 to account for loss of self.
+    if index? and index > oldIndex
+      index -= 1
+      return if index == oldIndex
   Modal.show 'messageParentConfirm',
     child: childMsg
     parent: parentMsg


Draw one-tick sliders in lonely History view

https://github.com/edemaine/coauthor/issues/247#issuecomment-516198619

--- client/message.coffee
+++ client/message.coffee
@@ -1362,7 +1362,7 @@
         index = diffs.length - 1
       previous = diffs[index]?.diffId
       ## Don't show a zero-length slider
-      return if diffs.length < 2
+      return unless diffs.length
       ## Draw slider
       @slider = new Slider @find('input'),
         #min: 0                 ## min and max not needed when using ticks
@@ -1370,6 +1370,7 @@
         #value: diffs.length-1  ## doesn't update, unlike setValue method below
         ticks: [0...diffs.length]
         ticks_snap_bounds: 999999999
+        reversed: diffs.length == 1  ## put one tick at far right
         tooltip: 'always'
         tooltip_position: 'bottom'
         formatter: (i) ->


remove comments

remove comments

--- server/models/homedata.coffee
+++ server/models/homedata.coffee
@@ -1,9 +1,7 @@
 cozydb = require 'cozy-db-pouchdb'

-# On décrit le modèle des données que l'on persistera et requêtera.
-# Ici c'est notr objet bookmark constitué de deux champs : le titre et le lien
-# de la bookmark.
+
 module.exports = Homedata = cozydb.getModel 'Homedata',
     helloworld: String
     name: String


fix(server): copy server js src files to the server

--- tasks/copy/copy-js.coffee
+++ tasks/copy/copy-js.coffee
@@ -19,7 +19,7 @@
 		tasks.run.async(
 			config, runTask,
 			'scripts', 'js',
-			['client']
+			['client', 'server']
 		)

 	# register task


Remove old stuff.

Remove old stuff.

--- app/assets/javascripts/app/widgets/todoList.coffee
+++ app/assets/javascripts/app/widgets/todoList.coffee
@@ -67,7 +67,7 @@

     if event.which != enterKey or not value then return

-    todos.create id: uuid(), title: value
+    todos.create title: value

     input.val ''


adds compile function to grunt file for tpds worker and background jobs worker

--- services/web/Gruntfile.coffee
+++ services/web/Gruntfile.coffee
@@ -27,6 +27,14 @@
 			app:
 				src: 'app.coffee'
 				dest: 'app.js'
+
+			TpdsWorker:
+				src: 'TpdsWorker.coffee'
+				dest: 'TpdsWorker.js'
+
+			BackgroundJobsWorker:
+				src: 'BackgroundJobsWorker.coffee'
+				dest: 'BackgroundJobsWorker.js'

 			sharejs:
 				options:


EDSC-149: Fix broken producer_granule_id serialization

--- app/assets/javascripts/models/data/query.js.coffee
+++ app/assets/javascripts/models/data/query.js.coffee
@@ -20,19 +20,31 @@
       name = ko.observable(name) unless ko.isObservable(name)
       @name = name

+    names: ->
+      @name.validValues ? [@name()]
+
     canWrite: ->
       value = @value()
       value = value.trim() if typeof value == "string"
       value? && (!value.length? || value.length > 0)

     canReadFrom: (query) ->
-      query[@name()]?
+      for name in @names()
+        if query[name]?
+          return true
+      false

     writeTo: (query) ->
       query[@name()] = @value()

     readFrom: (query) ->
-      @value(query[@name()])
+      for name in @names()
+        value = query[name]
+        if value?
+          @name(name)
+          @value(value)
+          break
+      null

     read: ->
       query = null
@@ -140,7 +152,13 @@
       super(name)

     readFrom: (query) ->
-      @value(query[@name()].join(@delimiter))
+      for name in @names()
+        value = query[name]
+        if value?
+          @name(name)
+          @value(value.join(@delimiter))
+          break
+      null

     writeTo: (query) ->
       query[@name()] = @value().split(@delimiter)
@@ -245,10 +263,9 @@

   class GranuleQuery extends Query
     constructor: (datasetId, parentQuery) ->
-      console.log 'constructed', datasetId
       super(parentQuery)
       @granuleIdsSelectedOptionValue = ko.observable("granule_ur")
-      #@granuleIdsSelectedOptionValue.validValues = ['granule_ur', 'producer_granule_id']
+      @granuleIdsSelectedOptionValue.validValues = ['granule_ur', 'producer_granule_id']
       @dayNightFlagOptions = [{name: "Anytime", value: null},
                               {name: "Day only", value: "DAY"},
                               {name: "Night only", value: "NIGHT"},


typo fix, caught during typed-doppio conversion

--- browser/node.coffee
+++ browser/node.coffee
@@ -480,7 +480,7 @@
     else
       ls = @index.ls file1
       for f_name in ls
-        @mv f_name, path2 + f_name.substr(path1.length), true, true
+        @mv f_name, file2 + f_name.substr(file1.length), true, true
       @index.rm file1
     return success


Add parenthesis

Add parenthesis


Fix shift+return

Fix shift+return

--- src/trix/controllers/input_controller.coffee
+++ src/trix/controllers/input_controller.coffee
@@ -227,9 +227,9 @@

     shift:
       return: (event) ->
-        event.preventDefault()
         @delegate?.inputControllerWillPerformTyping()
         @responder?.insertString("\n")
+        @input = "shift+return"

       left: (event) ->
         if @selectionIsInCursorTarget()


Add parseKeystroke function

Add parseKeystroke function

--- src/key-binding.coffee
+++ src/key-binding.coffee
@@ -12,18 +12,18 @@

   @normalizeKeystroke: (keystroke) ->
     normalizedKeystroke = keystroke.split(/\s+/).map (keystroke) =>
-      keys = @getParser().parse(keystroke)
+      keys = @parseKeystroke(keystroke)
       modifiers = keys[0...-1]
       modifiers.sort()
       [modifiers..., _.last(keys)].join('-')
     normalizedKeystroke.join(' ')

-  @getParser: ->
+  @parseKeystroke: (keystroke) ->
     unless KeyBinding.parser?
       keystrokePattern = fs.readFileSync(require.resolve('./keystroke-pattern.pegjs'), 'utf8')
       KeyBinding.parser = PEG.buildParser(keystrokePattern)

-    KeyBinding.parser
+    KeyBinding.parser.parse(keystroke)

   constructor: (source, command, keystroke, selector) ->
     @source = source


Add chainability example to inline docs

Add chainability example to inline docs

--- src/kissmetrics.coffee
+++ src/kissmetrics.coffee
@@ -45,6 +45,13 @@
 # Instantiates a new client with your Kissmetrics API key and an identifier
 # for the person you're recording data about. A new client must be created
 # for each person you record data about.
+#
+# All data methods (`record`, `set`, `alias`) are chainable.
+#
+# ```
+# km = new KissmetricsClient(API_KEY, user);
+# km.record('Changed username').alias(user.newname).set({mood: 'indecisive'});
+# ```
 #
 # ##### Arguments
 #


double mode

double mode

--- client/front.coffee
+++ client/front.coffee
@@ -836,7 +836,8 @@
                     oldline[1] = start
                     oldline[2] = end
                     #console.log [oldline[3], "!=", line, "or", oldline[4], "!=", prev_mode]
-                    if oldline[3] != line or oldline[4] != prev_mode
+                    if oldline[3] != line or prev_mode[1] != oldline[4][0]
+                    #iif oldline[3] != line or oldline[4] != prev_mode
                         #console.log "true"
                         [colored, mode, html] = @tokenizer.tokenize(line, prev_mode)
                         oldline[3] = line


chore(core): remove 'who'

chore(core): remove 'who'

--- scripts/example.coffee
+++ scripts/example.coffee
@@ -13,11 +13,7 @@
         res.send res.random greetings

     robot.hear /\benhance\b/i, (res) ->
-        res.send "![](http://i.giphy.com/10nMEclFWTPCp2.gif)"
-
-    robot.hear /\bwho\b/i, (res) ->
-        res.send "azure bot"
-
+        res.send("![](http://i.giphy.com/10nMEclFWTPCp2.gif)")

     fiftyfifty = ["I'd give that a 50/50.", "Hmmm, 50/50?", "That's simple... 50/50.", "50/50 is my best guess."]
     robot.hear /\bodds (on|of|for)\b|\bwhat are the (chances|odds)\b|\bknow the (chances|odds)\b/i, (res) ->


Time Entry deletion for project

Time Entry deletion for project

Make this SQL statment part of the same pg client and therefore the same
transaction.

--- controllers/projects.coffee
+++ controllers/projects.coffee
@@ -61,20 +61,20 @@

   deleteOne: (key, callback)->
+    {time_entry} = TimeEntriesController
+    deleteProjectTimeEntries = time_entry.delete().where(time_entry.projectId.equals(key))
     deleteProject = @project.delete().where(@project.id.equals(key))
     deleteUsersProjectsRows = @usersprojects.delete().where(@usersprojects.projectid.equals key)
     t = @transaction()
     start = ->
-      async.eachSeries [deleteUsersProjectsRows, deleteProject],
+      async.eachSeries [deleteProjectTimeEntries, deleteUsersProjectsRows, deleteProject],
         (s, cb)->
           t.query s, ()->
             cb()
         , ->
           t.commit()

-    t.on 'begin', =>
-      TimeEntriesController.deleteForProject key, ()->
-        start()
+    t.on 'begin', start
     t.on 'error', callback
     t.on 'commit', ->
       callback()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/active_bounds.coffee
+++ test/active_bounds.coffee
@@ -1,5 +1,5 @@
 module "ActiveBounds"

-test "should remove "
+test "should remove objects"

 module()


Updated AMD tests

Updated AMD tests

--- test/core/test-amd.coffee
+++ test/core/test-amd.coffee
@@ -7,4 +7,4 @@
   # library and dependencies
   require ['json-serialize', 'qunit_test_runner'], (jsn, runner) ->
     window.JSONS = null # force each test to require dependencies synchronously
-    require ['./build/test'], -> runner.start()+    runner.start(); require ['./build/test'], ->


Site name can and should be public.

Site name can and should be public.

--- server/accounts.coffee
+++ server/accounts.coffee
@@ -107,7 +107,7 @@

   lines.join '\n'

-Accounts.emailTemplates.siteName = Meteor.settings?.siteName or "PeerLibrary"
+Accounts.emailTemplates.siteName = Meteor.settings?.public?.siteName or "PeerLibrary"
 Accounts.emailTemplates.from = Meteor.settings?.from or "PeerLibrary <no-reply@peerlibrary.org>"
 Accounts.emailTemplates.resetPassword.subject = (user) ->
   """[#{ Accounts.emailTemplates.siteName }] Password reset"""


Cleaner tests

Cleaner tests

--- test/function_test.coffee
+++ test/function_test.coffee
@@ -2,45 +2,35 @@
 func   = require '../src/function'
 array  = require '../src/array'

-suite 'uncurry', ->
-  fn = null
-  cfn = null
-  setup ->
-    fn = (a) -> (b) -> (c) ->
-      [a, b, c].join ' '
+suite 'function', ->
+  suite 'uncurry', ->
+    fn = (a) -> (b) -> (c) -> [a, b, c].join ' '
     cfn = func.uncurry fn
-  test 'curried', ->
-    assert.equal 'a b c', fn('a')('b')('c')
-  test 'uncurry 1', ->
-    assert.equal 'a b c', cfn('a', 'b')('c')
-  test 'uncurry 2', ->
-    assert.equal 'a b c', cfn('a', 'b', 'c')
-  test 'uncurry 3', ->
-    assert.equal 'a b c', cfn('a', 'b', 'c', 'd')
+    test 'curried', ->
+      assert.strictEqual 'a b c', fn('a')('b')('c')
+    test '1', ->
+      assert.strictEqual 'a b c', cfn('a', 'b')('c')
+    test '2', ->
+      assert.strictEqual 'a b c', cfn('a', 'b', 'c')
+    test '3', ->
+      assert.strictEqual 'a b c', cfn('a', 'b', 'c', 'd')

-suite 'curry', ->
-  fn = (a, b, c, d) ->
-    [a, b, c, d].join(' ')
-  fnCurried = func.curry fn
-  fnCurriedExplicit = func.curry 3, fn
+  suite 'curry', ->
+    fn = (a, b, c, d) -> [a, b, c, d].join(' ')
+    fnCurried = func.curry fn
+    fnCurriedExplicit = func.curry 3, fn
+    test '1', ->
+      assert.strictEqual 'a b c d', fnCurried('a')('b', 'c', 'd')
+    test '2', ->
+      assert.strictEqual 'a b c d', fnCurried('a')('b')('c', 'd')
+    test '3', ->
+      assert.strictEqual 'a b c d', fnCurried('a')('b')('c')('d')
+    test 'pairs', ->
+      assert.strictEqual 'a b c d', fnCurried('a', 'b')('c', 'd')
+    test 'explicit arity', ->
+      assert.strictEqual 'a b c ', fnCurriedExplicit('a')('b')('c')

-  test '1', ->
-    assert.strictEqual 'a b c d', fnCurried('a')('b', 'c', 'd')
-  test '2', ->
-    assert.strictEqual 'a b c d', fnCurried('a')('b')('c', 'd')
-  test '3', ->
-    assert.strictEqual 'a b c d', fnCurried('a')('b')('c')('d')
-  test 'pairs', ->
-    assert.strictEqual 'a b c d', fnCurried('a', 'b')('c', 'd')
-  test 'explicit arity', ->
-    assert.strictEqual 'a b c ', fnCurriedExplicit('a')('b')('c')
-
-suite 'compose', ->
-  foo = null
-  setup ->
-    foo = [
-      ['a', 'b'],
-      ['c', 'd']
-    ]
-  test 'joins', ->
-    assert.strictEqual 'a: b; c: d', func.compose(array.join('; '), array.map(array.join(': ')))(foo)
+  suite 'compose', ->
+    arr = [['a', 'b'], ['c', 'd']]
+    test 'joins', ->
+      assert.strictEqual 'a: b; c: d', func.compose(array.join('; '), array.map(array.join(': ')))(arr)


Fixed statusCode typos.

Fixed statusCode typos.

--- src/plugins/ubs-grab.coffee
+++ src/plugins/ubs-grab.coffee
@@ -24,14 +24,14 @@

     logging.info "+ Grab #{command} (destination: #{resolvedPath})"

-    # Init a new promise, promise me a responseCode sometime
+    # Init a new promise, promise me a statusCode sometime
     deferred = Q.defer()
     {promise} = deferred
-    responseCode = null
+    statusCode = null

     outputStream = fs.createWriteStream path.join resolvedPath, path.basename command
     outputStream.on 'finish', ->
-      deferred.resolve responseCode
+      deferred.resolve statusCode

     request.get(command)
       .on 'error', (error) ->


Simplify code.

Simplify code.

--- src/map-printer.coffee
+++ src/map-printer.coffee
@@ -74,9 +74,8 @@
                 sw = map.unproject(bounds.getBottomLeft())
                 ne = map.unproject(bounds.getTopRight())

-                if L.latLngBounds(sw, ne).contains marker.getLatLng()
-                    marker.vid = vid
-                    vid++
+                if mapBounds.contains marker.getLatLng()
+                    marker.vid = ++vid
                     # Don't throw the actual icon away
                     marker._iconStore = marker._icon

@@ -152,4 +151,4 @@

             $('#map-as-png').remove()
             $('#list-of-units').remove()
-            @printed = true+            @printed = true


split out into two attention spans

split out into two attention spans

--- js-library/app/js/views/fact.coffee
+++ js-library/app/js/views/fact.coffee
@@ -10,9 +10,13 @@

 class Factlink.Fact
   constructor: (@id, @elements) ->
-    @attention_span = new Factlink.AttentionSpan
-      lost_attention: => @stopEmphasis()
-      gained_attention: => @startEmphasis()
+    @button_attention = new Factlink.AttentionSpan
+      lost_attention:   => @show_button.hide()
+      gained_attention: => @show_button.show()
+
+    @highlight_attention = new Factlink.AttentionSpan
+      lost_attention:   => @highlighter.dehighlight()
+      gained_attention: => @highlighter.highlight()

     @highlighter = new Highlighter $(@elements)

@@ -32,26 +36,20 @@

   highlight_temporary: (duration) ->
     @highlighter.highlight()
-    setTimeout (=> @stopEmphasis()), duration
+    setTimeout =>
+      @highlighter.dehighlight() unless @shouldHaveEmphasis()
+    , duration

-  onBlur: -> @attention_span.neglect()
+  onBlur: ->
+    @highlight_attention.neglect()
+    @button_attention.neglect()
   onFocus: (e) =>
     if e?
       @show_button.setCoordinates($(e.target).offset().top, e.pageX)
-    @attention_span.attend()
+    @highlight_attention.attend()
+    @button_attention.attend()

-  startEmphasis: ->
-    @highlighter.highlight()
-    @show_button.show()
-
-  stopEmphasis: =>
-    return if @shouldHaveEmphasis()
-
-    @highlighter.dehighlight()
-    @show_button.hide()
-
-  shouldHaveEmphasis: =>
-    @attention_span.has_attention() || @_loading
+  shouldHaveEmphasis: => @highlight_attention.has_attention() || @_loading

   openFactlinkModal: =>
     @startLoading()
@@ -63,7 +61,8 @@

   stopLoading: ->
     @_loading = false
-    @stopEmphasis()
+    @highlighter.dehighlight()
+    @button.hide()

   destroy: ->
     for el in @elements


don't highlight directly, so we don't light up on fast scroll

--- js-library/app/js/views/fact.coffee
+++ js-library/app/js/views/fact.coffee
@@ -71,7 +71,7 @@
     , highlight_time_on_load_and_creation

 class FactScrollPromotion
-  # states: invisible, small_time_visible, visible
+  # states: invisible, just_visible, small_time_visible, visible

   constructor: (@fact) ->
     @highlighter = new Highlighter $(fact.elements), 'fl-scroll-highlight'
@@ -81,10 +81,13 @@
   onVisibilityChanged: =>
     if @fact.isInView()
       if @state == 'invisible'
-        @switchToState 'small_time_visible'
-        @timout_handler = setTimeout =>
-          @switchToState 'visible'
-        , highlight_time_on_in_view
+        @switchToState 'just_visible'
+        @timeout_handler = setTimeout =>
+          @switchToState 'small_time_visible'
+          @timeout_handler = setTimeout =>
+            @switchToState 'visible'
+          , highlight_time_on_in_view
+        , 200
       # else: we are in a visible state, and
       # the fact is visible, no need to change state
     else
@@ -93,8 +96,8 @@

   switchToState: (to_state) =>
     return if to_state == @state
+    console.info 'Switching', @fact.id, @state, to_state if @fact.id == '148'

-    console.info 'Switching', @fact.id, @state, to_state if @fact.id == '148'
     switch to_state
       when 'small_time_visible'
         @highlighter.highlight()


sort without recreating items

sort without recreating items

--- src/mixins/list.coffee
+++ src/mixins/list.coffee
@@ -30,8 +30,9 @@
     @listenTo @collection, "add", @added
     @listenTo @collection, 'reset', @addAll
     @listenTo @collection, "sort", ->
-      @empty()
-      @addAll()
+      # @empty()
+      # @addAll()
+      @sort()
     @listenTo @collection, "remove", @removed
     @listenTo @collection, "request", @showLoading.bind(@, true)
     @listenTo @collection, "error", @showError
@@ -64,6 +65,16 @@
     else
       @listEl = @$el
     return @listEl
+
+  sort: () ->
+    for model in @collection.models
+      if @filterFunc model, @filters
+        view = @views[model.cid]
+        index = @collection.indexOf model
+        current = view.$el.index()
+        if index != current
+          el = @getListElement().children().eq(index)
+          el.before(view.$el.detach())

   empty: () ->
     @getListElement().empty()


strip dead code

strip dead code

--- source/javascripts/all.coffee
+++ source/javascripts/all.coffee
@@ -1,8 +1,4 @@
-# all.coffee
-
 "use strict";
-
-

 document.addEventListener 'DOMContentLoaded', (e) ->
   views = document.querySelectorAll '.js-street-view'
@@ -22,33 +18,3 @@
       panControl: false
       scrollwheel: false
       zoomControlOptions: { style: google.maps.ZoomControlStyle.SMALL }
-
-
-  # drawMap = (el) ->
-  #   console.log 'DRAWING'
-  #   lat = el.getAttribute 'data-lat'
-  #   lon = el.getAttribute 'data-lon'
-  #   heading = parseInt el.getAttribute 'data-heading'
-  #
-  #   if !isNaN(heading)
-  #     pov = heading: heading, pitch: 0
-  #
-  #   new google.maps.StreetViewPanorama el,
-  #     position: new google.maps.LatLng(lat, lon)
-  #     pov: pov
-  #     mode: 'webgl'
-  #     linksControl: false
-  #     panControl: false
-  #     scrollwheel: false
-  #     zoomControlOptions: { style: google.maps.ZoomControlStyle.SMALL }
-  #
-  # setOnScreen = ->
-  #   offset = window.pageYOffset
-  #   for el in views
-  #     if !el.classList.contains 'is-onscreen'
-  #       rect = el.getBoundingClientRect()
-  #       if offset in [rect.top..(rect.top + rect.height)]
-  #         el.classList.add 'is-onscreen'
-  #         drawMap(el)
-  #
-  # window.onscroll = setOnScreen


Provide commit SHA at beginning, and return build directory path

--- compiler/index.coffee
+++ compiler/index.coffee
@@ -1,74 +1,119 @@
 # Enable support for requiring `.cjsx` files.
 require('coffee-react/register')

-fs      = require 'fs'
-path    = require 'path'
-util    = require 'util'
+fs                  = require 'fs-extra'
+path                = require 'path'
+util                = require 'util'

 ContentAPI          = require './ContentAPI'
 formatProjectPath   = require './formatProjectPath'
 SDKError            = require './SDKError'

-module.exports = (project_directory) ->
+{ exec } = require 'child_process'

-    util.log("Compiling: #{ formatProjectPath(project_directory) }")
+_getCurrentCommit = (directory, cb) ->
+    unless fs.existsSync(path.join(directory, '.git'))
+        cb(null)
+    exec 'git rev-parse --short=N HEAD', cwd: directory, (err, stdout, stderr) ->
+        cb(stdout.split('\n').join(''))

-    # Load the project's package.json file, if present and valid.
-    project_package_file = path.join(project_directory, 'package.json')
-    unless fs.existsSync(project_package_file)
-        throw new SDKError('package', 'Unable to find package.json')
-    project_package_content = fs.readFileSync(project_package_file).toString()
-    try
-        project_package = JSON.parse(project_package_content)
-    catch e
-        throw new SDKError('package', 'Unable to parse package.json. Is it valid JSON?')
+module.exports = (project_directory, onCompile=null) ->
+    # Ensure build directory exists and is empty.
+    build_directory = path.join(project_directory, '.build')
+    if fs.existsSync(build_directory)
+        util.log(SDKError.colors.grey('Clearing previous build...'))
+        fs.removeSync(build_directory)

-    # Identify the project entrypoint.
-    unless project_package.main
-        throw new SDKError('configuration', "Project missing `package.main` (typically \"./main.coffee\")")
-    project_main = path.join(project_directory, project_package.main)
-    util.log("Project entrypoint: #{ formatProjectPath(project_directory, project_main) }")
+    # Provide the commit sha to the build, if available.
+    _getCurrentCommit project_directory, (commit_sha) ->
+        _sha = if commit_sha then SDKError.colors.grey(" (@ #{ commit_sha })") else ''
+        util.log("Compiling: #{ formatProjectPath(project_directory) }#{ _sha }")

-    # Load and validate the Marquee-specific compiler configuration.
-    project_config = project_package.marquee
-    unless project_config
-        throw new SDKError('configuration', "Project missing `package.marquee`.")
-    ['CONTENT_API_TOKEN', 'CONTENT_API_ROOT', 'HOST'].forEach (prop) ->
-        unless project_config[prop]
-            throw new SDKError('configuration', "Project missing `package.marquee.#{ prop }`.")
+        # Load the project's package.json file, if present and valid.
+        project_package_file = path.join(project_directory, 'package.json')
+        unless fs.existsSync(project_package_file)
+            throw new SDKError('package', 'Unable to find package.json')
+        project_package_content = fs.readFileSync(project_package_file).toString()
+        try
+            project_package = JSON.parse(project_package_content)
+        catch e
+            throw new SDKError('package', 'Unable to parse package.json. Is it valid JSON?')

-    # Load the project compiler entrypoint.
-    buildFn = require(project_main)
-    unless typeof buildFn is 'function'
-        throw new SDKError('entrypoint', "Project main MUST export a function. Got #{ SDKError.colors.underline(typeof buildFn) }.")
+        # Identify the project entrypoint.
+        unless project_package.main
+            throw new SDKError('configuration', "Project missing `package.main` (typically \"./main.coffee\")")
+        project_main = path.join(project_directory, project_package.main)
+        util.log("Project entrypoint: #{ formatProjectPath(project_directory, project_main) }")

-    # Set up the Content API wrapper for the project.
-    api = new ContentAPI
-        token   : project_config.CONTENT_API_TOKEN
-        root    : project_config.CONTENT_API_ROOT
-        cache   : false
-        project : project_package
+        # Load and validate the Marquee-specific compiler configuration.
+        project_config = project_package.marquee
+        unless project_config
+            throw new SDKError('configuration', "Project missing `package.marquee`.")
+        ['CONTENT_API_TOKEN', 'CONTENT_API_ROOT', 'HOST'].forEach (prop) ->
+            unless project_config[prop]
+                throw new SDKError('configuration', "Project missing `package.marquee.#{ prop }`.")

-    # Make the config globally available. Yes, globals are Bad(tm), but this
-    # makes for a substantially simpler compiler.
-    global.config = project_config
+        # Load the project compiler entrypoint.
+        buildFn = require(project_main)
+        unless typeof buildFn is 'function'
+            throw new SDKError('entrypoint', "Project main MUST export a function. Got #{ SDKError.colors.underline(typeof buildFn) }.")

-    # Create the emitFile function for the project.
-    emitFile = require('./emitFile')(project_directory, project_package, project_config)
+        # Set up the Content API wrapper for the project.
+        api = new ContentAPI
+            token   : project_config.CONTENT_API_TOKEN
+            root    : project_config.CONTENT_API_ROOT
+            cache   : false
+            project : project_package

-    # Finally, invoke the compiler.
-    try
-        buildFn
-            api         : api
-            emitFile    : emitFile
-            config      : project_config
-            project     : project_package
-    catch e
-        throw new SDKError('compiler', e)
+        # Create the file handling functions for the project.
+        _writeFile = require('./writeFile')(build_directory)
+        _emitFile = require('./emitFile')(
+            project_directory   : project_directory
+            project             : project_package
+            config              : project_config
+            writeFile           : _writeFile
+        )

-    # make temp directory for asset cache
-    # build all assets to asset cache
-    # make a temp directory for project
-    # copy auto assets
-    # build project into temp directory
+        # Set a timeout for the compiler. Must complete within 60 seconds.
+        _done_timeout = setTimeout ->
+            throw new SDKError('compiler', 'Compiler timeout. Compiler MUST call `done` within 60 seconds.')
+        , 60 * 1000
+        _done = ->
+            clearTimeout(_done_timeout)
+            # Check that the project has necessary files.
+            unless '404.html' in _emitFile.files_emitted
+                SDKError.warn('files', 'Projects SHOULD have a /404.html')
+            unless 'index.html' in _emitFile.files_emitted
+                SDKError.warn('files', 'Projects SHOULD have a /index.html')
+            onCompile?(_emitFile.files_emitted)
+
+        # TODO: compile assets
+        asset_hash = null
+
+        # Make the config globally available. Yes, globals are Bad(tm), but this
+        # makes for a substantially simpler compiler.
+        global.config = project_config
+
+        # Finally, invoke the compiler.
+        try
+            buildFn
+                api         : api
+                emitFile    : _emitFile
+                config      : project_config
+                project     : project_package
+                done        : _done
+                info:
+                    commit      : commit_sha
+                    date        : new Date()
+                    asset_hash  : asset_hash
+
+        catch e
+            throw new SDKError('compiler', e)
+
+    return build_directory
+        # make temp directory for asset cache
+        # build all assets to asset cache
+        # make a temp directory for project
+        # copy auto assets
+        # build project into temp directory


build-client: use KONFIG_JSON instead of env variables

--- build-client.coffee
+++ build-client.coffee
@@ -20,13 +20,15 @@
 buildAPI          = require 'bongo-api-builder'
 bongo             = require 'bongo'

+KONFIG = JSON.parse process.env.KONFIG_JSON or {}

 args =
   watchDuration : argv.watchDuration  or 5000
-  watch         : argv.watch          or process.env.KONFIG_CLIENT_WATCH or false
-  version       : argv.version        or process.env.KONFIG_VERSION      or "0.0.1"
-  sourceMapsUri : argv.sourceMapsUri  or process.env.KONFIG_CLIENT_RUNTIMEOPTIONS_SOURCEMAPSURI or "koding.com/sourcemaps"
+  watch         : argv.watch          or KONFIG.client.watch or false
+  version       : argv.version        or KONFIG.version      or "0.0.1"
+  sourceMapsUri : argv.sourceMapsUri  or KONFIG.client.runtimeOptions.sourceMapsUri or "koding.com/sourcemaps"
   verbose       : argv.verbose        or false
+
 console.log "building client with options:",args

 log =


Fix a minor typo in the options.relax test

--- test/options.relax.coffee
+++ test/options.relax.coffee
@@ -56,7 +56,7 @@
       next()

   it 'false with two invalid quotes on the left', (next) ->
-    # try with relax true
+    # try with relax false
     parse """
     384682,""SAMAY"" Hostel,Jiron Florida 285
     """, relax: false, (err, data) ->


move v_s test in a describe block

move v_s test in a describe block

--- spec/operators-spec.coffee
+++ spec/operators-spec.coffee
@@ -89,28 +89,26 @@
     beforeEach ->
       editor.setText('012345')
       editor.setCursorScreenPosition([0, 1])
+
+    it "deletes the character to the right and enters insert mode", ->
       keydown('s')
-
-    it "deletes the character to the right and enters insert mode", ->
       expect(editorView).toHaveClass 'insert-mode'
       expect(editor.getText()).toBe '02345'
       expect(editor.getCursorScreenPosition()).toEqual [0, 1]
       expect(vimState.getRegister('"').text).toBe '1'

-  describe "the v_s keybinding", ->
-    beforeEach ->
-      editor.setText('012345')
-      editor.setCursorScreenPosition([0, 1])
-      keydown('v')
-      editor.selectRight()
-      editor.selectRight()
-      keydown('s')
-
-    it "deletes the selected characters and enters insert mode", ->
-      expect(editorView).toHaveClass 'insert-mode'
-      expect(editor.getText()).toBe '0345'
-      expect(editor.getCursorScreenPosition()).toEqual [0, 1]
-      expect(vimState.getRegister('"').text).toBe '12'
+    describe "in visual mode", ->
+      beforeEach ->
+        keydown('v')
+        editor.selectRight()
+        editor.selectRight()
+        keydown('s')
+
+      it "deletes the selected characters and enters insert mode", ->
+        expect(editorView).toHaveClass 'insert-mode'
+        expect(editor.getText()).toBe '0345'
+        expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+        expect(vimState.getRegister('"').text).toBe '12'

   describe "the S keybinding", ->
     beforeEach ->


Remove pane-view-spec

Remove pane-view-spec

--- spec/pane-view-spec.coffee
+++ spec/pane-view-spec.coffee
@@ -1,47 +0,0 @@
-PaneContainer = require '../src/pane-container'
-PaneView = require '../src/pane-view'
-fs = require 'fs-plus'
-{Emitter, Disposable} = require 'event-kit'
-{$, View} = require '../src/space-pen-extensions'
-path = require 'path'
-temp = require 'temp'
-
-describe "PaneView", ->
-  [container, containerModel, view1, view2, editor1, editor2, pane, paneModel, deserializerDisposable] = []
-
-  class TestView extends View
-    @deserialize: ({id, text}) -> new TestView({id, text})
-    @content: ({id, text}) -> @div class: 'test-view', id: id, tabindex: -1, text
-    initialize: ({@id, @text}) ->
-      @emitter = new Emitter
-    serialize: -> {deserializer: 'TestView', @id, @text}
-    getURI: -> @id
-    isEqual: (other) -> other? and @id is other.id and @text is other.text
-    changeTitle: ->
-      @emitter.emit 'did-change-title', 'title'
-    onDidChangeTitle: (callback) ->
-      @emitter.on 'did-change-title', callback
-    onDidChangeModified: -> new Disposable(->)
-
-  beforeEach ->
-    jasmine.snapshotDeprecations()
-
-    deserializerDisposable = atom.deserializers.add(TestView)
-    container = atom.views.getView(new PaneContainer).__spacePenView
-    containerModel = container.model
-    view1 = new TestView(id: 'view-1', text: 'View 1')
-    view2 = new TestView(id: 'view-2', text: 'View 2')
-    waitsForPromise ->
-      atom.workspace.open('sample.js').then (o) -> editor1 = o
-
-    waitsForPromise ->
-      atom.workspace.open('sample.txt').then (o) -> editor2 = o
-
-    runs ->
-      pane = container.getRoot()
-      paneModel = pane.getModel()
-      paneModel.addItems([view1, editor1, view2, editor2])
-
-  afterEach ->
-    deserializerDisposable.dispose()
-    jasmine.restoreDeprecationsSnapshot()


fixed issue with send

fixed issue with send

--- communist.coffee
+++ communist.coffee
@@ -2,7 +2,7 @@
 	return  if typeof fun isnt "function"
 	if window.Worker
 		window.URL = window.URL or window.webkiURL
-		body = "var _f =  #{ fun.toString() };self.addEventListener('message', function(_e) {var send = function(data){self.postMessage({messege:data,cb:_e.data.cb})};try{self.postMessage({body:_f.apply(null, _e.data.body),cb:_e.data.cb})}catch(_err){self.postMessege({error:_err,cb:_e.data.cb})}})"
+		body = "var send;var _f =  #{ fun.toString() };self.addEventListener('message', function(_e) {send = function(data){self.postMessage({messege:data,cb:_e.data.cb})};try{self.postMessage({body:_f.apply(null, _e.data.body),cb:_e.data.cb})}catch(_err){self.postMessege({error:_err,cb:_e.data.cb})}})"
 		blob = new Blob [body],
 			type: "text/javascript"
 		bUrl = window.URL.createObjectURL(blob)
@@ -16,7 +16,7 @@
 				if  e.data.body
 					@CBs[e.data.cb] null, e.data.body
 					delete @CBs[e.data.cb]
-				else if e.body.messege
+				else if e.data.messege
 					@CBs[e.data.cb] null, e.data.messege
 				else if e.data.error
 					CBs[e.data.cb] e.data.error


Fix backslash escaping issues

Fix backslash escaping issues

--- spec/tree-view-spec.coffee
+++ spec/tree-view-spec.coffee
@@ -2388,7 +2388,11 @@
         expect(zetaEntries).toEqual(["zeta.txt"])

       it "squashes two dir names when the first only contains a single dir", ->
-        betaDir = $(treeView.roots[0].entries).find(".directory:contains(alpha#{path.sep}beta):first")
+        if path.sep is '\\'
+          # First escape the backslashes for Coffeescript, then escape them for jQuery
+          betaDir = $(treeView.roots[0].entries).find(".directory:contains(alpha\\\\beta):first")
+        else
+          betaDir = $(treeView.roots[0].entries).find(".directory:contains(alpha#{path.sep}beta):first")
         betaDir[0].expand()
         betaEntries = [].slice.call(betaDir[0].children[1].children).map (element) ->
           element.innerText
@@ -2396,7 +2400,11 @@
         expect(betaEntries).toEqual(["beta.txt"])

       it "squashes three dir names when the first and second only contain single dirs", ->
-        epsilonDir = $(treeView.roots[0].entries).find(".directory:contains(gamma#{path.sep}delta#{path.sep}epsilon):first")
+        if path.sep is '\\'
+          # First escape the backslashes for Coffeescript, then escape them for jQuery
+          epsilonDir = $(treeView.roots[0].entries).find(".directory:contains(gamma\\\\delta\\\\epsilon):first")
+        else
+          epsilonDir = $(treeView.roots[0].entries).find(".directory:contains(gamma#{path.sep}delta#{path.sep}epsilon):first")
         epsilonDir[0].expand()
         epsilonEntries = [].slice.call(epsilonDir[0].children[1].children).map (element) ->
           element.innerText


Kill unneeded ()

Kill unneeded ()

--- src/nack/client.coffee
+++ src/nack/client.coffee
@@ -38,7 +38,7 @@
     # Initialize the response netstring parser
     @_initResponseParser()

-  _initResponseParser: () ->
+  _initResponseParser: ->
     # Initialize a Netstring stream parser
     nsStream = new ns.Stream this

@@ -52,7 +52,7 @@
       @_incoming = null
       @emit 'error', exception

-  _processRequest: () ->
+  _processRequest: ->
     # Process the request now if the socket is open and
     # we aren't already handling a response
     if @readyState is 'open' and !@_incoming
@@ -64,7 +64,7 @@
       # Try to reconnect and try again soon
       @reconnect()

-  _finishRequest: () ->
+  _finishRequest: ->
     @_outgoing.shift()

     res = @_incoming


Fixed typo on requirements

Fixed typo on requirements


spec : localhost

spec : localhost

--- spec/lib/loopback-info.coffee
+++ spec/lib/loopback-info.coffee
@@ -34,7 +34,7 @@
     describe 'getURL', ->

         it 'returns URL with host, port and api root info', ->
-            expect(@lbInfo.getURL()).to.equal('0.0.0.0:3000/api')
+            expect(@lbInfo.getURL()).to.equal('localhost:3000/api')

     describe 'getEnv', ->


social: add options for kite protocol

social: add options for kite protocol

--- workers/social/lib/social/main.coffee
+++ workers/social/lib/social/main.coffee
@@ -16,6 +16,7 @@

 {exec} = require 'child_process'
 {extend} = require 'underscore'
+{ join: joinPath } = require 'path'

 process.on 'uncaughtException', (err)->
   exec './beep'
@@ -58,6 +59,27 @@
   models      : './models'
   resourceName: social.queueName
   mq          : broker
+
+  kite          :
+    kontrol     : 'ws://localhost:4000'
+    name        : 'social'
+    environment : 'vagrant'
+    region      : 'vagrant'
+    version     : KONFIG.version
+    username    : 'koding'
+    kiteKey     : joinPath __dirname, '../../../../kite_home/koding/kite.key'
+
+    fetchClient: (name, context, callback) ->
+      { JAccount } = koding.models
+      [callback, context] = [context, callback] unless callback
+      context   ?= group: 'koding'
+      callback  ?= ->
+      JAccount.one 'profile.nickname': name, (err, account) ->
+        return callback err  if err?
+
+        if account instanceof JAccount
+          callback null, { context, connection:delegate:account }
+
   fetchClient :(sessionToken, context, callback)->
     { JUser, JAccount } = koding.models
     [callback, context] = [context, callback] unless callback


remove unnecessary function

remove unnecessary function

--- spec/text-objects-spec.coffee
+++ spec/text-objects-spec.coffee
@@ -17,9 +17,6 @@
   keydown = (key, options={}) ->
     options.element ?= editorElement
     helpers.keydown(key, options)
-
-  commandModeInputKeydown = (key, opts = {}) ->
-    editor.commandModeInputView.editorElement.getModel().setText(key)

   describe "the 'iw' text object", ->
     beforeEach ->


Test to expose circular structure bug in impl

Finally looked at implementation and saw that it'd recurse
infinitely for objects with circular structures, which is
definitely not good (and will break td.js even when not
using matchers

--- test/src/when-test.coffee
+++ test/src/when-test.coffee
@@ -39,7 +39,7 @@
     Then -> @testDouble(44, 5) == undefined
     Then -> @testDouble(88, "five") == undefined

-  describe 'using deep matcher', ->
+  describe 'using deep matchers', ->
     context 'single level', ->
       Given -> td.when(@testDouble(key: td.matchers.isA(String))).thenReturn("yay")
       Then -> @testDouble(key: "testytest") == "yay"
@@ -59,6 +59,16 @@
       Then -> @testDouble([5, 6]) == undefined
       Then -> @testDouble([5]) == undefined
       Then -> @testDouble([]) == undefined
+
+    context 'arguments with circular structures', ->
+      Given -> @arg =
+        foo: 'bar'
+      Given -> @arg.baz = @arg
+      Given -> td.when(@testDouble(@arg)).thenReturn("yay")
+      Then -> @testDouble(@arg) == "yay"
+      Then -> @testDouble('no') == undefined
+
+

   describe 'stubbing sequential returns', ->
     context 'a single stubbing', ->


"empty" schema marker

"empty" schema marker

--- src/schema-generator.coffee
+++ src/schema-generator.coffee
@@ -50,6 +50,8 @@
     if firstLevel
       schemaDict["$schema"] = SCHEMA_VERSION
       schemaDict["id"] = "#"
+      if typeof(baseObject) == 'object' and Object.keys(baseObject).length == 0
+        schemaDict["empty"] = true

     if objectId isnt undefined
       schemaDict["id"] = objectId


permanently return true from sendMail method; hopefully fixes #262

--- server/methods/mail/send.coffee
+++ server/methods/mail/send.coffee
@@ -39,7 +39,7 @@
 				text: TAPi18n.__('push.teamCancellation.text', {date: date, time: time} , user.profile.language)
 				query: userId: user._id
 		else
-			sent = Mailer.send
+			Mailer.send
 				to: data.recipient
 				from: data.sender + ' <no-reply@jwmanagement.org>'
 				replyTo: data.sender + '<' + data.from + '>'
@@ -47,4 +47,6 @@
 				template: data.template
 				data: data.data

+			sent = true
+
 	sent


Groups: Inviter's name is revealed in invitation message

--- client/Dashboard/views/groupsinvitationview.coffee
+++ client/Dashboard/views/groupsinvitationview.coffee
@@ -90,14 +90,15 @@
             placeholder   : "(optional)"

   getDefaultInvitationMessage:->
+    fullName = "#{KD.whoami().profile.firstName} #{KD.whoami().profile.lastName}"
     """
     Hi there,

-    #INVITER# has invited you to the group #{@getData().title}.
+    #{fullName} has invited you to the group #{@getData().title}.

     This link will allow you to join the group: #URL#

-    If you reply to this email, it will go to #INVITER#.
+    If you reply to this email, it will go to #{fullName}.

     Enjoy! :)
     """


activity: update reference to `KD.utils` namespace

--- client/Social/Activity/views/embedboxwidget.coffee
+++ client/Social/Activity/views/embedboxwidget.coffee
@@ -68,7 +68,7 @@
     input.on 'change', fn

   checkInputForUrls: ->
-    @utils.defer =>
+    KD.utils.defer =>
       input = @getDelegate()
       text = input.getValue()


StackTemplateListItem: Revert pistachio changes and start to use pistachio again

--- client/app/lib/stacks/stacktemplatelistitem.coffee
+++ client/app/lib/stacks/stacktemplatelistitem.coffee
@@ -42,31 +42,9 @@

   buildViews: ->

-    stackTemplate = @getData()
-    { meta, isDefault, inUse, accessLevel, config, title } = stackTemplate
-
-    @addSubView @info = new kd.CustomHTMLView
-      cssClass  : 'stacktemplate-info clearfix'
-
-    @info.addSubView @title = new StackTemplateListItemTitle {}, stackTemplate
-
-    @info.addSubView @labels  = new kd.CustomHTMLView
-      cssClass  : 'labels'
-
-    @info.addSubView @lastUpdatedView = new StackTemplateListItemLastUpdated {}, stackTemplate
-
-    @addSubView @buttons  = new kd.CustomHTMLView
-      cssClass   : 'buttons'
-
-    @buttons.addSubView @settings
-    @buildLabels()
-
-
-  buildLabels: ->
-
     { isDefault, inUse, accessLevel, config } = @getData()

-    @labels.addSubView @isDefaultView = new kd.CustomHTMLView
+    @isDefaultView = new kd.CustomHTMLView
       cssClass   : 'custom-tag'
       partial    : 'DEFAULT'
       attributes :
@@ -74,7 +52,7 @@
       tooltip    :
         title    : 'This group currently using this template'

-    @labels.addSubView @inUseView     = new kd.CustomHTMLView
+    @inUseView   = new kd.CustomHTMLView
       cssClass   : 'custom-tag'
       partial    : 'IN USE'
       attributes :
@@ -82,7 +60,7 @@
       tooltip    :
         title    : 'This template is in use'

-    @labels.addSubView @notReadyView  = new kd.CustomHTMLView
+    @notReadyView = new kd.CustomHTMLView
       cssClass   : 'custom-tag not-ready'
       partial    : 'NOT READY'
       attributes :
@@ -90,32 +68,37 @@
       tooltip    :
         title    : 'Template is not verified or credential data is missing'

-    @labels.addSubView @accessLevelView = new kd.CustomHTMLView
+    @accessLevelView = new kd.CustomHTMLView
       cssClass   : "custom-tag #{accessLevel}"
       partial    : accessLevel.toUpperCase()
       attributes :
         testpath : 'StackAccessLevelTag'
       tooltip    :
-        title    : switch accessLevel
-          when 'public'
-            'This group currently using this template'
-          when 'group'
-            'This template can be used in group'
-          when 'private'
-            'Only you can use this template'
+        title    : @getAccessLevelTooptipTitle accessLevel

     @isDefaultView.hide() unless isDefault
     @inUseView.hide()     unless inUse
     @notReadyView.hide()  if config.verified

-  updateLabels: ->
+  getAccessLevelTooptipTitle: (accessLevel) ->

-    @isDefaultView?.destroy()
-    @inUseView?.destroy()
-    @notReadyView?.destroy()
-    @accessLevelView?.destroy()
-    @buildLabels()
+    switch accessLevel
+      when 'public'
+        'This group currently using this template'
+      when 'group'
+        'This template can be used in group'
+      when 'private'
+        'Only you can use this template'
+
+
+  # updateLabels: ->
+
+  #   @isDefaultView?.destroy()
+  #   @inUseView?.destroy()
+  #   @notReadyView?.destroy()
+  #   @accessLevelView?.destroy()
+  #   @buildLabels()

   _itemSelected: (data) ->
@@ -138,3 +121,16 @@
     #     new ForceToReinitModal {}, stackTemplate

     super
+
+
+  pistachio: ->
+
+    { meta } = @getData()
+
+    """
+

+      {div.title{#(title)}} {{> @isDefaultView}} {{> @inUseView}} {{> @notReadyView}} {{> @accessLevelView}}
+      Last updated #{timeago meta.modifiedAt}
+

+
{{> @settings}}

+    """


StackTemplateListItem: Do not use pistachio

--- client/app/lib/stacks/stacktemplatelistitem.coffee
+++ client/app/lib/stacks/stacktemplatelistitem.coffee
@@ -108,16 +108,3 @@
     #     new ForceToReinitModal {}, stackTemplate

     super
-
-
-  pistachio: ->
-
-    { meta } = @getData()
-
-    """
-

-      {div.title{#(title)}} {{> @isDefaultView}} {{> @inUseView}} {{> @notReadyView}} {{> @accessLevelView}}
-      Last updated #{timeago meta.modifiedAt}
-

-
{{> @settings}}

-    """


Add missed argument.

Add missed argument.

--- client/ide/lib/views/statusbar/idestatusbar.coffee
+++ client/ide/lib/views/statusbar/idestatusbar.coffee
@@ -61,7 +61,7 @@
       href     : "#{kd.singletons.router.getCurrentPath()}/share"
       title    : 'Loading'
       cssClass : 'share fr hidden'
-      click    : =>
+      click    : (event) =>
         kd.utils.stopDOMEvent event
         return  if @hasClass 'loading'
         return  unless appManager.frontApp.mountedMachine.isRunning()


Remove dead code

Remove dead code

--- lib/client/user_media_getter.coffee
+++ lib/client/user_media_getter.coffee
@@ -1,31 +0,0 @@
-'use strict'
-
-class @UserMediaGetter
-  constructor: (@_mediaConfig) ->
-
-  getUserMedia: ->
-    # There may be no media config, for no video/audio
-    unless @mediaConfig?
-      return callback()
-    addStreamToRtcPeerConnection = =>
-      @_rtcPeerConnection.addStream(@_localStream)
-    if @_localStream? and _.isEqual(@mediaConfig, @_lastMediaConfig)
-      # Already have a local stream and the media config has not changed, so
-      # we will keep on using the same stream.
-      addStreamToRtcPeerConnection()
-      return callback()
-    @_lastMediaConfig = _.clone(@mediaConfig)
-    @_waitingForUserMedia.set(true)
-    navigator.getUserMedia @mediaConfig, (stream) =>
-      @_localStream = stream
-      addStreamToRtcPeerConnection()
-      @_localStreamUrl.set URL.createObjectURL(stream)
-      if callback?
-        callback()
-      @_waitingForUserMedia.set(false)
-    , (error) =>
-      @_waitingForUserMedia.set(false)
-      @_lastGetUserMediaError.set(error)
-      @_logError(error)
-
-


minimize diff by restoring function locations

--- common/static/coffee/src/discussion/content.coffee
+++ common/static/coffee/src/discussion/content.coffee
@@ -78,6 +78,16 @@
         if @getContent(id)
           @getContent(id).updateInfo(info)
       $.extend @contentInfos, infos
+
+    pinThread: ->
+      pinned = @get("pinned")
+      @set("pinned",pinned)
+      @trigger "change", @
+
+    unPinThread: ->
+      pinned = @get("pinned")
+      @set("pinned",pinned)
+      @trigger "change", @

     flagAbuse: ->
       temp_array = @get("abuse_flaggers")
@@ -128,16 +138,6 @@
       @get("votes")["up_count"] = parseInt(@get("votes")["up_count"]) - 1
       @trigger "change", @

-    pinThread: ->
-      pinned = @get("pinned")
-      @set("pinned",pinned)
-      @trigger "change", @
-
-    unPinThread: ->
-      pinned = @get("pinned")
-      @set("pinned",pinned)
-      @trigger "change", @
-
     display_body: ->
       if @has("highlighted_body")
         String(@get("highlighted_body")).replace(/<highlight>/g, '<mark>').replace(/<\/highlight>/g, '</mark>')


added help indicator for passing arguments to scripts run with `coffee`

--- command.coffee
+++ command.coffee
@@ -21,10 +21,10 @@

 # The help banner that is printed when `coffee` is called without arguments.
 BANNER = '''
-  Usage: coffee [options] path/to/script.coffee
+  Usage: coffee [options] path/to/script.coffee -- [args]

   If called without options, `coffee` will run your script.
-         '''
+'''

 # The list of all the valid option flags that `coffee` knows how to handle.
 SWITCHES = [


Fix for keeping document auto selected

Fix for keeping document auto selected

--- lib/markdown-table-formatter.coffee
+++ lib/markdown-table-formatter.coffee
@@ -25,9 +25,11 @@

         autoSelectEntireDocument = atom.config.get("markdown-table-formatter.autoSelectEntireDocument")

+        autoSelected = false
         if selectionsRanges[0].isEmpty() and autoSelectEntireDocument
             # console.log('all selected')
             editor.selectAll()
+            autoSelected = true
             selectionsRanges = editor.getSelectedBufferRanges()

         # console.log('myIterator')
@@ -46,6 +48,10 @@

         if restoreSelections
             editor.setSelectedBufferRanges(initialSelectionsRanges)
+
+        if autoSelectEntireDocument and autoSelected
+            for selection in editor.getSelections()
+                selection.clear()

     formatTable: (text) ->
         # console.log(text)


Refactor filter

Refactor filter

--- lib/notational-velocity-view.coffee
+++ lib/notational-velocity-view.coffee
@@ -49,6 +49,8 @@
     return titleItem

   filter: (filterQuery) ->
+    if filterQuery == "" || filterQuery == undefined
+      return @docQuery.documents
     return @docQuery.search(filterQuery)

   getFilterKey: ->
@@ -123,11 +125,7 @@

   populateList: ->
     filterQuery = @getFilterQuery()
-    filteredItems = null
-    if filterQuery == "" || filterQuery == undefined
-      filteredItems = @docQuery.documents
-    else
-      filteredItems = @filter(filterQuery)
+    filteredItems = @filter(filterQuery)

     selectedItem = @selectItem(filterQuery)


Add remove block XML snippet

Add remove block XML snippet

--- .atom/snippets.cson
+++ .atom/snippets.cson
@@ -34,3 +34,7 @@
   'Magento layout reference':
     'prefix': 'ref'
     'body': '<reference name="${1:name}">$2</reference>'
+  'Magento layout remove':
+    'prefix': 'remove'
+    'body': '<remove name="${1:name}" />'
+


Remove quotes from popup-removal delay setting

Actually, I didn't remove the quotes, Atom did. Serious business, guys.

--- .config/config.cson
+++ .config/config.cson
@@ -1,5 +1,4 @@
 "*":
-  "popupDismissDelay": 700
   "SFTP-deployment": {}
   "asciidoc-preview": {}
   "atom-beautify":
@@ -47,6 +46,7 @@
   "find-and-replace":
     showSearchWrapIcon: false
   hex: {}
+  popupDismissDelay: 700
   "recent-files":
     updated: false
   "remote-edit": {}


_setChildNamespaceProps on all modules which are functions (classes or functions) if a module has a .class property that is a funciton (class or function), call _setChildNamespaceProps on that too

--- src/Runtime/Neptune.coffee
+++ src/Runtime/Neptune.coffee
@@ -63,8 +63,11 @@
     @allNamespaces[@namespacePath] = namespace.initAsSubNamespace name, @
     namespace

+  isFunction = (f) -> typeof f == "function"
+
   @_setChildNamespaceProps: (name, child) ->
-    if typeof child == "function" && name.match /^[A-Z]/
+    if isFunction child
+      @_setChildNamespaceProps name, child.class if isFunction child.class
       child.namespace = @
       child.namespacePath = @namespacePath + "." + name


Grab dependency field from service defs when wrapping in middleware

--- lib/wrapServicesInMiddleware.coffee
+++ lib/wrapServicesInMiddleware.coffee
@@ -22,6 +22,7 @@
       # attach meta-data
       wrapper.serviceName = serviceName
       wrapper.callStack = []
+      wrapper.dependencies = serviceDef.dependencies || {}

       # expose a function for adding to the stack
       wrapper.prepend = (services) ->


Fix typo

Fix typo

--- client/entry.coffee
+++ client/entry.coffee
@@ -18,7 +18,7 @@

       Router.map ->
         @route 'signUp',
-          path: 'sign-up',
+          path: '/sign-up',
           template: appConfig.signUpTemplate

 @AccountsEntry = AccountsEntry


:memo: doc parameters in select-list-view.coffee

--- src/select-list-view.coffee
+++ src/select-list-view.coffee
@@ -64,14 +64,14 @@

   # Public: Set the array of items to display in the list.
   #
-  # * array: The array of model elements to display in the list.
+  # array - The {Array} of model elements to display in the list.
   setArray: (@array=[]) ->
     @populateList()
     @setLoading()

   # Public: Set the error message to display.
   #
-  # * message: The error message.
+  # message - The {String} error message (default: '').
   setError: (message='') ->
     if message.length is 0
       @error.text('').hide()
@@ -81,7 +81,7 @@

   # Public: Set the loading message to display.
   #
-  # * message: The loading message.
+  # message - The {String} loading message (default: '').
   setLoading: (message='') ->
     if message.length is 0
       @loading.text("")
@@ -131,8 +131,8 @@
   #
   # Subclasses may override this method to customize the message.
   #
-  # * itemCount: The number of items in the array specified to {.setArray}
-  # * filteredItemCount: The number of items that pass the fuzzy filter test.
+  # itemCount - The {Number} of items in the array specified to {.setArray}
+  # filteredItemCount - The {Number} of items that pass the fuzzy filter test.
   getEmptyMessage: (itemCount, filteredItemCount) -> 'No matches found'

   selectPreviousItem: ->
@@ -184,7 +184,7 @@
   #
   # This method should be overridden by subclasses.
   #
-  # * element: The selected model element.
+  # element - The selected model element.
   confirmed: (element) ->

   attach: ->


PCE yields promises

PCE yields promises

--- lib/processingchainentrance.coffee
+++ lib/processingchainentrance.coffee
@@ -16,14 +16,10 @@

   forward_operation: (operation) =>
     message = JSON.stringify(operation)
-    q = Q.all [
+    Q.all([
       @journal.record(message)
-      @replication.send(message)]
-
-    q.then(=> @package_operation(operation))
-     .then(@on_operation_succeded)
-     #.fail(@on_operation_failed)
-     #.done()
+      @replication.send(message)
+    ]).then(=> @package_operation(operation))

   package_operation: (operation) =>
     deferred = Q.defer()
@@ -33,10 +29,3 @@
       deferred.reject(err)

     return deferred.promise
-
-
-  on_operation_succeded: (update_set) =>
-    #console.log "success:", update_set
-
-  on_operation_failed: (error) =>
-    console.log "failure:", error