Updated ListView: - Removed jQuery dependency - Improved internal organisation - Added sort method - Added utility methods to get indexes of objects and views and to get the view for an object. - setContent -> reset - addItem -> add - removeItem -> remove

--- src/view.coffee
+++ src/view.coffee
@@ -375,87 +375,147 @@
 # List view class. Allows easy creation and updating of a list of views.
 class LRSListView extends LRSView

+	# ### initialize
 	initialize: (content = null) ->
-		unless @permanentContent
-			@permanentContent = @el.children()
-			@permanentViews = _.clone(@views)
-			delete @permanentViews.content
-			@permanentViewsArray = (view.el[0] for name, view of @permanentViews)
-
 		super()

+		# Check if content is provided and if we have views already (it is assumed initialize is not called anymore after proper initialization).
 		if content and @views.content
+			# Yes; it's preloaded content. Use it.
 			@setPreloadedContent(content)
 		else
-			@setContent(content)
-
+			# No; it's normal content (or nothing). Use it.
+			@reset(content)
+
+		@
+
+	# ### setPreloadedContent
+	# Properly initialize the views we already have from the DOM with correct data and get our own references in order.
 	setPreloadedContent: (content) ->
+
+		# Set content to nothing.
+		@content = []
+
+		# Prepare for loop.
 		previousView = null
-		@content = []
+
+		# Iterate all objects provided.
 		for object, i in content
-			@content.push(object)
-
+
+			# Check if we already have a view for them.
+			# Set default to null.
 			view = null
+
+			# Iterate all our content views.
 			for v in @views.content
-				if v.el.attr('data-id') is object.id
+				# If the data-id attribute is the object's id, it belongs to the object; set view and break from loop.
+				if v.el.getAttribute('data-id') is object.id
 					view = v
 					break
-
+
+			# Check if we found a view.
 			if view
+				# Yes; initialize it.
 				view.initialize(object)
 			else
+			# TODO: Order!
 				view = new @options.itemClass(null, null, @).initialize(object)
 				if previousView
 					view.insertAfter(previousView.el)
 					@views.content.splice(i, 0, view)
 				else
 					view.appendTo(@el)
-
+
+			@content.push(
+				object: object
+				view: view
+			)
+
+	reset: (content) ->
+		#return console.log('d') if not _.isNull(content) and not _.isArray(content)
+		return if content is null and (not @content or @content.length is 0)
+
+		@views.content or= []
+
+		if @views.content.length
+			for view in @views.content
+				view.remove().deinitialize()
+
+		@content = []
+
+		if content isnt null
+			for object, i in content
+				@_processObject(object, i)

-			#@views[_.uniqueId('lvi_')] = view
-
-	setContent: (content) ->
-		return if not _.isNull(content) and not _.isArray(content)
-		return if content is null and @content = []
-
-		@views[name] = view for name, view of @permanentViews
-		@views.content = []
-		@el.children().not(@permanentViewsArray).remove()
-
-		if content is null
-			@content = []
-		else
-			@content = []
-			for object, i in content
-				@content.push object
-				@_processObject(object, i)
-
-	addItem: (item, before = false) ->
-		#if before
-			#beforeIndex = _.indexOf(@content, item)
-			#@content.splice(beforeIndex, 0, item)
+		@
+
+	setContent: @::reset
+
+	sort: (content) ->
+		return if not content.length > 0 or not @content
+
+		newContent = []
+		newContentViews = []
+
+		for object in content
+			c = @content[@indexForObject(object)]
+			newContent.push(c)
+			newContentViews.push(c.view)
+
+		@content = newContent
+		@views.content = newContentViews
+
+		reinsert = @withdraw()
+
+		for view in @views.content
+			view.appendTo(@)
+
+		reinsert()
+
+	add: (object, before = false) ->
 		if before is true
-			@content.unshift item
 			i = 0
 		else if before is false
-			@content.push item
-			i = @content.length - 1
-		else
-			i = _.indexOf(@content, before)
-			@content.splice(i, 0, item)
-
-		@_processObject(item, i)
-
-	removeItem: (object) ->
-		i = @content.indexOf(object)
-		@content.splice(i, 1)
+			i = @content.length# - 1
+		else
+			i = @indexForObject(before)
+			i = @content.length if i is -1
+
+		@_processObject(object, i)
+
+	addItem: @::add
+
+	remove: (object) ->
+		i = @indexForObject(object)
+		removed = @content.splice(i, 1)
 		@views.content[i].remove().deinitialize()
 		@views.content.splice(i, 1)
+
+	removeItem: @::remove
+
+	# TODO? contentForObject (object) ->
+	indexForObject: (object) ->
+		for c, i in @content
+			if c.object is object
+				return i
+		return -1
+
+	indexForView: (view) ->
+		for c, i in @content
+			if c.view is view
+				return i
+		return -1
+
+	viewForObject: (object) ->
+		i = @indexForObject(object)
+		return undefined if i is -1
+		return @content[i].view
+
+	# TODO? objectForView: (object) ->

 	_processObject: (object, i) ->
-		#i = _.indexOf(@content, object)
-		if (!object.isView)
-			if (@options.itemClass)
+		if not object.isView # TODO: Use a more reliable check.
+			if @options.itemClass
 				view = new @options.itemClass(null, null, @).initialize(object)
 			else
 				view = new lrs.LRSView.views.LRSGeneratedListItemView(@options.subTemplate, null, @).initialize(object)
@@ -465,8 +525,14 @@
 		if i is @views.content.length
 			view.appendTo(@el)
 		else
-			view.el.insertBefore(@views.content[i].el)
-		@views.content.splice(i, 0, view)
+			@el.insertBefore(view.el, @views.content[i].el)
+
+		@content.splice(i, 0,
+			object: object
+			view: view
+		)
+
+		@views.content.splice(i, 0, view) # TODO: Should we keep the views in the right order or just push?

 		view


Added insertAfter

Added insertAfter

--- src/view.coffee
+++ src/view.coffee
@@ -200,6 +200,9 @@

 	insertBefore: (el) ->
 		@el.insertBefore(el)
+
+	insertAfter: (el) ->
+		@el.insertAfter(el)

 	addClass: (classes) ->
 		@el.addClass(classes)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/game_object.coffee
+++ src/game_object.coffee
@@ -161,7 +161,7 @@
       I.active = false
   }

-  defaultModules = [Bindable, Bounded, Cooldown, Drawable, Durable, Metered, ]
+  defaultModules = [Bindable, Bounded, Cooldown, Drawable, Durable, Metered, TimedEvent]
   modules = defaultModules.concat(I.includedModules.invoke('constantize'))
   modules = modules.without(I.excludedModules.invoke('constantize'))


live edit sprites (moving auto sprite load into drawable)

--- src/game_object.coffee
+++ src/game_object.coffee
@@ -4,10 +4,8 @@
   $.reverseMerge I,
     age: 0
     active: true
-    color: "#880"
     created: false
     destroyed: false
-    spriteName: null
     x: 0
     y: 0
     width: 8
@@ -15,14 +13,7 @@
     solid: false
     includedModules: []
     excludedModules: []
-
-
-  if I.spriteName
-    I.sprite = Sprite(I.spriteName, (sprite) ->
-      I.width = sprite.width
-      I.height = sprite.height
-    )
-
+
   self = Core(I).extend
     update: ->
       I.age += 1


Use onDidChangeText instead of onWillChange

--- lib/csound-pattern.coffee
+++ lib/csound-pattern.coffee
@@ -17,21 +17,22 @@
       @userDefinedOpcodesByWorkspaceIDs[workspace.id] = userDefinedOpcodes

       @subscriptions.add workspace.observeTextEditors((editor) =>
-        @subscriptions.add editor.buffer.onWillChange((event) ->
-          # bufferRangeForScopeAtPosition is a private method of TextEditor
-          # (https://github.com/atom/atom/search?q=bufferRangeForScopeAtPosition+path%3Asrc+filename%3Atext-editor.coffee)
-          range = editor.bufferRangeForScopeAtPosition('entity.name.function.opcode.csound', event.oldRange.start)
+        @subscriptions.add editor.buffer.onDidChangeText((event) ->
+          for change in event.changes
+            # bufferRangeForScopeAtPosition is a private method of TextEditor
+            # (https://github.com/atom/atom/search?q=bufferRangeForScopeAtPosition+path%3Asrc+filename%3Atext-editor.coffee)
+            range = editor.bufferRangeForScopeAtPosition('entity.name.function.opcode.csound', event.oldRange.start)

-          if range
-            index = userDefinedOpcodes.indexOf(editor.getTextInBufferRange(range))
-            if index >= 0
-              userDefinedOpcodes.splice(index, 1)
-              # tokenizedBuffer is a private property of TextEditor
-              # (https://github.com/atom/atom/search?q=tokenizedBuffer+path%3Asrc+filename%3Atext-editor.coffee)
-              # that returns an instance of the private class TokenizedBuffer
-              # (https://github.com/atom/atom/search?q=invalidateRow+path%3Asrc+filename%3Atokenized-buffer.coffee)
-              for row in [0...editor.getLineCount()] when !editor.isBufferRowCommented(row)
-                editor.tokenizedBuffer.invalidateRow(row)
+            if range
+              index = userDefinedOpcodes.indexOf(editor.getTextInBufferRange(range))
+              if index >= 0
+                userDefinedOpcodes.splice(index, 1)
+                # tokenizedBuffer is a private property of TextEditor
+                # (https://github.com/atom/atom/search?q=tokenizedBuffer+path%3Asrc+filename%3Atext-editor.coffee)
+                # that returns an instance of the private class TokenizedBuffer
+                # (https://github.com/atom/atom/search?q=invalidateRow+path%3Asrc+filename%3Atokenized-buffer.coffee)
+                for row in [0...editor.getLineCount()] when !editor.isBufferRowCommented(row)
+                  editor.tokenizedBuffer.invalidateRow(row)
         )
       )


Tweak mobile version media query

Tweak mobile version media query

--- assets/javascripts/app/app.coffee
+++ assets/javascripts/app/app.coffee
@@ -211,7 +211,8 @@
     try
       # Need to sniff the user agent because some Android and Windows Phone devices don't take
       # resolution (dpi) into account when reporting device width/height.
-      @_isMobile ?= (window.matchMedia('(max-device-width: 767px), (max-device-height: 767px)').matches) or
+      @_isMobile ?= (window.matchMedia('(max-device-width: 767px)').matches) or
+                    (window.matchMedia('(max-device-height: 767px) and (max-device-width: 1024px)').matches) or
                     (navigator.userAgent.indexOf('Android') isnt -1 and navigator.userAgent.indexOf('Mobile') isnt -1) or
                     (navigator.userAgent.indexOf('IEMobile') isnt -1)
     catch


Ignore exceptions when 827 has been overriden

--- assets/javascripts/app/app.coffee
+++ assets/javascripts/app/app.coffee
@@ -1,5 +1,6 @@
 @app =
   $: $
+  $$: $$
   collections: {}
   models:      {}
   templates:   {}
@@ -142,7 +143,7 @@
   isInjectionError: ->
     # Some browser extensions expect the entire web to use jQuery.
     # I gave up trying to fight back.
-    window.$ isnt app.$
+    window.$ isnt app.$ or window.$$ isnt app.$$

   isAppError: (error, file) ->
     # Ignore errors from external scripts.


fixed trash icon showing up when switching between droppables

--- plugins/image.coffee
+++ plugins/image.coffee
@@ -286,7 +286,7 @@
                             $(".tmpBig").replaceWith $(".tmp, editable")  if $(".tmpBig")
                             tmpObject.removeClass("inlineImage-middle inlineImage-left inlineImage-right").addClass("inlineImage-" + position).css "display", "block"
                         helper.showOverlay position
-                    helper.delayAction createTmpObject, 300
+                    helper.delayAction createTmpObject, 150

                 handleStartEvent: (event, ui) ->
                     $(document).trigger('startPreventSave');
@@ -329,33 +329,36 @@
                     dnd.init(editable)

                 handleOverEvent: (event, ui) ->
-                  # todo: handle with a class
-                  # temorary fix to avoid "handleOverEvent" to be fired before "handleLeaveEvent"
-                  delay = ->
-                    $(ui.helper).css "border", "3px solid white"
-                    $(ui.helper).find('.trashcan').remove()
-
-                    editable.append overlay.big
-                    editable.append overlay.left
-                    editable.append overlay.right
-
-                    helper.removeTmpNodes()
-                    position = helper.calcPosition(ui, offset)
-
-                    createTmp = ->
-                        if position is "middle"
-                            helperInsert = helper.createHelperElement()
-                        else
-                            helperInsert = helper.createInsertElement(ui, true)
-                        $(event.target).prepend helperInsert
-                        helper.showOverlay position
-
-                    helper.delayAction createTmp, 100
-                  helper.delayAction delay, 5
+                    # temorary fix to avoid "handleOverEvent" to be fired before "handleLeaveEvent"
+                    delay = ->
+                        window.timeoutTrash = clearTimeout(window.timeoutTrash)  if window.timeoutTrash
+                        # todo: handle with a class
+                        $(ui.helper).css "border", "3px solid white"
+                        $(ui.helper).find('.trashcan').remove()
+
+                        editable.append overlay.big
+                        editable.append overlay.left
+                        editable.append overlay.right
+
+                        helper.removeTmpNodes()
+                        position = helper.calcPosition(ui, offset)
+
+                        createTmp = ->
+                            if position is "middle"
+                                helperInsert = helper.createHelperElement()
+                            else
+                                helperInsert = helper.createInsertElement(ui, true)
+                            $(event.target).prepend helperInsert
+                            helper.showOverlay position
+
+                        helper.delayAction createTmp, 100
+                    helper.delayAction delay, 5

                 handleLeaveEvent: (event, ui) ->
-                    $(ui.helper).append($('

'))
-                    $('.bigBlueOverlay, .smallDottedOverlay').remove()
+                    func = ->
+                        $(ui.helper).append($('

'))
+                        $('.bigBlueOverlay, .smallDottedOverlay').remove()
+                    window.timeoutTrash = setTimeout(func , 300)
                     helper.removeTmpNodes()

                 createHelper: (event) ->


the best javascript color library

the best javascript color library

--- src/color.coffee
+++ src/color.coffee
@@ -116,7 +116,19 @@

       rgba: -> "rgba(#{self.r()}, #{self.g()}, #{self.b()}, #{self.a()})"

-
+      toHex: ->
+        hexString = (number) ->
+          number.toString(16)
+        padString = (hexString) ->
+          if hexString.length == 1
+            return hexString = "0" + hexString
+
+          return hexString
+
+        hexFromNumber = (number) ->
+          return padString(hexString(number))
+
+        "##{hexFromNumber(channels[0])}#{hexFromNumber(channels[1])}#{hexFromNumber(channels[2])}"

       toString: -> self.rgba()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -43,7 +43,7 @@

     if arguments.length == 0
       parsedColor = [0, 0, 0, 0]
-    else if arguments.length == 1 && Object.prototype.toString.call(arguments[0]) == '[object Array]'
+    else if arguments.length == 1 && Object.isArray(arguments[0])
       alpha = if arguments[0][3]? then arguments[0][3] else 1
       parsedColor = [
         parseInt(arguments[0][0]),


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -605,6 +605,23 @@

     ###*
     A new color. The calling color mixed with `other` using `amount` as the mixing ratio. If amount is not passed, then the colors are mixed evenly.
+
+

+    red = Color(255, 0, 0)
+    yellow = Color(255, 255, 0)
+
+    # With no arguments the colors are mixed evenly
+    orange = red.mixWith(yellow)
+
+    orange.toString()
+    # => 'rgba(255, 128, 0, 1)'
+
+    # With this argument we are mixing the color 30% red and 70% yellow
+    somethingCloseToOrange = red.mixWith(yellow, 0.3)
+
+    somethingCloseToOrange.toString()
+    # => rgba(255, 179, 0, 1)
+

     @name mixWith
     @methodOf Color#


Add a query param to teacher class view to skip calculation

For really large classes where the calculation takes too long

--- app/views/courses/TeacherClassView.coffee
+++ app/views/courses/TeacherClassView.coffee
@@ -75,6 +75,7 @@

   initialize: (options, classroomID) ->
     super(options)
+    @skipCalculation = utils.getQueryVariable('skipCalculation')
     # wrap templates so they translate when called
     translateTemplateText = (template, context) => $('<div />').html(template(context)).i18n().html()
     @singleStudentCourseProgressDotTemplate = _.wrap(require('templates/teachers/hovers/progress-dot-single-student-course'), translateTemplateText)
@@ -224,6 +225,7 @@
     @classroom?.loaded and @classroom?.get('members')?.length is 0 or (@students?.loaded and @classroom?.sessions?.loaded)

   calculateProgressAndLevels: ->
+    return if @skipCalculation # TODO: Fix perf for this function for large classes, remove this
     return unless @supermodel.progress is 1 and @allStatsLoaded()
     # TODO: How to structure this in @state?
     for student in @students.models


Disabling xhr_streaming is stupid.

Disabling xhr_streaming is stupid.

--- src/sockjs.coffee
+++ src/sockjs.coffee
@@ -36,7 +36,7 @@
             origins: ['*:*']
             disabled_transports: []
         if @options.sockjs_url
-            throw "options.sockjs_url is required!"
+            throw new Error("options.sockjs_url is required!")
         if user_options
             $.extend(@options, user_options)

@@ -58,6 +58,8 @@
             ['OPTIONS', t('/xhr'), opts_filters],
             ['POST',    t('/xhr_send'), ['xhr_cors', 'expect_xhr', 'xhr_send']],
             ['OPTIONS', t('/xhr_send'), opts_filters],
+            ['POST',    t('/xhr_streaming'), ['xhr_cors', 'xhr_streaming']],
+            ['OPTIONS', t('/xhr_streaming'), opts_filters],
         ]
         maybe_add_transport = (name, urls) ->
             if options.disabled_transports.indexOf(name) isnt -1
@@ -70,9 +72,6 @@
                 ['GET', t('/websocket'), ['websocket']]])
         maybe_add_transport('eventsource',[
                 ['GET', t('/eventsource'), ['h_no_cache', 'eventsource']]])
-        maybe_add_transport('xhr-streaming',[
-                ['POST',    t('/xhr_streaming'), ['xhr_cors', 'xhr_streaming']],
-                ['OPTIONS', t('/xhr_streaming'), opts_filters]])
         webjs_handler = new webjs.WebJS(app, dispatcher)

         install_handler = (ee, event, handler) ->


Prevent the level status tile from taking space in the status bar if not in the Levels workspace

--- lib/level-status-view.coffee
+++ lib/level-status-view.coffee
@@ -28,6 +28,8 @@
     @workspaceSubscrs.add workspace.onDidChangeActiveLevel \
       (activeLevel) =>
         @updateOnDidChangeActiveLevelOfWorkspace(activeLevel)
+    # initially hide the level status
+    @hide()

   destroy: ->
     @workspaceSubscrs.dispose()


Revert "Don't re-throw errors from `.wrap`"

This reverts commit 248ed36af74778b9003c329c7a9a7f204746ca8f.

--- src/honeybadger.coffee
+++ src/honeybadger.coffee
@@ -51,6 +51,7 @@
         func.apply(this, arguments)
       catch e
         Honeybadger.notify(e)
+        throw e

   reset: () ->
     @resetContext()


+ load option to initialize method to determine whether call load(), default to false

--- src/subkey.coffee
+++ src/subkey.coffee
@@ -105,10 +105,18 @@
       @_initialize(aKeyPath, aOptions) if @_initialize
       defineProperty @, '_loadingState_', null
       @setLoadingState "unload"
-      @load(aReadyCallback)
+      vWannaLoad = aOptions.load if aOptions
       that = @
-      @on "ready", ->
-        that.load(aReadyCallback)
+      if vWannaLoad
+        delete aOptions.load
+        @load(aReadyCallback)
+        @on "ready", ->
+          that.load(aReadyCallback)
+      else if aReadyCallback #notify when the database is ready.
+        if dbCore.isOpen() is true
+          setImmediate aReadyCallback.bind(@, null, @)
+        else
+          @on "ready", (err, result)-> aReadyCallback.call that, err, result
     finalize: (isFreeSubkeys)->
       @_finalize(isFreeSubkeys) if @_finalize
       @freeSubkeys() if isFreeSubkeys isnt false


clarified debug message

clarified debug message

--- lib/query/QueryWriter.coffee
+++ lib/query/QueryWriter.coffee
@@ -15,12 +15,12 @@
     readyMixin.call(@)
     debugMixin.call(@)

-    @debug 'Waiting for cache manager...'.blue
+    @debug "'#{@sourceName}' waiting for cache manager...".blue

     @cacheManager.ready =>

       idSet = @_getIdSet()
-      @debug 'Cache ready! Initial idSet:'.blue, idSet
+      @debug "'#{@sourceName}' running... Initial idSet:".blue, idSet
       if _.isArray(idSet) and _.isEmpty(idSet)
         @emit 'ready'


Tweaked Soundcloud regex to be stricter

Tweaked Soundcloud regex to be stricter

Limit to playlists only

--- src/aotw.coffee
+++ src/aotw.coffee
@@ -35,7 +35,7 @@

         # Restrict commands denoted by a tilde to the following users.
         # If left empty, any user can issue restricted commands.
-        @admins = ["colt", "thomas","stevendiaz", "Shell"] #hehe
+        @admins = ["colt", "thomas", "stevendiaz", "Shell"]

         @robot.brain.on "loaded", storageLoaded
         storageLoaded()
@@ -84,10 +84,10 @@
     nominate: (msg) ->
         if msg.match[1] != ""
             url = msg.match[2]
-            spotify = /https?:\/\/(open|play)\.spotify\.com\/(album|track|user\/[^\/]+\/playlist)\/([a-zA-Z0-9]+)/
-            googlePlay = /https?:\/\/(music|play)\.google\.com\/music\/m\/([a-zA-Z0-9]+)/
-            youtube = /https?:\/\/(?:www\.)?youtube.com\/watch\?(?=.*v=\w+)(?:\S+)?/
-            soundCloud = /^https?:\/\/(soundcloud.com|snd.sc)\/(.*)$/
+            spotify = /^https?:\/\/(open|play)\.spotify\.com\/(album|track|user\/[^\/]+\/playlist)\/([a-zA-Z0-9]+)$/
+            googlePlay = /^https?:\/\/(music|play)\.google\.com\/music\/m\/([a-zA-Z0-9]+)$/
+            youtube = /^https?:\/\/(?:www\.)?youtube.com\/watch\?(?=.*v=\w+)(?:\S+)?$/
+            soundCloud = /^https?:\/\/(soundcloud.com)\/(.*)\/(sets)\/(.*)$/
             if url.match(spotify) or url.match(googlePlay) or url.match(youtube) or url.match(soundCloud)
                 user = msg.message.user.name.toLowerCase()
                 try


Fix config check.

Fix config check.

--- src/base.coffee
+++ src/base.coffee
@@ -19,7 +19,7 @@
 		package_name = require('./package').name
 		@userConfig = new Configstore package_name
 		@_.extend this, @userConfig.all
-		if not @authorName and options.name isnt 'init'
+		if not @authorName and options.namespace isnt 'tamia:init'
 			@stop 'Generator config not found. Please run yo tamia:init.'

 		# Single folder for all templates


reactivity: code documentation fix

reactivity: code documentation fix

--- client/app/lib/messageeventmanager.coffee
+++ client/app/lib/messageeventmanager.coffee
@@ -125,14 +125,16 @@

     message.body = Encoder.XSSEncode message.body

-    # Every time message is updated, we need to synchronize
-    # its payload and link properties which contain embed.ly data.
-    # They have the same object structure and data with the only
-    # difference that payload.link_embed is string representation
-    # of json object while link.link_embed is payload.link_embed
-    # parsed to js object.
-    # If payload is null or doesn't contain embed.ly data,
-    # link should be deleted
+    ###
+      Every time message is updated, we need to synchronize
+      its payload and link properties which contain embed.ly data.
+      They have the same object structure and data with the only
+      difference that payload.link_embed is string representation
+      of json object while link.link_embed is payload.link_embed
+      parsed to js object.
+      If payload is null or doesn't contain embed.ly data,
+      link should be deleted
+    ###
     { payload } = message
     if payload?.link_url
       message.link =


rm logs

rm logs

--- client/apps/dashboard/client/index.coffee
+++ client/apps/dashboard/client/index.coffee
@@ -18,8 +18,6 @@
     $el = $(e.currentTarget)
     $entry = $el.closest('.entry')
     id = $entry.data('id')
-
-    console.log 'get from event', $entry, id, @collection.get id

     entry = @collection.get id


Added zoom and pan to the map

Added zoom and pan to the map

--- client/browser/fleetCommander/maps.coffee
+++ client/browser/fleetCommander/maps.coffee
@@ -1,5 +1,6 @@
 height = null
 width = null
+nodeContainer = null
 svg = null
 Session.set("mapRegion", "Derelik")

@@ -16,7 +17,7 @@

 redraw = ->
   #console.log "here", d3.event.translate, d3.event.scale
-  svg.attr "transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"
+  nodeContainer.attr "transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"

 Template.fcMiddle.rendered = ->
   svg = d3.select("#fcMiddle").append("svg").attr("width", width).attr("height", height).attr("pointer-events", "all")
@@ -25,16 +26,17 @@
 rerender = ->
   $("#fcMiddle svg").empty()
   svg.append('svg:g').call(d3.behavior.zoom().on("zoom", redraw)).append('svg:g').append('svg:rect').attr('width', width).attr('height', height).attr('fill', 'white')
+  nodeContainer = svg.append('svg:g').attr('width', width).attr('height', height)
   color = d3.scale.category20()
-  force = d3.layout.force().size([width, height]).charge(-200).gravity(0.05)#.linkDistance(30)
+  force = d3.layout.force().size([width, height]).charge(-200).gravity(0.05).linkDistance(30)
   d3.json "/data/"+Session.get("mapRegion")+".json", (error, graph) ->
     console.log graph
     svg.append("text").attr("x", (width / 2)).attr("y", '50px').style("font-weight", "bold").attr("text-anchor", "middle").style("font-size", "24px").text(Session.get("mapRegion"))
     force.nodes(graph.systems).links(graph.jumps).start()
-    link = svg.selectAll(".link").data(graph.jumps).enter().append("line").attr("class", "link").style("stroke-width", (d) ->
+    link = nodeContainer.selectAll(".link").data(graph.jumps).enter().append("line").attr("class", "link").style("stroke-width", (d) ->
       Math.sqrt d.value
     )
-    node = svg.selectAll(".node").data(graph.systems).enter().append("g").attr("class", "node").call(force.drag)
+    node = nodeContainer.selectAll(".node").data(graph.systems).enter().append("g").attr("class", "node").call(force.drag)
     node.append("text").attr("dx", 12).attr("dy", ".35em").text (d) ->
       d.name
     node.append("circle").attr("r", 5)


client: don't redirect to Account page on pass. reset

--- client/landing/Login/AppController.coffee
+++ client/landing/Login/AppController.coffee
@@ -9,7 +9,7 @@
   handleResetRoute = ({params:{token}})->
     KD.singleton('appManager').open 'Login', (app) ->
       if KD.isLoggedIn()
-        KD.getSingleton('router').handleRoute "/Account/Profile?focus=password&token=#{token}"
+        KD.getSingleton('router').handleRoute "/Activity"
       else
         app.getView().setCustomDataToForm('reset', {recoveryToken:token})
         app.getView().animateToForm('reset')


JContextMenu: Update arrow margin based on the menu view margins on viewport.

--- components/contextmenu/contextmenu.coffee
+++ components/contextmenu/contextmenu.coffee
@@ -10,6 +10,9 @@
     options.arrow          ?= no

     super options, data
+
+    @topMargin  = 0
+    @leftMargin = 0

     o = @getOptions()

@@ -49,6 +52,11 @@
     o.placement or= "top"
     o.margin     ?= 0

+    if o.placement in ['top', 'bottom']
+      o.margin += @leftMargin
+    else
+      o.margin += @topMargin
+
     @arrow = new KDCustomHTMLView
       tagName  : "span"
       cssClass : "arrow #{o.placement}"
@@ -74,7 +82,7 @@

     @addSubView @arrow

-  positionContextMenu:()->
+  positionContextMenu:->
     options     = @getOptions()
     event       = options.event or {}
     mainView    = @getSingleton 'mainView'
@@ -88,13 +96,19 @@
     top         = (options.y or event.pageY or 0) + options.offset.top
     left        = (options.x or event.pageX or 0) + options.offset.left

+    expectedTop  = top
+    expectedLeft = left
+
     if top + menuHeight > mainHeight
       top  = mainHeight - menuHeight + options.offset.top

     if left + menuWidth > mainWidth
       left  = mainWidth - menuWidth + options.offset.left

+    @topMargin  = expectedTop  - top
+    @leftMargin = expectedLeft - left
+
     @getDomElement().css
       width     : "#{options.menuWidth}px"
       top       : top
-      left      : left+      left      : left


Another truthy

Another truthy

--- components/main_layout/header/view.coffee
+++ components/main_layout/header/view.coffee
@@ -52,7 +52,7 @@
         success: (result) =>
           totalUnread = result.get('total_unread')
           if result.get('feed').length > 0
-            if totalUnread > 0 and (Cookies.get('notification-count') != totalUnread)
+            if totalUnread > 0 and (Cookies.get('notification-count') !== totalUnread)
               bundleText = if totalUnread >= 100 then "99+" else totalUnread
               @$('.mlh-bundle-count')
                 .text("#{bundleText}")


:memo: Add arg to pane::destroyItem()

:memo: Add arg to pane::destroyItem()

--- src/pane.coffee
+++ src/pane.coffee
@@ -402,6 +402,8 @@
   # If the item is active, the next item will be activated. If the item is the
   # last item, the pane will be destroyed if the `core.destroyEmptyPanes` config
   # setting is `true`.
+  #
+  # * `item` Item to destroy
   destroyItem: (item) ->
     index = @items.indexOf(item)
     if index isnt -1


this isn't working

this isn't working

--- src/pane.coffee
+++ src/pane.coffee
@@ -9,9 +9,6 @@
   showing: false

   constructor: (@window) ->
-    $('.pane').live 'click', (event) =>
-      console.log @.constructor.name
-      true

   add: ->
     verticalDiv = $('#app-vertical')


:atom: Use faster fuzzy finder :rocket:

:atom: Use faster fuzzy finder :rocket:

--- atom/config.cson
+++ atom/config.cson
@@ -48,6 +48,8 @@
     revealTreeView: false
   "find-and-replace":
     projectSearchResultsPaneSplitDirection: "right"
+  "fuzzy-finder":
+    useRipGrep: true
   "highlight-line":
     enableBackgroundColor: false
   "markdown-preview":


Revert "Increase max line length to suppress E501 error"

This reverts commit 5c72bc60f99de2aca246f6c9af6cd5eb35709cfd.

--- atom/config.cson
+++ atom/config.cson
@@ -149,8 +149,6 @@
       "source.js.sca.ss"
       "source.ts"
     ]
-  "linter-flake8":
-    maxLineLength: 90
   "linter-ui-default":
     hidePanelWhenEmpty: true
     showPanel: true


Add key bindings for block travel

Add key bindings for block travel

--- atom/keymap.cson
+++ atom/keymap.cson
@@ -4,6 +4,8 @@
   'ctrl-shift-alt-t': 'custom:open-todo-list'
 'atom-text-editor':
   'ctrl-shift-a': 'asciidoc-preview:toggle'
+  'alt-up': 'block-travel:move-up'
+  'alt-down': 'block-travel:move-down'
 '.platform-darwin atom-workspace':
   'ctrl-"': 'toggle-quotes:toggle'
   'alt-cmd-n': 'advanced-open-file:toggle'


Add AVStreamGenerator class

Add AVStreamGenerator class

--- avstreams.coffee
+++ avstreams.coffee
@@ -14,6 +14,20 @@
   shasum = crypto.createHash 'sha512'
   shasum.update buf
   return shasum.digest('hex')[0..7]
+
+# Generates stream upon request
+class AVStreamGenerator
+  constructor: (methods) ->
+    if methods?.generate?
+      @generate = methods.generate
+    if methods?.teardown?
+      @teardown = methods.teardown
+
+    methods?.init?()
+
+  generate: ->
+
+  teardown: (stream) ->

 class AVStream
   constructor: (id) ->
@@ -158,9 +172,11 @@

 eventListeners = {}
 streams = {}
+streamGenerators = {}

 api =
   AVStream: AVStream
+  AVStreamGenerator: AVStreamGenerator

   emit: (name, data...) ->
     if eventListeners[name]?
@@ -188,7 +204,20 @@
     return streams[streamId]?

   get: (streamId) ->
-    return streams[streamId]
+    if streamGenerators[streamId]?
+      return streamGenerators[streamId].generate()
+    else
+      return streams[streamId]
+
+  addGenerator: (streamId, generator) ->
+    if streamGenerators[streamId]?
+      logger.warn "warning: avstreams.addGenerator(): overwriting generator: #{streamId}"
+    streamGenerators[streamId] = generator
+
+  removeGenerator: (streamId) ->
+    if streamGenerators[streamId]?
+      streamGenerators[streamId].teardown()
+    delete streamGenerators[streamId]

   createNewStreamId: ->
     retryCount = 0


Disable any element with the class '.disabled', not only anchors

To make it work for buttons, specially.

--- app/assets/javascripts/app/application/base.js.coffee
+++ app/assets/javascripts/app/application/base.js.coffee
@@ -19,7 +19,7 @@
       true # so it continues to the next callbacks, if any

     # Disable the click in any link with the 'disabled' class
-    $("a.disabled").on "click.mconfBase", (e) ->
+    $(".disabled").on "click.mconfBase", (e) ->
       e.preventDefault()
       true # so it continues to the next callbacks, if any

@@ -89,7 +89,7 @@

   @unbind: ->
     $("a.webconf-join-link:not(.disabled)").off "click.mconfBase"
-    $("a.disabled").off "click.mconfBase"
+    $(".disabled").off "click.mconfBase"
     $('a.link-to-expand').off "click.mconfBase"
     $('a.link-to-collapse').off "click.mconfBase"
     $('.visible-on-hover').each ->


fix for clarat-org/clarat#824 - unified (and decreased) search radius to 25km

--- app/assets/javascripts/search/queries/personal.coffee
+++ app/assets/javascripts/search/queries/personal.coffee
@@ -1,5 +1,5 @@
 class Clarat.Search.Query.Personal extends Clarat.Search.Query.Base
-  SEARCH_RADIUS: 50000
+  SEARCH_RADIUS: 25000

   # TODO: geolocation
   constructor: (@geolocation, @exact_location, args...) ->


CHANGE: scrollToChild now merely scrolls child onscreen and has a new, 2nd paramter if you want that child centered NEW: scrollAreaOnscreen, centerArea

--- source/Art/Engine/Elements/Widgets/ScrollElement.coffee
+++ source/Art/Engine/Elements/Widgets/ScrollElement.coffee
@@ -364,18 +364,41 @@
   ###################
   scrollToTop: -> @animateToValidScrollPosition @childrenSize
   scrollToBottom: -> @animateToValidScrollPosition -@childrenSize
-  scrollToChild: (child) -> @scrollToArea child.getClippedDrawAreaInAncestor @
-
-  scrollToArea: (area) ->
-
+  scrollToChild: (child, center) ->
+    if center
+      @centerArea child.getLogicalAreaInAncestor @
+    else
+      @scrollAreaOnscreen child.getLogicalAreaInAncestor @
+
+  scrollAreaOnscreen: (area) ->
+    {windowSize} = @
+
+    rangeStart  = @getAreaStart area
+    rangeEnd    = @getAreaEnd area
+
+    if rangeStart < 0
+      @animateToValidScrollPosition -rangeStart
+
+    else if rangeEnd > windowSize
+      @animateToValidScrollPosition max -rangeStart, windowSize - rangeEnd
+
+  getAreaStart: (area) ->
     if @isHorizontal
-      rangeStart  = area.left
-      rangeEnd    = area.right
-      windowSize  = @getCurrentSize().x
-    else
-      rangeStart  = area.top
-      rangeEnd    = area.bottom
-      windowSize  = @getCurrentSize().y
+      area.left
+    else
+      area.top
+
+  getAreaEnd: (area) ->
+    if @isHorizontal
+      area.right
+    else
+      area.bottom
+
+  centerArea: (area) ->
+    {windowSize} = @
+
+    rangeStart  = @getAreaStart area
+    rangeEnd    = @getAreaEnd area

     @animateToValidScrollPosition -(
       min(


enable br tag

enable br tag

--- src/ui/app.coffee
+++ src/ui/app.coffee
@@ -3,7 +3,7 @@
 trifl.expose window

 # expose some selected tagg functions
-trifl.tagg.expose window, ('ul li div span a i button table thead tbody tr td th input textarea pre'.split(' '))...
+trifl.tagg.expose window, ('ul li div span a i button table thead tbody tr td th input textarea pre br'.split(' '))...

 {applayout} = require './views'


remove unecessary position in app.coffee

--- src/ui/app.coffee
+++ src/ui/app.coffee
@@ -72,11 +72,7 @@
 require('./views/menu')(viewstate)

 # tie layout to DOM
-
-# restore last position of window
 currentWindow = remote.getCurrentWindow()
-
-currentWindow.setPosition viewstate.pos...

 document.body.appendChild applayout.el


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/level_state.coffee
+++ src/level_state.coffee
@@ -1,5 +1,5 @@
 ###*
-A Game State
+A Game State that loads up

 @see GameState
 @name LevelState


fix pygments repo link

fix pygments repo link

--- src/docco.coffee
+++ src/docco.coffee
@@ -17,7 +17,7 @@
 #
 # To install Docco, first make sure you have [Node.js](http://nodejs.org/),
 # [Pygments](http://pygments.org/) (install the latest dev version of Pygments
-# from [its Mercurial repo](http://dev.pocoo.org/hg/pygments-main)), and
+# from [its Mercurial repo](https://bitbucket.org/birkenfeld/pygments-main)), and
 # [CoffeeScript](http://coffeescript.org/). Then, with NPM:
 #
 #     sudo npm install -g docco


Remove dead/extraneous code; clean up

Remove dead/extraneous code; clean up

--- components/carousel/view.coffee
+++ components/carousel/view.coffee
@@ -53,31 +53,27 @@
   render: ->
     figures = @collection.models

-    @$el.html(carouselTemplate carouselFigures: figures, height: @height)
-
     if @length < @minLength
       @$el.empty()
-      return @
-
-    preFigures = figures[..]
-    postFigures = figures[..]
-    center = Math.ceil(@length / 2)
-
+      return this
+
+    @$el
+      .addClass('carousel-loading')
+      .html(carouselTemplate carouselFigures: figures, height: @height)
     @cacheSelectors()

-    @$el.addClass 'carousel-loading'
     # Start the carousel at the first image
     @setActive 0
     # When images are loaded, do the math
     if @$el?.imagesLoaded
       @$el.imagesLoaded => @setStops()
     # Ensure the carousel is revealed even if an image gets stuck
-    _.delay (=>
+    _.delay =>
       @$el.removeClass('carousel-loading')
       @setStops()
-    ), 5000
+    , 5000
     @bindEvents()
-    @
+    this

   # In order to prevent DOM manipulation, the stage has two copies of the figures.
   # For a list of 6 figures (numbered 1 through 6), the rendered list looks like this:
@@ -127,12 +123,10 @@

   bindEvents: ->
     # Bind key events to cycle the carousel
-    @$document.on "keyup.partner-show-carousel", (event) => @keyUp(event)
-
-    # Update the layout on window resize with a loading spinner while stops
-    # are re-calculated
+    @$document.on "keyup.partner-show-carousel", (e) => @keyUp(e)
+
+    # Update the layout on window resize
     throttledSetStops = _.throttle (=> @setStops()), 500
-    @$window.on "resize.partner-show-carousel", => @$el.addClass('loading')
     @$window.on "resize.partner-show-carousel", throttledSetStops

     # This will release the inTransition blocker when transitions complete


Remove extra w

Remove extra w

--- components/layout/client.coffee
+++ components/layout/client.coffee
@@ -169,7 +169,7 @@
     model = new Backbone.Model
       id: 'premium_message'
       title: "Help support Are.na"
-      body: "The more Are.na is supported by our users, the more freedom we have to make it the best it can be. If you're finding Are.na useful, consider upgrading to a premium account."
+      body: "The more Are.na is supported by our users, the more freedom we have to make it the best it can be. If you're finding Are.na useful, consider upgrading to a premium account."
       type: 'announcement'
     new MessageView container: $('#message-container'), model: model


Set view to always fit the world

Set view to always fit the world

--- views/map.coffee
+++ views/map.coffee
@@ -130,7 +130,7 @@

"

 $ ->
-  map = L.map('map').setView([28.3, 20.8], 3)
+  map = L.map('map').fitWorld()
   L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}@2x.png?access_token={accessToken}', {
     attribution: 'WOO Map @ GitHub | Map data © OpenStreetMap © Mapbox',
     maxZoom: 18,


ruby snippets update

ruby snippets update

--- atom.symlink/snippets.cson
+++ atom.symlink/snippets.cson
@@ -69,3 +69,12 @@
       it '${1:doesSomething}', ->

     """
+
+'.source.ruby':
+  'context test block':
+    'prefix': 'co'
+    'body': """
+      context "${1:someContext}" do
+
+      end
+    """


Removes jQuery binding to $(...).data

Removes jQuery binding to $(...).data

--- src/core.coffee
+++ src/core.coffee
@@ -1,10 +0,0 @@
-do (root = @) ->
-
-  root.$$ = (node) ->
-    data = $(node).data '$$'
-
-    unless data?
-      data = {}
-      $(node).data '$$', data
-
-    data


+ add more testing

+ add more testing

--- test/index-test.coffee
+++ test/index-test.coffee
@@ -242,26 +242,27 @@
       result = task.inspect()
       expect(result).to.be.equal '<Task "Simple": "one":124>'
   describe 'defineFunction', ->
-    fnSync = sinon.spy -> 'hi'
     beforeEach ->
+    afterEach ->
+    it 'should define the non-params function as a new task', ->
+      fnSync = sinon.spy -> 'hi'
       Task.defineFunction 'HiFnTask', fnSync
-      fnSync.reset()
-    afterEach ->
-      Task.unregister('/HiFn').should.be.ok
-    it 'should define the non-params function as a new task', ->
       task = Task 'HiFn'
       expect(task.executeSync()).to.be.equal 'hi'
       expect(fnSync).to.be.calledOnce
       expect(fnSync).to.be.calledOn task
+      Task.unregister('/HiFn').should.be.ok
     it 'should define the non-params function as a new task with specified self', ->
+      fnSync = sinon.spy -> 'hi'
       self = {}
       Task.defineFunction 'HiFn1Task', self:self, fnSync:fnSync
+      try
       task = Task 'HiFn1'
       expect(task.executeSync()).to.be.equal 'hi'
       expect(fnSync).to.be.calledOnce
       expect(fnSync).to.be.calledOn self
       Task.unregister('/HiFn1').should.be.ok
-    it 'should define the non-params function as a new task async', (done)->
+    it 'should define the non-params function as a new task asynchronously', (done)->
       fn = sinon.spy (cb)-> cb(null, 'hi')
       Task.defineFunction 'HiFn1Task', fn: fn
       task = Task 'HiFn1'
@@ -269,6 +270,17 @@
         expect(result).to.be.equal 'hi'
         expect(fn).to.be.calledOnce
         expect(fn).to.be.calledOn task
+        Task.unregister('/HiFn1').should.be.ok
+        done(err)
+    it 'should define the non-params function as a new task with specified self asynchronously', (done)->
+      fn = sinon.spy (cb)-> cb(null, 'hi')
+      self = {}
+      Task.defineFunction 'HiFn1Task', self:self, fn: fn
+      task = Task 'HiFn1'
+      task.execute (err, result)->
+        expect(result).to.be.equal 'hi'
+        expect(fn).to.be.calledOnce
+        expect(fn).to.be.calledOn self
         Task.unregister('/HiFn1').should.be.ok
         done(err)
     it 'should define the function with params as a new task', ->
@@ -277,3 +289,13 @@
       task = Task 'AddFn', a:1,b:20
       expect(task.executeSync()).to.be.equal 21
       expect(fn).to.be.calledOnce
+      Task.unregister('/AddFn').should.be.ok
+    it 'should define the function with params as a new task asynchronously', (done)->
+      fn = sinon.spy (a,b, cb)-> cb(null, a+b)
+      Task.defineFunction 'AddFnTask', params:[{name:'a'},{name:'b'}], fn: fn
+      task = Task 'AddFn', a:1,b:20
+      task.execute (err, result)->
+        expect(result).to.be.equal 21
+        expect(fn).to.be.calledOnce
+        Task.unregister('/AddFn').should.be.ok
+        done(err)


Update configuration file

Update configuration file

--- .config/config.cson
+++ .config/config.cson
@@ -1,17 +1,15 @@
 "*":
-  editor:
-    tabLength: 4
-    fontFamily: "Menlo"
-    softTabs: false
-    autoIndentOnPaste: false
-    invisibles: {}
-    lineHeight: 1.3
-    fontSize: 11
+  "SFTP-deployment": {}
+  "asciidoc-preview": {}
+  "atom-beautify":
+    _analyticsUserId: "84a7da30-e058-42d8-9fd2-cc0519eb2781"
+  "atom-material-ui":
+    fonts: {}
+    tabs: {}
+    ui: {}
+  "autoclose-html": {}
+  "autocomplete-plus": {}
   core:
-    themes: [
-      "atom-light-ui"
-      "phoenix-syntax"
-    ]
     disabledPackages: [
       "snippets"
       "SFTP-deployment"
@@ -24,30 +22,35 @@
       "background-tips"
       "welcome"
     ]
+    themes: [
+      "atom-light-ui"
+      "Phoenix-Syntax"
+    ]
+  docblockr: {}
+  editor:
+    autoIndentOnPaste: false
+    fontFamily: "Menlo"
+    fontSize: 11
+    invisibles: {}
+    lineHeight: 1.3
+    softTabs: false
+    tabLength: 4
   "exception-reporting":
     userId: "4b2dfe3a-7eef-a871-4d35-230cb11366f8"
+  "file-icons":
+    coloured: false
+  "find-and-replace": {}
+  hex: {}
+  "recent-files":
+    updated: false
+  "remote-edit": {}
+  "remote-sync": {}
+  "spell-check": {}
+  "status-bar": {}
+  "toggle-quotes": {}
+  "tree-view":
+    hideIgnoredNames: true
   welcome:
     showOnStartup: false
-  "tree-view":
-    hideIgnoredNames: true
   whitespace:
     removeTrailingWhitespace: false
-  "asciidoc-preview": {}
-  "autoclose-html": {}
-  "SFTP-deployment": {}
-  "remote-sync": {}
-  "remote-edit": {}
-  "file-icons":
-    coloured: false
-  "recent-files":
-    updated: false
-  "spell-check": {}
-  "autocomplete-plus": {}
-  "atom-beautify":
-    _analyticsUserId: "84a7da30-e058-42d8-9fd2-cc0519eb2781"
-  "status-bar": {}
-  hex: {}
-  docblockr: {}
-  "toggle-quotes": {}
-  "find-and-replace":
-    showSearchWrapIcon: false


Updating  to be

Updating  to be

--- src/guess.coffee
+++ src/guess.coffee
@@ -60,39 +60,39 @@

     number

-win = (msg) ->
-    msg.reply "#{msg.match[1]} is the right answer! You got it at the #{suffix(players[msg.message.user.name].attempts)} attempt."
-    restart msg.message.user.name
+win = (res) ->
+    res.reply "#{res.match[1]} is the right answer! You got it at the #{suffix(players[res.message.user.name].attempts)} attempt."
+    restart res.message.user.name
     #console.log players

 restart = (user) ->
     players[user] = null

 module.exports = (robot) ->
-    robot.respond /guess (\d{4})/i, (msg) ->
-        if not players[msg.message.user.name]?
+    robot.respond /guess (\d{4})/i, (res) ->
+        if not players[res.message.user.name]?
             # Initialize
-            players[msg.message.user.name] =
+            players[res.message.user.name] =
                 answer: newNumber()
                 attempts: 0

-        ++players[msg.message.user.name].attempts
+        ++players[res.message.user.name].attempts

-        if players[msg.message.user.name].answer is msg.match[1]
-            win msg
+        if players[res.message.user.name].answer is res.match[1]
+            win res
             return

-        feedback = checkNumber players[msg.message.user.name].answer, msg.match[1]
+        feedback = checkNumber players[res.message.user.name].answer, res.match[1]

-        msg.reply "#{feedback[0]}A #{feedback[1]}B"
+        res.reply "#{feedback[0]}A #{feedback[1]}B"

-    robot.respond /guess surrender/i, (msg) ->
-        if players[msg.message.user.name]
-            restart msg.message.user.name
-            msg.reply "New game session created! #{msg.random(failure)}"
+    robot.respond /guess surrender/i, (res) ->
+        if players[res.message.user.name]
+            restart res.message.user.name
+            res.reply "New game session created! #{res.random(failure)}"

-    robot.respond /guess tutorial/i, (msg) ->
-        msg.reply "The goal of this game is to guess a 4-digit number within the least number of attempts possible."
-        msg.send "With every guess, you will get a feedback indicating how many A and B you got with the guess."
-        msg.send "An A means: one of the digits is correct, and is also at the right place."
-        msg.send "A B means: one of the digits is a right number, but not at the right place."+    robot.respond /guess tutorial/i, (res) ->
+        res.reply "The goal of this game is to guess a 4-digit number within the least number of attempts possible."
+        res.send "With every guess, you will get a feedback indicating how many A and B you got with the guess."
+        res.send "An A means: one of the digits is correct, and is also at the right place."
+        res.send "A B means: one of the digits is a right number, but not at the right place."


Moved game init to own method, randomness

--- src/index.coffee
+++ src/index.coffee
@@ -1,19 +1,20 @@
 async = require 'async'
 {EventEmitter2: EventEmitter} = require 'eventemitter2'
+MersenneTwister = require 'mersennetwister'

 TimeManager = require './time-manager'
+Random = require './random'
 {Map} = require './map'

+{Dummy, FastDummy, Player} = require './creatures'
+
 {initialize, deinitialize, Renderer} = require './io/tty'
-
-{Dummy, FastDummy, Player} = require './creatures'

 class Game
 	constructor: ->
 		# console.error 'Starting game...'
-		@state = 'main menu'
+		@state = 'main-menu'

-		@timeManager = new TimeManager
 		@events = new EventEmitter
 			wildcard: yes
 			# newListener: yes
@@ -24,6 +25,15 @@
 		initialize @
 		@renderer = new Renderer @

+		@events.on 'key.c', (ch, key) =>
+			@quit() if key.ctrl
+
+		@events.on 'state.enter.game', =>
+			@initGame()
+
+	initGame: ->
+		@random = new Random(new MersenneTwister)
+		@timeManager = new TimeManager
 		@currentMap = new Map @, 50, 15

 		@entities = [
@@ -34,22 +44,22 @@

 		@timeManager.targets.push @entities...

-		@events.on 'key.c', (ch, key) =>
-			@quit() if key.ctrl
-
 	quit: ->
 		deinitialize @
 		process.exit 0

 	goState: (state) ->
+		@events.emit "state.exit.#{@state}", 'exit', @state
 		@state = state
+		@events.emit "state.enter.#{@state}", 'enter', @state
+
 		@renderer.invalidate()

 	main: ->
 		async.whilst (-> true),
 			(next) =>
 				switch @state
-					when 'main menu'
+					when 'main-menu'
 						@events.once 'key.s', =>
 							@goState 'game'
 							next()


Fix command description

Fix command description

--- src/index.coffee
+++ src/index.coffee
@@ -9,7 +9,7 @@
 #     https://developer.vimeo.com
 #
 # Commands:
-#   hubot vimeo <query> -> <url vimeo>
+#   hubot vimeo <query> -> Get a video url
 #
 # Author:
 #   lgaticaq


fix(debug): remove debug call

fix(debug): remove debug call

--- src/index.coffee
+++ src/index.coffee
@@ -99,5 +99,3 @@
   return

 module.exports = TlsaBuilder
-
-(new TlsaBuilder('tikatuka.io')).generateValue().then(console.log).catch console.error


Reduce logging.

Reduce logging.

--- src/index.coffee
+++ src/index.coffee
@@ -6,6 +6,7 @@
 # To temporarily introspect variables during development.
 spy = window
 slog = console.log # spy + log
+slog = () -> null

 spy.resolveCb = (data) ->
     window.d = data
@@ -488,9 +489,11 @@
 window.onload = main

 window.onhashchange = (e) ->
+    ###
     slog "onhashchange: #{location.hash}"
     slog "newURL: #{e.newURL}"
     slog "oldURL: #{e.oldURL}"
+    ###

     reload = false

@@ -510,9 +513,9 @@
     reload ||= reloadWhiteList.test(hash)

     if reload
-        slog "loading: #{e.newURL}"
+        # slog "loading: #{e.newURL}"
         window.location.reload()
     else
-        slog "skipping: #{e.newURL}"
-
-
+        # slog "skipping: #{e.newURL}"
+
+


Removed extraneous reference to mysql which was breaking connection initialization

--- src/index.coffee
+++ src/index.coffee
@@ -38,7 +38,7 @@
   deferred = Q.defer()
   console.log "connecting to MySQL..."
   connectWatch = durations.stopwatch().start()
-  connection = mysql.mysql.createConnection mysqlConfig
+  connection = mysql.createConnection mysqlConfig
   connection.connect (error) ->
     if error
       console.log "Error connecting to MySQL:", error, "\nStack:\n", error.stack
@@ -176,4 +176,3 @@
 # If run directly
 if require.main == module
   runScript()
-


testing

testing

--- src/index.coffee
+++ src/index.coffee
@@ -33,7 +33,6 @@
     if currentMeeting?
       console.log "====================================="
       console.log "curentMeeting found : ", currentMeeting
-      console.log "Valid Until: #{@validUntil}"
       meetingStartTime = _.get event, 'genisys.currentMeeting.startTime'
       noShowLimit = moment(meetingStartTime).utc().add(@limitMinutes, 'minute')
       if moment().isBefore(noShowLimit)


Added CUI.DataForm to the webpack build.

--- src/index.coffee
+++ src/index.coffee
@@ -122,6 +122,7 @@
 require('./elements/FormModal/FormModal.coffee')
 require('./elements/DataTable/DataTable.coffee')
 require('./elements/DataTable/DataTableNode.coffee')
+require('./elements/DataForm/DataForm.coffee')
 require('./elements/Select/Select.coffee')
 require('./elements/StickyHeader/StickyHeader.coffee')
 require('./elements/StickyHeader/StickyHeaderControl.coffee')


Resize icon almost always not wanted

Resize icon almost always not wanted

--- src/index.coffee
+++ src/index.coffee
@@ -13,11 +13,12 @@
       marginBottom: rhythm(1/4)

     input:
-      width: '100%'
       border: "1px solid"
       borderColor: gray(50)
       marginBottom: rhythm(1)
       padding: "calc(#{rhythm(3/4)} - 1px)"
+      resize: 'none'
+      width: '100%'

     button:
       fontSize: '1rem'


testing

testing

--- src/index.coffee
+++ src/index.coffee
@@ -43,7 +43,8 @@
         meetingId = _.get currentMeeting, 'meetingId'
         console.log "====================================="
         console.log "Ending meeting, validUntil: ", moment(@validUntil).toISOString()
-        console.log "meetingStartTime: #{meetingStartTime} and No show limit :#{noShowLimit.toISOString()}"
+        console.log "Ending meeting, current time: ", moment().toISOString()
+        console.log "meetingStartTime: #{meetingStartTime} and No show limit :#{noShowLimit.toISOString()}" if moment().utc().isAfter(noShowLimit)
         @endMeeting meetingId

   endMeeting: (meetingId) =>


Removed any reference to the global namepace, not used anymore

--- src/intro.coffee
+++ src/intro.coffee
@@ -2,13 +2,7 @@

 # @license The MIT License

-# Required ES5 features: Object.keys
-
-# get a reference to the global namespace
-root = exports ? this
-
-# get the XMLHttpRequest object from the global namespace
-#XMLHttpRequest = root.XMLHttpRequest
+# @NOTE: Required ES5 features: Object.keys

 # NPM module for XMLHttpRequest contains the real XMLHttpRequest into a
 # property inside the module


Set sources looks better

Set sources looks better

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

--- src/items.coffee
+++ src/items.coffee
@@ -28,9 +28,8 @@

     setSources = (effects) -> e.source = this for e in effects

-    # Set source of all effects
-    setSources @auras if @auras
-    setSources @passives if @passives
+    # Set sources of all effects
+    [@auras, @passives].map (el) -> setSources el if el
     @active.source = this if @active

     # Calculate stats


fixes #50, path from config file

fixes #50, path from config file

--- src/jscpd.coffee
+++ src/jscpd.coffee
@@ -41,7 +41,7 @@
     if typeof optionsNew.languages is 'string' then optionsNew.languages = optionsNew.languages.split ','

     if config.path
-      optionsNew.path = path.normalize "#{cwd}/#{config.path}"
+      optionsNew.path = path.normalize "#{options.path}/#{config.path}"
       cwd = options.path

     optionsNew.extensions = TokenizerFactory::getExtensionsByLanguages(optionsNew.languages)


Move call to prototype

Move call to prototype

--- src/label.coffee
+++ src/label.coffee
@@ -2,12 +2,12 @@

 class Label extends Shape
   constructor: (args = {}) ->
-    super args
-
     @_font = { size: 10, family: 'monospace' }
     @_text = 'text goes here'
     @_alignment = 'center'
     @fixed = true # Does not move with camera/parent objects
+
+    super(args)

     @fixed = args.fixed if args.hasOwnProperty('fixed')
     @font = args.font if args.hasOwnProperty('font')


Oscillator

Oscillator

--- test/oscillator.coffee
+++ test/oscillator.coffee
@@ -11,6 +11,7 @@
   equals o(7.5).toFixed(6), 0
   equals o(22.5).toFixed(6), 0

+  # Sin
   o = Oscillator
     period: 30
     amplitude: 10


moved sort

moved sort

--- mocks/cursor.coffee
+++ mocks/cursor.coffee
@@ -25,6 +25,10 @@

     return callback(null, json.length) if count or @_cursor.$count # only the count

+    if @_cursor.$sort and Array.isArray(json)
+      $sort_fields = if Array.isArray(@_cursor.$sort) then @_cursor.$sort else [@_cursor.$sort]
+      json.sort (model, next_model) => return Helpers.jsonFieldCompare(model, next_model, $sort_fields)
+
     # only select specific fields
     if @_cursor.$values
       $fields = if @_cursor.$white_list then _.intersection(@_cursor.$values, @_cursor.$white_list) else @_cursor.$values
@@ -50,9 +54,5 @@
     else if @_cursor.$white_list
       json = _.map(json, (item) => _.pick(item, @_cursor.$white_list))

-    if @_cursor.$sort
-      $sort_fields = if Array.isArray(@_cursor.$sort) then @_cursor.$sort else [@_cursor.$sort]
-      json.sort (model, next_model) => return Helpers.jsonFieldCompare(model, next_model, $sort_fields)
-
     callback(null, json)
     return # terminating


final code cleanup for install.coffee

final code cleanup for install.coffee

--- src/lib/install.coffee
+++ src/lib/install.coffee
@@ -11,12 +11,9 @@
 # the ID in use.
 chrome.extension.sendRequest type: 'info', (data) ->
   # Names of the classes to be removed from the targeted elements.
-  classes = [
-    'chrome_install_button'
-    'primary'
-  ]
+  classes = ['chrome_install_button', 'btn-primary', 'primary']
   # Disable all "Install" links on the homepage for Template.
-  for anchor in document.querySelectorAll "a.#{classes[0]}[href$=#{data.id}]"
-    anchor.className += ' disabled'
-    anchor.innerText  = 'Installed'
-    anchor.className  = anchor.className.replace cls, '' for cls in classes+  for link in document.querySelectorAll "a.#{classes[0]}[href$=#{data.id}]"
+    link.innerText = 'Installed'
+    link.classList.add 'disabled'
+    link.classList.remove cls for cls in classes


Work around silly CoffeeScript bug. Fixes #70.

--- lib/font/directory.coffee
+++ lib/font/directory.coffee
@@ -66,7 +66,8 @@

         return new Buffer(directory.data)

-    checksum = ([data...]) ->
+    checksum = (data) ->
+        data = [data...]
         while data.length % 4
             data.push 0


Non-breaking hyphens, do not bill as editable.

Added non-breaking hyphens to every instance of b-tree. No longer touting the
files as editable. That is not the point. Log files are not editable. These are
like log files though, in that they are plain text and easy enough to read.

--- src/lib/strata_.coffee
+++ src/lib/strata_.coffee
@@ -1,4 +1,4 @@
-# A Streamline.js friendly evented I/O b-tree for Node.js.
+# A Streamline.js friendly evented I/O b‑tree for Node.js.
 #
 # ## Purpose
 #
@@ -6,33 +6,33 @@
 # choosing, indexed for fast retrieval.
 #
 # Strata is faster than a flat file, lighter than a database, with more capacity
-# than an in memory tree.
+# than an in‑memory tree.
 #
-# Strata is a [b-tree](http://en.wikipedia.org/wiki/B-tree) implementation for
-# [Node.js](http://nodejs.org/) that is **evented**, **concurrent**,
-# **persistent** and **durable**.
-#
-# Strata is **evented**. It uses asynchronous I/O to read and write b-tree
-# pages, allowing your CPU to continue to do work while Strata waits on I/O.
-#
-# Strata is **concurrent**. Strata will satisfy any queries from its in memory
-# cache when it can, so requests can be satisifed, even when there are evented
-# I/O requests outstanding.
+# Strata is a [b‑tree](http://en.wikipedia.org/wiki/B-tree)
+# implementation for [Node.js](http://nodejs.org/) that is **evented**,
+# **concurrent**, **persistent** and **durable**.
+#
+# Strata is **evented**. It uses asynchronous I/O to read and write
+# b‑tree pages, allowing your CPU to continue to do work while Strata
+# waits on I/O.
+#
+# Strata is **concurrent**. Strata will answer any queries from its
+# in‑memory cache when it can, so requests can be satisifed even when
+# there are evented I/O requests outstanding.
 #
 # Strata is **persistent**. It stores your tree in page files. The page files
-# are plain old JSON, text files that are easy to manage. You can open them up
-# in a `vim` or EMACS, back them up using `tar`, check them into `git`, and
-# munge them with JavaScript.
+# are plain old JSON, text files that are easy to manage. You can view them with
+# `tail -f`, back them up hot using `rsync`, and version them with `git`.
 #
 # Strata is **durable**. It only appends records to to file, so a hard shutdown
 # will only ever lose the few last records added. Pages are journaled when they
 # are vacuumed or rewritten.
 #
-# Strata is a b-tree. A b-tree is a database primiative. Using Strata, you can
-# start to experiment with database designs of your own. You can use Strata to
-# build an MVCC database table, like PostgreSQL. You can create Strata b-trees
-# to create relationship indexes. You can use Strata to store what ever form of
-# JSON suits your needs like NoSQL databases.
+# Strata is a b‑tree. A b‑tree is a database primiative. Using
+# Strata, you can start to experiment with database designs of your own. You can
+# use Strata to build an MVCC database table, like PostgreSQL. You can create
+# Strata b‑trees to create relationship indexes. You can use Strata to
+# store what ever form of JSON suits your needs like NoSQL databases.
 #
 # Strata is two database primatives in one, because with a time series index,
 # you can use Strata as a write ahead-log.
@@ -43,9 +43,9 @@
 #
 # ## Terminology
 #
-# We refer to the nodes in our b-tree as *pages*. The term node conjures an
+# We refer to the nodes in our b‑tree as *pages*. The term node conjures an
 # image of a discrete component in a linked data structure that contains one,
-# maybe two or three, values. Nodes in a b-tree contain hundreds or thousands of
+# maybe two or three, values. Nodes in a b‑tree contain hundreds or thousands of
 # values. They are indexed. They are read from disk. They are allowed to fall
 # out of memory when they have not been recently referenced. These are behaviors
 # that conjure an image of a page of values.
@@ -54,33 +54,35 @@
 # *child*, *split* and *merge*.
 #
 # There is no hard and fast definition for all the terms. A leaf is a fuzzy
-# concept in b-tree literature, for example. We call a page that contains
+# concept in b‑tree literature, for example. We call a page that contains
 # records a *leaf page*. We call a non-leaf page a *branch page*. The term
 # *order* means different things to different people.  We define the order of a
 # branch page to be the maximum number of child pages, while the order of a leaf
 # page to be the maximum number of records.
 #
-# The term *b-tree* itself may not be correct. There are different names for
-# b-tree that reflect the variations of implementation, but those distinctions
+# The term *b‑tree* itself may not be correct. There are different names for
+# b‑tree that reflect the variations of implementation, but those distinctions
 # have blurred over the years. Our implemenation may be considered a b+tree,
 # since pages are linked, and records are stored only in the leaves.
 #
 # Terms specific to our implementation will be introduced as they are
 # encountered in the document.
 #
-# ## What is a b-tree?
-#
-# This documentation assumes that you understand the theory behind the b-tree,
+# ## What is a b‑tree?
+#
+# This documentation assumes that you understand the theory behind the
+# b‑tree,
 # and know the variations of implementation. If you are interested in learning
-# about b-trees you should start with the Wikipedia articles on
+# about b‑trees you should start with the Wikipedia articles on
 # [B-trees](http://en.wikipedia.org/wiki/B-tree) and
-# [B+trees](http://en.wikipedia.org/wiki/B%2B_tree). I was introduced to b-trees
+# [B+trees](http://en.wikipedia.org/wiki/B%2B_tree). I was introduced to
+# b‑trees
 # while reading [Algorithms in C](http://www.amazon.com/dp/0201314525), quite
 # some time ago.
 #
-# ## What flavor of b-tree is this?
-#
-# Strata is a b-tree with leaf pages that contain records ordered by the
+# ## What flavor of b‑tree is this?
+#
+# Strata is a b‑tree with leaf pages that contain records ordered by the
 # collation order of the tree. Records are stored for retrieval in constant
 # time, addressed by an integer index, so that they can be found using binary
 # search.
@@ -98,7 +100,7 @@
 # sibling pages next to each other can be combined to create a page less than
 # than the order they are merged.
 #
-# The b-tree always has a root branch page. The order of the tree increases when
+# The b‑tree always has a root branch page. The order of the tree increases when
 # the root branch page is split. It decreases when the root branch page is
 # merged. The split of the root branch is a different operation from the split
 # of a non-root branch, because the root branch does not have siblings.
@@ -120,7 +122,7 @@

 # ## Collation
 #
-# A b-tree has a collation defined by the application developer.
+# A b‑tree has a collation defined by the application developer.
 #
 # The collation is determined by the combination of an extractor and a
 # comparator. The extractor is used to extract a key from the stored record. The
@@ -134,7 +136,7 @@
 # we don't need the actual record, it will eventually be collected by a cache
 # purge, while the key will be retained. If the key is subset of a large record,
 # purging the records and retaining the keys will reduce the in memory size of
-# the b-tree.
+# the b‑tree.
 #
 # Also, the comparator is pretty easily generalized, while the exractor
 # is invariably specialized. You might have a single string comparator that you
@@ -143,18 +145,18 @@
 # ### Default Collation
 #
 # You will almost certainly define your down extractors and comparators, but the
-# b-tree has a default that works for b-tree that stores only JavaScript primitives.
+# b‑tree has a default that works for b‑tree that stores only JavaScript primitives.

 # Default comparator is good only for strings, use a - b for numbers.
 comparator = (a, b) ->
   if a < b then -1 else if a > b then 1 else 0

-# Default extractor returns the value as whole, i.e. a b-tree of strings.
+# Default extractor returns the value as whole, i.e. a b‑tree of strings.
 extractor = (a) -> a

 # ## Pages
 #
-# Our b-tree has two types of pages. Leaf pages and branch pages.
+# Our b‑tree has two types of pages. Leaf pages and branch pages.
 #
 # A *leaf page* contains records. A *branch page* contains references to other
 # pages.
@@ -162,7 +164,7 @@
 # Both leaf pages and branch pages are ordered according to the collation.
 #
 # To find a record, we descend a tree of branch pages to find the leaf page that
-# contains the record. That is a b-tree.
+# contains the record. That is a b‑tree.
 #
 # ## Page Storage
 #
@@ -271,7 +273,7 @@
   # We take the limits approach. The bluk of a cached page is the size of the
   # references array and the size of objects in records map. We keep track of
   # those sizes. When we reach a maxmimum size for cached records and page
-  # references for the entire b-tree, we trigger a cache purge to bring it below
+  # references for the entire b‑tree, we trigger a cache purge to bring it below
   # the maxiumum size. The purge will remove entries from the end of the
   # most-recently used list until the limit is met.
   #
@@ -297,7 +299,7 @@
   # each record loaded in memory when JSON serialized with JSON.
   #
   # This is not an exact measure of the system memory committed to the in memory
-  # representation of the b-tree. It ignores the house keeping associated with
+  # representation of the b‑tree. It ignores the house keeping associated with
   # each page.
   #
   # An exact mesure is not necessary. We only need to be sure to trigger a cache
@@ -325,7 +327,7 @@
   # is unlinked from the balance list, and linked to the head of the core list.
   #
   # We always move a page to the front of the core list when we reference it
-  # during b-tree descent.
+  # during b‑tree descent.

   # Create an most-recently used list head node and return it. We call this to
   # create the core and balance list in the constructor above.
@@ -361,7 +363,7 @@
   # * The leaf page file is a text file of JSON strings that is an append log of
   # record insertions and deletions.
   # * A leaf page cannot contain two records that share the same key, therefore
-  # the b-tree cannot contain duplicates.
+  # the b‑tree cannot contain duplicates.
   #
   # In the abstract, a leaf page is an array of records.  Given an integer, the
   # leaf page will return the record stored at the offset of the array. This
@@ -370,7 +372,7 @@
   # Our leaf page implemenation maintains an array of file positions called a
   # positions array. A file position in the positions array references a record
   # in the leaf page file by its file position. The positions in the positions
-  # array are sorted according to the b-tree collation of the referenced
+  # array are sorted according to the b‑tree collation of the referenced
   # records.
   #
   # In the leaf page file, a record is stored as JSON string. The objects are
@@ -382,7 +384,7 @@
   # can search for a record in a leaf page using binary search in logorithmic
   # time.
   #
-  # Leaf pages cannot contain duplicate records. Therefore, the b-tree cannot
+  # Leaf pages cannot contain duplicate records. Therefore, the b‑tree cannot
   # contain duplicate records. You can simulate duplicate records by adding a
   # series value to your key. The cursor implementation is designed faciliate
   # psuedo-duplicates in this fashion.
@@ -525,7 +527,7 @@

   # Write an insert object. Calculate the serialized JSON string length of the
   # inserted record and add it to the in memory JSON size of the page and the in
-  # memory b-tree as a whole. We always use the JSON serialization we already
+  # memory b‑tree as a whole. We always use the JSON serialization we already
   # perform for storage, instead of serializing for both storage and size
   # calculation.
   writeInsert: (fd, page, index, record, _) ->
@@ -540,7 +542,7 @@

   # Write a delete object. Calculate the serialized JSON string length of the
   # inserted record and add it to the in memory JSON size of the page and the in
-  # memory b-tree as a whole.
+  # memory b‑tree as a whole.
   #
   # TODO Document `ghost`.
   writeDelete: (fd, page, index, ghost, _) ->
@@ -679,8 +681,8 @@
   #
   # We open a file descriptor and then close it after the record has been read.
   # The desire to cache the file descriptor is strong, but it would complicate
-  # the shutdown of the b-tree. As it stands, we can always simply let the
-  # b-tree succumb to the garbage collector, because we hold no other system
+  # the shutdown of the b‑tree. As it stands, we can always simply let the
+  # b‑tree succumb to the garbage collector, because we hold no other system
   # resources that need to be explictly released.
   #
   # Note how we allow we keep track of the minimum buffer size that will
@@ -743,13 +745,13 @@
   # the left most leaf page of a child and using the leaf page page key.
   # * The root branch page is always at address `0`.
   #
-  # To find the a record in the b-tree, we first use a tree of branch pages to
+  # To find the a record in the b‑tree, we first use a tree of branch pages to
   # find the leaf page that contains our record.
   #
   # A branch page contains the addresses of child pages. This array of page
   # addresses is essentially an *array of children*.
   #
-  # The child addresses are ordered according to the b-tree collation of the
+  # The child addresses are ordered according to the b‑tree collation of the
   # keys of the directly or indirectly referenced leaf pages.
   #
   # There are three types of branch pages, penultimate branch pages, interior
@@ -760,12 +762,13 @@
   # A penultimate branch page is a branch page whose children are leaf pages. If
   # a branch page is not penultimate, then its children are branch pages.
   #
-  # In a penultimate branch page, the array of children is ordered by the b-tree
+  # In a penultimate branch page, the array of children is ordered by the
+  # b‑tree
   # collation using a first record in the referenced leaf page for ordering.
   # That is, the first record of the leaf page is used as the key associated
   # with a page address in a penultimate branch page.
   #
-  # The non-leaf nodes of a b-tree have the property that the number of node
+  # The non-leaf nodes of a b‑tree have the property that the number of node
   # children is one greater than the number of keys. We obtain this property by
   # treating the first child as the left child of the entire page, and excluding
   # its key from the search. We search the subsequent keys to find the first key
@@ -799,14 +802,14 @@
   # branch page the subsequent children have an associated key that is the first
   # record of a leaf page.
   #
-  # The key is obtained by decending the sub-tree referenced by the child. We
+  # The key is obtained by decending the sub‑tree referenced by the child. We
   # first visit the branch page referneced by the child. We then visit left
   # children recursively, visiting the left child of the child, and the left
   # child of any subsquently visited children, until we reach a leaf page.  The
   # first record of that leaf page is the key to associate with the child
   # address in the address array of the interior branch page.
   #
-  # It is the nature of the b-tree that keys move up to the higher levels of the
+  # It is the nature of the b‑tree that keys move up to the higher levels of the
   # tree as pages split, while preserving the collation order of the keys. When
   # a branch page splits, a key from the middle of the page is chosen as a
   # partition. The partition is used as the key for the right half of the split
@@ -836,7 +839,7 @@
   # #### Root Branch Page
   #
   # The root page is the first page we consult to find the desired leaf page.
-  # Our b-tree always contains a root page. The b-tree is never so empty that
+  # Our b‑tree always contains a root page. The b‑tree is never so empty that
   # the root page disappears. The root page always has the same address.
   #
   # TK move. Until the root branch page is split, it is both the root branch
@@ -866,7 +869,7 @@
   # of a leaf page, and that leaf page is the left most leaf page in the entire
   # tree.
   #
-  # This maintains a property of the b-tree that for every leaf page except the
+  # This maintains a property of the b‑tree that for every leaf page except the
   # left most leaf page, there exists a unique branch page key derived from the
   # first record of the page.
   #
@@ -916,7 +919,7 @@
   # We write the branch page to a file as a single JSON object on a single line.
   # We tuck the page properties into an object, and then serialize that object.
   # We do not store the branch page keys. They are looked up as needed as
-  # described in the b-tree overview above.
+  # described in the b‑tree overview above.
   #
   # We always write a page branch first to a replacement file, then move it
   # until place using `relink`.
@@ -931,7 +934,7 @@
     buffer[json.length] = 0x0A
     fs.writeFile filename, buffer, "utf8", _

-    # Update in memory serialized JSON size of page and b-tree.
+    # Update in memory serialized JSON size of page and b‑tree.
     @size -= page.size or 0
     page.cache = {}
     page.size = JSON.stringify(page.addresses).length
@@ -939,7 +942,7 @@

   # To read a branch page we read the entire page and evaluate it as JSON. We
   # did not store the branch page keys. They are looked up as needed as
-  # described in the b-tree overview above.
+  # described in the b‑tree overview above.

   #
   readBranches: (page, _) ->
@@ -949,7 +952,7 @@
     [ right, addresses ] = record
     count = addresses.length

-    # Set in memory serialized JSON size of page and add to b-tree.
+    # Set in memory serialized JSON size of page and add to b‑tree.
     page.size = JSON.stringify(addresses).length
     @size += page.size

@@ -989,7 +992,7 @@
   # child and no keys. The left child is a single leaf page that is empty.
   #
   # Note that the address of the root branch page is `0` and the address of the
-  # left most leaf page is `-1`. This will not change. Even as the b-tree is
+  # left most leaf page is `-1`. This will not change. Even as the b‑tree is
   # balanced with splits and mergers of leaf pages, the root branch page is
   # always `0` and left most leaf page is always `-1`.

@@ -1067,34 +1070,36 @@

   # ### Concurrency
   #
-  # The b-tree must only be read and written by a single Node.js process. It is
+  # The b‑tree must only be read and written by a single Node.js process. It is
   # not suitable for use with multiple node processes, or the cluster API.
   #
-  # Although there is only a single thread in a Node.js process, the b-tree is
+  # Although there is only a single thread in a Node.js process, the
+  # b‑tree is
   # still a concurrent data structure. Instead of thinking about concurrency in
-  # terms of threads we talk about concurrent *descents* of the b-tree.
+  # terms of threads we talk about concurrent *descents* of the b‑tree.
   #
   # When we search the tree or alter the tree, we must descend the tree.
   #
-  # Decents of the b-tree can become concurrent when descent encounters a page
+  # Decents of the b‑tree can become concurrent when descent encounters a page
   # that is not in memory. While it is waiting on evented I/O to load the page
   # files, the main thread of the process can make progress on another request
-  # to search or alter the b-tree, it can make process on another descent.
+  # to search or alter the b‑tree, it can make process on another descent.
   #
   # This concurrency keeps the CPU and I/O loaded.
   #
   # ### Locking
   #
   # Locking prevents race conditions where an evented I/O request returns to to
-  # find that the sub-tree it was descending has been altered in way that causes
+  # find that the sub‑tree it was descending has been altered in way that causes
   # an error. Pages may have split or merged by the main thread, records may
-  # have been inserted or deleted. While evented I/O is performed, the sub-tree
+  # have been inserted or deleted. While evented I/O is performed, the
+  # sub‑tree
   # needs to be locked to prevent it from being altered.
   #
-  # The b-tree is locked page by page. We are able to lock only the pages of
+  # The b‑tree is locked page by page. We are able to lock only the pages of
   # interest to a particular descent of the tree.
   #
-  # Futhermore, the b-tree destinguishes between shared read locks and exclusive
+  # Futhermore, the b‑tree destinguishes between shared read locks and exclusive
   # write locks. Multiple descents can read a traverse that is read locked, but
   # only the descent that holds an exclusive write lock can traverse it or write
   # to it.
@@ -1252,15 +1257,16 @@

 # ## Descent
 #
-# We use the term *descent* to describe b-tree operations, because all b-tree
-# operations require a descent of the b-tree, a traversal of the b-tree starting
+# We use the term *descent* to describe b‑tree operations, because all
+# b‑tree
+# operations require a descent of the b‑tree, a traversal of the b‑tree starting
 # from the root. Whenever we are search the tree, insert or delete records, or
 # balance the tree with a page splits and merges, we first begin with a descent
-# of the b-tree, from the root, to find the page we want to act upon.
+# of the b‑tree, from the root, to find the page we want to act upon.
 #
 # #### Descent as Unit of Work
 #
-# We use the term descent to describe the both traversal of the b-tree and the
+# We use the term descent to describe the both traversal of the b‑tree and the
 # subsequent actions performed when when the desired page is found.
 #
 # The descent is the unit of work in our concurrency model.  A descent is
@@ -1274,8 +1280,8 @@
 # progress on another descent in the main thread of execution.
 #
 # Because descents can make interleaved progress, we need to synchronize access
-# to b-tree pages, just as we would with a multi-threaded b-tree implementation.
-# When we descend the b-tree we need to make sure that we do not alter pages
+# to b‑tree pages, just as we would with a multi-threaded b‑tree implementation.
+# When we descend the b‑tree we need to make sure that we do not alter pages
 # that another waiting descent needs to complete its descent when it awakes, nor
 # read pages that a waiting descent had begun to alter before it had to wait.
 #
@@ -1284,27 +1290,28 @@
 #
 # #### Classes of Descent
 #
-# When we descend to leaf pages of a search b-tree to obtain records, we
-# *search* the b-tree. When we change the size of the b-tree by adding or
-# deleting records we *edit* the b-tree. When we change the structure of the
-# b-tree by splitting or merging pages, we *balance* the b-tree.
+# When we descend to leaf pages of a search b‑tree to obtain records, we
+# *search* the b‑tree. When we change the size of the b‑tree by adding or
+# deleting records we *edit* the b‑tree. When we change the structure of the
+# b‑tree by splitting or merging pages, we *balance* the b‑tree.
 #
 # We talk about search descents, edit descents, and balance descents we we
-# describe the interaction of b-tree operations.
+# describe the interaction of b‑tree operations.
 #
 # We use these terms in this document to save the chore of writing, and the
 # confustion of reading; insert or delete, or split or merge. We also want to
-# draw a distinction between changing the count of records stored in the b-tree,
-# *editing*, and changing the height of the b-tree, the count of pages, or the
+# draw a distinction between changing the count of records stored in the
+# b‑tree,
+# *editing*, and changing the height of the b‑tree, the count of pages, or the
 # choice of keys, *balancing*.
 #
 # #### Locking on Descent
 #
-# Becase a search descent does not alter the structure of the b-tree, Multiple
+# Becase a search descent does not alter the structure of the b‑tree, Multiple
 # search descents can be performed concurrently, without interfering with each
 # other.
 #
-# Descents that alter the b-tree exclusive access, but only to the pages they
+# Descents that alter the b‑tree exclusive access, but only to the pages they
 # alter. A search descent can still make progres in the presence of an
 # alteration decent, so long as the search does not visit the pages being
 # altered.
@@ -1336,7 +1343,8 @@
 #
 # Both branch pages and leaf pages are singly linked to their right sibling. If
 # you hold a lock on a page, you are allowed to obtain a lock on its right
-# sibling. This left right ordering allows us to traverse a level of the b-tree,
+# sibling. This left right ordering allows us to traverse a level of the
+# b‑tree,
 # which simplifies the implemtation of record cursors and page merges.
 #
 # When we move from a page to its right sibling, we hold the lock on the left
@@ -1420,7 +1428,7 @@
 # ### Iterator
 #
 # The application developer uses an iterator to move across the leaf pages of
-# the b-tree in ascending collation order, one leaf page a time. The leaf pages
+# the b‑tree in ascending collation order, one leaf page a time. The leaf pages
 # themselves are visited one at a time, not the records. The iterator can
 # randomly access any record a the currently visited leaf page.
 #
@@ -1440,7 +1448,7 @@
   # As the result of a descent, we will know the index of the record that
   # corresponds to the key used to find the leaf page. This is either the index
   # of the key's record, or if there no record that could derive the key in the
-  # b-tree, the location where the key's record would be inserted.
+  # b‑tree, the location where the key's record would be inserted.
   #
   # There are good reasons to search for key that does not exist in the tree. We
   # may be interested in searching for time series data that occured between
@@ -1461,7 +1469,7 @@
   # sibling page.
   #
   # However, we do know that the first leaf page is the correct leaf page for
-  # the search key, because we used a b-tree descent to find the page. That is
+  # the search key, because we used a b‑tree descent to find the page. That is
   # unambiguous. When we search for the search key in the leaf page, even if it
   # does not exist, and is greater than the last record, we still know for
   # certain that the key does not belong to any of the right siblings.
@@ -1486,7 +1494,7 @@
   #
   # Additional public properties of the `Iterator` are the `key` used to create
   # the iterator, `found` which indicates whether or not the record actually
-  # exists in the b-tree, `count` which is the number of leaf pages visited by
+  # exists in the b‑tree, `count` which is the number of leaf pages visited by
   # this iterator, and `exclusive` indicating whehter we are an iterator or
   # a mutator. This properties are read-only, so make sure you only read them.

@@ -1534,7 +1542,7 @@
 # A mutator is an iterator that can also edit leaf pages. It can delete records
 # from the currently visit leaf page. It can insert records into the current
 # leaf page, if the record belongs in the current leaf page. Like an `Iterator`
-# it  moves bacross the leaf pages of an the b-tree in ascending collation
+# it  moves bacross the leaf pages of an the b‑tree in ascending collation
 # order. It has random access to the records in the page using an index into the
 # array of records.
 #
@@ -1549,11 +1557,11 @@
 # As in the case of ambiguous range starts, an insert location is unambiguous if
 # the key is the search key used to locate the first page of the mutator. The
 # key is determined to belong inside the leaf page by virtue of a desent of the
-# b-tree. That is unambiguous.
+# b‑tree. That is unambiguous.
 #
 # Using the example of time series data again, the application developer may
 # have an hour of events she wishes to insert into a day of events, within a
-# b-tree of years of events. Because the events took place within an hour, they
+# b‑tree of years of events. Because the events took place within an hour, they
 # would all be inserted into leaf pages that are close to each other, perhaps
 # right next to each other, or maybe they all fall within a single leaf page.
 #
@@ -1572,7 +1580,7 @@
 # equal to the insert key, then we are on the wrong page. Unless we inspect the
 # next page, the insert location is ambiguous.
 #
-# To obtain an unambiguous insert location without descending the b-tree to
+# To obtain an unambiguous insert location without descending the b‑tree to
 # create a new mutator, we add a `Mutator.peek` method.
 #
 # This gives the mutator permission to peek at the right sibling leaf page of
@@ -1677,7 +1685,7 @@

         # Since we need to fsync anyway, we open the file and and close the file
         # when we append a JSON object to it. Because no file handles are kept
-        # open, the b-tree object can left to garbage collection.
+        # open, the b‑tree object can left to garbage collection.
         filename = @_io.filename @_page.address
         fd = fs.open filename, "a", 0644, _
         position = @_io.writeInsert fd, @_page, index, record, _
@@ -1713,7 +1721,7 @@
 #
 # #### Staccato Blanace Operations
 #
-# The b-tree balance operations cascade by nature. If you insert a value into a
+# The b‑tree balance operations cascade by nature. If you insert a value into a
 # leaf node, such that the leaf node is beyond capacity, you split the leaf
 # node, adding a new child to the parent node. If the parent node is now beyond
 # capacity, you split the parent node, adding a new child to its parent node.
@@ -1721,7 +1729,7 @@
 # leaf node will split every node all they way up to the root.
 #
 # Merges too move from leaves to root, so that a merge at one level of the
-# b-tree potentially triggers a merge of the parent with one of its siblings.
+# b‑tree potentially triggers a merge of the parent with one of its siblings.
 #
 # However, we've established rules for lock acquisition that require that locks
 # are obtained from the top down, and never from the bottom up. This is why we
@@ -1729,15 +1737,15 @@
 # descend the tree once to insert or delete records form the leaf pages. We then
 # descend the tree once for each split or merge of a page.
 #
-# Much b-tree literature makes mention of a potential efficency where you split
+# Much b‑tree literature makes mention of a potential efficency where you split
 # full pages on the way back up from an insert. You can determine which pages
-# would split if the leaf split as you descend the b-tree, since you'll visit
+# would split if the leaf split as you descend the b‑tree, since you'll visit
 # every page that would participate in a split.
 #
 # That efficency applies only for split, and not for merge, because you have to
 # inspect the left and right siblings of a page to determine if it is time to
 # merge. If the left sibling page of a page, is not also child of that page's
-# parent page, then the left sibling page is in a different sub-tree. It can not
+# parent page, then the left sibling page is in a different sub‑tree. It can not
 # be reached by the path that was used to find the leaf page where the delete
 # occured.
 #
@@ -1769,9 +1777,9 @@
 # mangniutde less frequently.
 #
 # Conserving descents during balance operations is a false economy. It
-# complicates lock acquisition. It reduces the liveliness of the b-tree.
-#
-# The multiple descents will allow searches of the b-tree to make progress
+# complicates lock acquisition. It reduces the liveliness of the b‑tree.
+#
+# The multiple descents will allow searches of the b‑tree to make progress
 # between balance operations.
 #
 # ##### Descent as Unit of Work
@@ -1786,13 +1794,13 @@
 # level the moment we've detected the need for one. If we fill a leaf page, we
 # descend the tree again to split the leaf page.
 #
-# Because the b-tree is a concurrent structure, the leaf split descent may
+# Because the b‑tree is a concurrent structure, the leaf split descent may
 # discover that another descent has removed a record, and a leaf split is no
 # longer necessary. There may be, in fact, a descent on the way to the left
 # sibling of the page, to check for the potential for a merge.
 #
 # The concurrent operation means that we have to deal with situation where we've
-# undertaken a descent to balance the b-tree, but another series of descents
+# undertaken a descent to balance the b‑tree, but another series of descents
 # has rendered that plan invalid.
 #
 # As long as we're dealing with that problem, we may as well decouple insertion
@@ -1821,7 +1829,7 @@
 # in a separate thread of execution.
 #
 # Of course, a Node.js application really only has one thread of execution. In
-# our b-tree, however, multiple descents can make progress at the time, or
+# our b‑tree, however, multiple descents can make progress at the time, or
 # rather, the progress made by one decent, while another descent waits on I/O.
 #
 # We ensure that only one descent at a time is making progress toward the
@@ -1836,7 +1844,7 @@
 # balance the tree, the *balancer*.
 #
 # The balancer maintains an offset count for each modified leaf page in the
-# b-tree. When an insert is performed, the offset count for the leaf page is
+# b‑tree. When an insert is performed, the offset count for the leaf page is
 # incremented.  When a delete is performed, the offset count for the leaf page
 # is decremented. This keeps track of the total change in size.
 #
@@ -1900,7 +1908,7 @@
 # To split a leaf page, we start by obtaining the key value of the first record.
 # We can do this by acquiring a read lock on the page, without performing a
 # descent. The balancer gets to break some rules since it knows that we know
-# that the b-tree is not being otherwise balanced.
+# that the b‑tree is not being otherwise balanced.
 #
 # We descend the tree until we encoutner the penultimate branch page that is the
 # parent of the branch page.  We acquire an excsluive lock the branch page. We
@@ -1938,7 +1946,7 @@
 # keys in our tree. Even if we kept keys around, we're sending searches down a
 # path to nowhere. There is no leaf page to visit. We get rid of these paths. We
 # always balance the upper levels immediately, we perform the cascade. Our tree
-# descent logic would have to account for these empty sub-trees. Much better to
+# descent logic would have to account for these empty sub‑trees. Much better to
 # balance and keep things orderly.
 #
 # This raises a concerns about live lock, that we might be balancing
@@ -1978,9 +1986,9 @@
 # To merge a leaf page, we start by obtaining the key value of the first record.
 # We can do this by acquiring a read lock on the page, without performing a
 # descent. The balancer gets to break some rules since it knows that we know
-# that the b-tree is not being otherwise balanced.
-#
-# With that key, we descend the b-tree. We know that the key value cannot
+# that the b‑tree is not being otherwise balanced.
+#
+# With that key, we descend the b‑tree. We know that the key value cannot
 # change, because it is the balancer that alters keys. The first record may be
 # deleted by editing, but a ghost of the first record is preserved for the key
 # value, which is the key value of the page.
@@ -2002,7 +2010,7 @@
 # left sibling because the first record is now somewhere in the midst of the
 # left sibling. We lock excluslively hand-over-hand thereafter to squeeze out
 # any shared locks. Our exclusive lock on the parent containing the key prevents
-# another descent from entering the sub-tree where we are performing the merge.
+# another descent from entering the sub‑tree where we are performing the merge.
 #
 # We now proceed down the path to the merge page as we would ordinarily, except
 # that we acquire exclusive locks hand-over-hand instead of shared locks. This
@@ -2010,7 +2018,7 @@
 #
 # We retain the exclusive lock on the penultimate branch page. No other descent
 # will be able to visit this penultimate branch, because we've blocked entry
-# into the sub-tree and squeeed out the other descents. We still need to hold
+# into the sub‑tree and squeeed out the other descents. We still need to hold
 # onto the exclusive lock, however, otherwise the page might be discarded during
 # a cache purge, which can happen concurently.
 #
@@ -2036,7 +2044,7 @@
 # merging branch pages other than the root branch page is the same regardless of
 # the depth of the branch page.
 #
-# We acquire the key for the left most page in the sub-tree underneath the
+# We acquire the key for the left most page in the sub‑tree underneath the
 # branch page. We do this by following the left most children until we reach a
 # leaf page. We use that key to descend the tree.
 #
@@ -2059,7 +2067,7 @@
 # the left sibling. Remove the merge sibling from its parent. Delete the key
 # from where we found it, so it can be looked up again.
 #
-# Before we lose track of the sub-tree we're in, we descend to the poteinally
+# Before we lose track of the sub‑tree we're in, we descend to the poteinally
 # new left most leaf of the parent, and obtain its key to repeat the process.
 #
 # #### Filling the Root Page
@@ -2071,7 +2079,7 @@
 # We descend again, locking the root. We lock the one child of the root. We copy
 # the contents of the one root child into the root and delete the child.
 #
-# This will decrease the height of the b-tree by one.
+# This will decrease the height of the b‑tree by one.
 #
 # #### Deleting Pages
 #
@@ -2119,7 +2127,7 @@
 # are a great many operations, then balance, wait a while, then balance, wait a
 # while. It is up the the end user.
 #
-# The end user can use the b-tree a map, tucking in values, getting them out.
+# The end user can use the b‑tree a map, tucking in values, getting them out.
 # Or else, as an index, to scan, perform table scans. We'll figure that out.
 #
 # Now I have an API problem. The client will have to know about pages to work
@@ -2131,12 +2139,12 @@
 #
 # There is a desire to cache the addresses of the left sibling pages when
 # possible, so I wouldn't have to descend the tree. Except that the
-# most-recently used list works hand in hand with b-tree descent. The higher
+# most-recently used list works hand in hand with b‑tree descent. The higher
 # levels of the tree are kept in memory, because they are more frequently visted
 # than lower levels. To much iteration along one level threatens to purge other
 # levels.
 #
-# One can imagine that when balancing b-tree that has been left unbalanced for a
+# One can imagine that when balancing b‑tree that has been left unbalanced for a
 # long time, reading in many unbalanced leaf pages will cause the first ones to
 # flush, which is a pity, since we'll probably need one of them.
 #
@@ -2190,7 +2198,7 @@
   # necessary, it turns out that in the mean time, that page has shrunk so that
   # it is now too small. We could create an outer loop that keeps on referencing
   # cache entries until all are available, but then you have an outer strange
-  # condition where you might load the entire b-tree, because you're taking so
+  # condition where you might load the entire b‑tree, because you're taking so
   # long, and every page is being touched. Allow balance to be imperfect.
   balance: (@io, _) ->
     # We only ever run one balance at a time. If there is a balance in progress,
@@ -2234,7 +2242,7 @@
       # containing the next sibling. If a sibling is not participating in our
       # balance plan, then its link is null. This gives us one or more linked
       # lists that reference a series of leaf pages ordered according to their
-      # order in the b-tree.
+      # order in the b‑tree.
       #
       # We are always allowed to get a lock on a single page, so long as we're
       # holding no other locks.
@@ -2361,7 +2369,7 @@
         else
           delete ordered[address]

-    # Perform the operations to balance the b-tree.
+    # Perform the operations to balance the b‑tree.
     for operation in @operations
       @[operation.method](operation, _)

@@ -2472,7 +2480,7 @@
     cursor.insert(record)
     cursor.unlock()

-  # Create a cassette to insert into b-tree.
+  # Create a cassette to insert into b‑tree.
   cassette: (object) -> new Cassette(object, @_io.extractor(object))

   # Create an array of cassettes, sorted by the record key, from the array of


JUser: fixed param shadowing on unregister method

--- workers/social/lib/social/models/user/index.coffee
+++ workers/social/lib/social/models/user/index.coffee
@@ -166,7 +166,7 @@
           foreignAuth     : {}
         }
         modifier = { $set: userValues, $unset: { oldUsername: 1 }}
-        user.update modifier, (err, callback) =>
+        user.update modifier, (err, docs) =>
           return callback err  if err?
           accountValues = {
             'profile.nickname'    : username