Keep target attribute in show notes/description

- do not set all target attributes to "_parent" by default
- keep target "_blank" intact if this has been set by intention

--- src/javascripts/configuration.coffee
+++ src/javascripts/configuration.coffee
@@ -137,12 +137,15 @@
       prefix: 'pp'
     )

-    # make links text open in parent window
+    # open links in parent window when not specified to open in new window / tab
     rivets.formatters.description = (text) =>
       elem = document.createElement('div')
       elem.innerHTML = text.trim()
       links = elem.querySelectorAll('a')
-      Array.prototype.forEach.call(links, (link) => link.target = '_parent')
+      Array.prototype.forEach.call(links, (link) => (
+        if !link.target || (link.target && link.target != '_blank')
+          link.target = '_parent'
+      ))
       elem.innerHTML

     rivets.formatters.scale = (url, size) =>


removing debug stuff

removing debug stuff

--- lib/lt3.coffee
+++ lib/lt3.coffee
@@ -376,7 +376,6 @@
               throw err if err
               log "page added to #{site_slug}"
               exit "to view: lt3 open #{site_slug} #{app_slug} #{page_slug} --dev"
-      (DASSAD)(ADSASD)(DSASAD(SDASAD(DSASAD)))

   # create a new site
   when 'v1:create'


positioning of infowindow over large pin

--- app/assets/javascripts/map.js.coffee
+++ app/assets/javascripts/map.js.coffee
@@ -19,7 +19,7 @@

   infobox: (boxText)->
     content: boxText
-    pixelOffset: new google.maps.Size(-140, 0)
+    pixelOffset: new google.maps.Size(-140, -100)
     boxStyle:
       width: "280px"
       'background-color': 'white'


Fixed drawing tool query

Fixed drawing tool query

--- app/assets/javascripts/map.js.coffee
+++ app/assets/javascripts/map.js.coffee
@@ -63,9 +63,8 @@
     southWest = rectangle.getBounds().getSouthWest()
     northEast = rectangle.getBounds().getNorthEast()
     processCrashes({
-      path: '/crashes/clusters',
-      year: '2011',
-      zoomLevel: zoomLevel,
+      path: '/crashes',
+      year: '2011',
       southWest: southWest,
       northEast: northEast,
       callback: (response) =>


Document Unburden hardcoding.

Document Unburden hardcoding.

--- data/bw/abilities.coffee
+++ data/bw/abilities.coffee
@@ -617,6 +617,7 @@
       battle.message "#{@pokemon.name} is loafing around!"
       return false

+# Hardcoded in Pokemon#removeItem
 makeAbility 'Unburden'

 makeAbility 'Victory Star', ->


Remove unused argument

Remove unused argument

--- app/assets/volume/spreadsheet.coffee
+++ app/assets/volume/spreadsheet.coffee
@@ -926,7 +926,7 @@
           if info.r
             if input == info.record.measures[info.metric.id]
               add("Keep " + info.record.displayName,
-                (cell) -> return,
+                () -> return,
                 true)
             if !input
               add("Remove " + info.record.displayName + " from this session",


Partially revert 6fb9ae0aa02e1550248598843c31a3bd834bc9b9

Still need the replaceChild, oh well

--- app/assets/volume/spreadsheet.coffee
+++ app/assets/volume/spreadsheet.coffee
@@ -378,7 +378,7 @@
           slot = slots[i]
           stop = slot.id == volume.top.id
           row = document.createElement('tr')
-          $(rows[i]).remove() if rows[i]
+          rows[i]?.parentNode?.replaceChild(row, rows[i])
           rows[i] = row
           row.id = id + '_' + i
           row.data = i


Allow array of teamIds in bulkLoad

Allow array of teamIds in bulkLoad

--- src/collections/teams.coffee
+++ src/collections/teams.coffee
@@ -45,17 +45,15 @@

 # Loads all items associated with a team, optionally limited by the types array
 exports.bulkLoad = (teamId, types, callback) ->
-  if typeof teamId is 'object'
+  if typeof teamId is 'object' and !Array.isArray(teamId)
+    # Using params object (smartload)
     loadParams = teamId
-    # Using params object (smartload)
-    unless @isId loadParams.teamId
-      throw new TSArgsError 'teamsnap.bulkLoad', 'teamId must be provided'
     teamId = loadParams.teamId
     types = loadParams.types
-  else
-    # Using classic bulk_load
-    unless @isId teamId
-      throw new TSArgsError 'teamsnap.bulkLoad', 'teamId must be provided'
+
+  unless @isId(teamId) or
+  (Array.isArray(teamId) and @isId(teamId[0]))
+    throw new TSArgsError 'teamsnap.bulkLoad', 'teamId must be provided'

     if typeof types is 'function'
       callback = types


Add character to SpriteCommandSchema say (#302)

--- app/schemas/models/level.ozar.coffee
+++ app/schemas/models/level.ozar.coffee
@@ -92,6 +92,12 @@
       ogg: c.shortString(title: 'OGG', format: 'sound-file')
       preload: {title: 'Preload', description: 'Whether to load this sound file before the level can begin (typically for the first dialogue of a level).', type: 'boolean' }
     responses: c.array {title: 'Buttons', description: 'An array of buttons to include with the dialogue, with which the user can respond.'}, ResponseSchema
+    character: c.shortString(
+      title: 'Character'
+      description: 'The character portrait to use for the say message. Not setting this, or choosing the default, will use the Vega character.'
+      enum: ['vega', 'blank', 'capella']
+      default: 'vega'
+    )
     i18n: {type: 'object', format: 'i18n', props: ['blurb', 'text', 'sound'], description: 'Help translate this message'}
   move: c.object {title: 'Move', description: 'Tell the Thang to move.', required: ['target'], default: {target: {}, duration: 500}},
     target: _.extend _.cloneDeep(PointSchema), {title: 'Target', description: 'Target point to which the Thang will move.', default: {x: 20, y: 20}}


Refactor: $timeout and problems with word count

--- app/scripts/controllers/words.coffee
+++ app/scripts/controllers/words.coffee
@@ -19,7 +19,7 @@
         $scope.wordFrequency = "?"
       else
         $scope.wordFrequency = "..."
-        $timeout($scope.getWordFrequency(), 2000)
+        $timeout($scope.getWordFrequency, 2000)
     $scope.$watch "state", ->
       $scope.getRepList()

@@ -55,6 +55,7 @@
           q: "select * from json where url=\'#{url}\'"
           format: "json"
       ).success((data, status) ->
+        $scope.wordFrequency = 0
         $scope.wordFrequency = $scope.countFrequency(data.query.results.json.results)
       ).error (data, status) ->
         console.log "Error #{status}: #{data}"


amqp: Fix some noisy console.log

amqp: Fix some noisy console.log

--- src/amqp.coffee
+++ src/amqp.coffee
@@ -40,7 +40,6 @@
     if type == 'inqueue'
       @channel.assertQueue queueName, options, callback
     else
-      console.log 'create exchange', queueName, type
       @channel.assertExchange queueName, 'fanout', options, (err) =>
         return callback err if err
         # HACK: to make inqueue==outqueue work:
@@ -104,6 +103,7 @@
     super address, options

   bindQueue: (from, to, callback) ->
+    debug 'bind', from, to
     @channel.bindQueue to, from, '', {}, callback
   unbindQueue: (from, to, callback) ->
     return callback null


collision with regular bounds

collision with regular bounds

--- test/collision.coffee
+++ test/collision.coffee
@@ -62,7 +62,7 @@
   equals p1.y, 0
   equals p1.x, 20

-  p2 = Collision.rayRectangle start, rect.bounds()
+  p2 = Collision.rayRectangle start, rect.centered()

   equals p1.y, 0
   equals p1.x, 20


:lipstick: whitespace

:lipstick: whitespace

--- src/atom.coffee
+++ src/atom.coffee
@@ -17,8 +17,6 @@

 {$} = require './space-pen-extensions'
 WindowEventHandler = require './window-event-handler'
-
-

 # Public: Atom global for dealing with packages, themes, menus, and the window.
 #


Caching results

Caching results

--- src/memegen.coffee
+++ src/memegen.coffee
@@ -5,7 +5,8 @@
 #   None
 #
 # Commands:
-#   hubot hello - <what the respond trigger does>
+#   hubot list - Returns available meme templates from Memegen.link and their respective URLs (keys)
+#   hubot <template> --top <text> --bottom <text> - Creates a <template> meme using <text> and returns links to it
 #
 # Notes:
 #   None
@@ -16,10 +17,18 @@
 MEMEGEN_API_URL = "http://memegen.link"

 module.exports = (robot) ->
+    _templateCache = null
+
     robot.respond /meme list/i, (res) ->
+        return res.send(_templateCache) if _templateCache?
         GetMGResult res, "/templates/", null, (obj) ->
+            _templateCache = ""
             for template, url of obj
-                res.send "#{template} (#{url})"
+                key = url.split "/"
+                key = key[key.length - 1]
+                _templateCache += "#{template} | Key: #{key} | Example: http://memegen.link/#{key}/hello/world.jpg\n"
+            # TODO: Paste results?
+            res.send _templateCache

     robot.respond /meme (.+) --top (.+) --bottom (.+)/i, (res) ->
         template = res.match[1]
@@ -27,8 +36,9 @@
         bottomText = _spaceToHyphen(res.match[3])

         GetMGResult res, "/#{template}/#{topText}/#{bottomText}", null, (obj) ->
-            res.send "Visible: #{obj.direct.visible}"
-            res.send "Masked: #{obj.direct.masked}"
+            links = "Visible: #{obj.direct.visible}\n"
+            links += "Masked: #{obj.direct.masked}"
+            res.send links

 _spaceToHyphen = (str) ->
     str.replace(/\s+/g, '-').toLowerCase()
@@ -37,9 +47,9 @@
     res.http("#{MEMEGEN_API_URL}#{api}")
         .query(params)
         .get() (err, httpRes, body) ->
-            # Improve error handling
+            # TODO: Improve error handling
             if err or (httpRes.statusCode isnt 200 and httpRes.statusCode isnt 302)
                 res.reply "I'm unable to process your request at this time due to a server error. Please try again later."
                 return res.robot.logger.error "hubot-memegen: #{body} (#{err})"

-            handler JSON.parse(body)
+            handler JSON.parse(body)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -55,6 +55,7 @@
         I[name] = 100

       if not I["max#{name.capitalize()}"]
+        if I[]
         I["max#{name.capitalize()}"] = 100

       ratio = I[name] / I["max#{name.capitalize()}"]


add /send_photo_to_vk handler that posts photo file to vk

--- src/controllers/index.coffee
+++ src/controllers/index.coffee
@@ -13,6 +13,7 @@
   res.render 'index'

 exports.send_photo_to_vk = (req, res) ->
+  console.log "Request body is: " + JSON.stringify req.body
   request.post {url: req.body.url, json: {photo: req.body.photo}}, (err, resp, body) ->
     console.log "Err:" + JSON.stringify err
     console.log "Resp:" + JSON.stringify resp


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -6,7 +6,8 @@
 player = GameObject
   health: 100
   maxHealth: 100
-player.include
+
+player.include

 enemy = GameObject
   health: 500


More reflection.

More reflection.

--- src/methods.coffee
+++ src/methods.coffee
@@ -293,13 +293,14 @@
             for i in [src_pos...src_pos+length]
               dest.array[j++] = src.array[i]
         o 'currentTimeMillis()J', (rs) -> gLong.fromNumber((new Date).getTime())
+        o 'identityHashCode(L!/!/Object;)I', (x) -> x.ref
         o 'initProperties(L!/util/Properties;)L!/util/Properties;', (rs, props) ->
             m = rs.method_lookup({'class':'java/util/Properties','sig':{'name':'setProperty'}})
             # properties to set:
             #  java.version,java.vendor,java.vendor.url,java.home,java.class.version,java.class.path,
             #  os.name,os.arch,os.version,file.separator,path.separator,
             #  user.name,user.home,user.dir
-            properties = {'file.encoding':'US_ASCII','java.vendor':'DoppioVM','line.separator':'\n'}
+            properties = {'java.home':'/', 'file.encoding':'US_ASCII','java.vendor':'DoppioVM','line.separator':'\n'}
             for k,v of properties
               rs.push props.ref, rs.init_string(k,true), rs.init_string(v,true)
               m.run(rs)


Allow exclusion of itself,inv,equips from weight calc

--- src/calc.coffee
+++ src/calc.coffee
@@ -43,21 +43,35 @@
 		subject.calc 'strength'

 	## Intermediate calculations
-	weight: (subject) ->
+	weight: (subject, include = {}) ->
+		_.defaults include,
+			{ itself: yes, inventory: yes, equips: yes }
+
+		{itself, inventory, equips} = include
+
 		weightOf = (i) -> i.weight ? 0

-		invWeight = subject.inventory
-			.map (item) -> weightOf item
-			.reduce ((p, c) -> p+c), 0
+		invWeight =
+			if inventory
+				subject.inventory
+				.map (item) -> weightOf item
+				.reduce ((p, c) -> p+c), 0
+
+			else 0

 		eqpWeight =
-			(weightOf item for slot,item of subject.equipment)
-			.reduce ((p, c) -> p+c), 0
+			if equips
+				(weightOf item for slot,item of subject.equipment)
+				.reduce ((p, c) -> p+c), 0

-		(weightOf subject) + invWeight + eqpWeight
+			else 0
+
+		subjWeight = if itself then weightOf subject else 0
+
+		subjWeight + eqpWeight + invWeight

 	excessWeight: (subject) ->
-		Math.max 0, (subject.calc 'weight') - (subject.calc 'maxWeight')
+		Math.max 0, (subject.calc 'weight', itself: no) - (subject.calc 'maxWeight')

 module.exports = {
 	meleeDamage


HIRE-16-frontend : added missing return statement

--- src/main/java/app/profile/profile.coffee
+++ src/main/java/app/profile/profile.coffee
@@ -44,14 +44,18 @@
       $scope.success = true
       $timeout (->
         $scope.success = false
+
       ), 10000
+
     ), ->
       $scope.error = true
       $document.duScrollTopAnimated(0)
       $('.form-group').removeClass('has-warning')
       $timeout (->
         $scope.error = false
+
       ), 10000
+

   $scope.cancel = ->
     $scope.editMode = false


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_game_state.coffee
+++ src/engine_game_state.coffee
@@ -50,6 +50,7 @@
         return self
       else
         I.currentState.cameras()
+
     flash: (options={}) ->
       self.camera(options.camera).flash(options)
     objects: ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_game_state.coffee
+++ src/engine_game_state.coffee
@@ -36,7 +36,7 @@
   # Just pass through to the current state
   add: (classNameOrEntityData, entityData) ->
     # Allow optional add "Class", data form
-    if classNameOrEn?
+    if classNameOrEntityData.isString?
       entityData.class = className
     else
       entityData = className


Unequip works properly again

Unequip works properly again

--- src/entities/creature.coffee
+++ src/entities/creature.coffee
@@ -92,7 +92,7 @@
 		else
 			break for slot, i of @equipment when i is item

-		if not slot? or item? or @equipment[slot] isnt item then no
+		if not (slot? or item?) or @equipment[slot] isnt item then no
 		else
 			delete @equipment[slot]
 			@inventory.push item


implemented language distance and crossover

--- lingsim.coffee
+++ lingsim.coffee
@@ -53,7 +53,7 @@

 Utils = new Utilities()

-class Genome
+class Language
   GENOME_SIZE: 6
   GENOME_SPACE: 4

@@ -68,13 +68,17 @@
     index = Utils.randomIndex @genome
     @genome[index] = @randomGene()

+  distance: (otherLanguage) =>
+    Utils.editDistance @genome, @otherLanguage.genome

-class Language
-  constructor: ->
-    @genome = new Genome()
+  # two point crossover
+  crossover: (otherLanguage) =>
+    otherGenome = otherLanguage.genome
+    [pointA, pointB] = [@randomIndex(), @randomIndex()].sort()

-  distance: (otherLanguage) =>
-    @genome.distance otherLanguage.genome
+    fragment = @genome[pointA..pointB]
+    @genome[pointA..pointB] = otherGenome[pointA..pointB]
+    otherGenome[pointA..pointB] = fragment

 class Agent


Mesh: Return highest LoD when there is no bound box.

(cherry picked from commit 57a66c7fec059b372c116fcbb31b5670d6d7da9a)

--- engine/mesh.coffee
+++ engine/mesh.coffee
@@ -330,7 +330,11 @@
             # TODO: Optimize
             inv = mat4.invert(mat4.create(), @world_matrix)
             if not inv? or not @bound_box
-                return @last_lod_object = @lod_objects[0]?.object or @
+                # Return highest loaded LoD
+                return @ if @data?
+                for {object} in @lod_objects when object.data?
+                    return object
+                return @
             p = vec3.transformMat4 vec3.create(), cam_pos, inv
             p = vec3.max p, p, @bound_box[0]
             p = vec3.min p, p, @bound_box[1]


#104 Repairing references Error handling file

--- error/Error.coffee
+++ error/Error.coffee
@@ -17,31 +17,31 @@
     isCustom: true

   badRequest: (attributeName, expected, actualValue) ->
-    error(Type.BAD_REQUEST, "#{attributeName} was expected to be of type #{expected}, but received #{actualValue}")
+    @error(@Type.BAD_REQUEST, "#{attributeName} was expected to be of type #{expected}, but received #{actualValue}")

   unauthorized: (methodName, details) ->
-    error(Type.UNAUTHORIZED, "#{methodName} is not allowed, you should be logged in : #{details}")
+    @error(@Type.UNAUTHORIZED, "#{methodName} is not allowed, you should be logged in : #{details}")

   forbidden: (methodName, details) ->
-    error(Type.FORBIDDEN, "#{methodName} is forbidden (requires higher authorization level) : #{details}")
+    @error(@Type.FORBIDDEN, "#{methodName} is forbidden (requires higher authorization level) : #{details}")
+
+  entityNotFound: (nodeType, id) ->
+    @notFound(nodeType, 'id', id)

   notFound: (nodeType, key, value) ->
-    error(Type.NOT_FOUND, "No #{nodeType} found for #{key} : #{value}")
+    @error(@Type.NOT_FOUND, "No #{nodeType} found for #{key} : #{value}")

   notImplemented: (methodName) ->
-    error(Type.NOT_IMPLEMENTED, "You should implement method #{methodName}")
-
-  entityNotFound: (nodeType, id) ->
-    error(Type.NOT_FOUND, "No #{nodeType} found for id : #{id}")
+    @error(@Type.NOT_IMPLEMENTED, "You should implement method #{methodName}")

   illegalArgument: (argumentValue, methodName) ->
-    error(Type.ILLEGAL_ARGUMENT, "#{argumentValue} is not a valid value for method #{methodName}")
+    @error(@Type.ILLEGAL_ARGUMENT, "#{argumentValue} is not a valid value for method #{methodName}")

   unsupportedOperation: (methodName) ->
-    error(Type.UNSUPPORTED_OPERATION, methodName)
+    @error(@Type.UNSUPPORTED_OPERATION, methodName)

   unsupportedOperation: (methodName, reason) ->
-    error(Type.UNSUPPORTED_OPERATION, "#{methodName} is not supported : #{reason}")
+    @error(@Type.UNSUPPORTED_OPERATION, "#{methodName} is not supported : #{reason}")

   wrongType: (expected, actual) ->
-    error(Type.WRONG_TYPE, "Expected type #{expected}, got #{actual}")+    @error(@Type.WRONG_TYPE, "Expected type #{expected}, got #{actual}")


Keep a separate corrected start point

Keep a separate corrected start point

--- framer/LayerDraggable.coffee
+++ framer/LayerDraggable.coffee
@@ -72,10 +72,10 @@

 	@define "offset",
 		get: ->
-			return {x:0, y:0} if not @_layerStartPoint
+			return {x:0, y:0} if not @_correctedLayerStartPoint
 			return offset =
-				x: @layer.x - @_layerStartPoint.x
-				y: @layer.y - @_layerStartPoint.y
+				x: @layer.x - @_correctedLayerStartPoint.x
+				y: @layer.y - @_correctedLayerStartPoint.y

 	# TODO: what to do with this?
 	# Should there be a tap event?
@@ -138,14 +138,14 @@
 			t: Date.now()

 		# Store original layer position
-		@_layerStartPoint =
-			x: @layer.x
-			y: @layer.y
+		@_layerStartPoint = @layer.point
+		@_correctedLayerStartPoint = @layer.point

 		# If we are beyond bounds, we need to correct for the scaled clamping from the last drag,
 		# hence the 1 / overdragScale
 		if @constraints and @bounce
-			@_layerStartPoint = @_constrainPosition(@_layerStartPoint, @constraints, 1 / @overdragScale)
+			@_correctedLayerStartPoint = @_constrainPosition(
+				@_correctedLayerStartPoint, @constraints, 1 / @overdragScale)

 		# Store start cursor position
 		@_cursorStartPoint =
@@ -154,8 +154,8 @@

 		# Store cursor/layer offset
 		@_layerCursorOffset =
-			x: touchEvent.clientX - @_layerStartPoint.x
-			y: touchEvent.clientY - @_layerStartPoint.y
+			x: touchEvent.clientX - @_correctedLayerStartPoint.x
+			y: touchEvent.clientY - @_correctedLayerStartPoint.y

 		# Store the current layer scale so we can correct movement for it
 		@_screenScale =
@@ -182,8 +182,8 @@
 			t: Date.now() # We don't use timeStamp because it's different on Chrome/Safari

 		offset =
-			x: touchEvent.clientX - @_layerStartPoint.x - @_layerCursorOffset.x
-			y: touchEvent.clientY - @_layerStartPoint.y - @_layerCursorOffset.y
+			x: touchEvent.clientX - @_correctedLayerStartPoint.x - @_layerCursorOffset.x
+			y: touchEvent.clientY - @_correctedLayerStartPoint.y - @_layerCursorOffset.y

 		# Scale the offset with the screen scale for the current layer
 		offset.x = offset.x * @speedX * (1 / @_screenScale.x) * @layer.scaleX * @layer.scale
@@ -191,8 +191,8 @@

 		# See if horizontal/vertical was set and set the offset
 		point = @layer.point
-		point.x = @_layerStartPoint.x + offset.x if @horizontal
-		point.y = @_layerStartPoint.y + offset.y if @vertical
+		point.x = @_correctedLayerStartPoint.x + offset.x if @horizontal
+		point.y = @_correctedLayerStartPoint.y + offset.y if @vertical

 		# Constraints and overdrag
 		point = @_constrainPosition(point, @_constraints, @overdragScale) if @_constraints


added html template

added html template

--- src/reports.coffee
+++ src/reports.coffee
@@ -34,18 +34,21 @@
   logger.info 'fetching channel report for #' + channel.id + ' ' + user.email
   metrics.fetchChannelMetrics 'day',channel.id,user,{}
     .then (data) ->
-        contact.contactUser 'email', user.email, 'Report for ' + channel.name , plainTemplate(channel,data), plainTemplate(channel,data) , afterEmail
+        contact.contactUser 'email', user.email, 'Report for ' + channel.name , plainTemplate(channel,data), htmlTemplate(channel,data) , afterEmail

 fetchUsers = (callback) ->
   User.find {}, callback

 plainTemplate = (channel,data) ->"
+  Channel Name : #{ channel.name } \r\n
+  Channel Load : #{ data[0].load } transactions \r\n
+  Transaction Average Response : #{ data[0].avgResp } \r\n
+"
+htmlTemplate = (channel,data) ->"
   Channel Name : #{ channel.name } \r\n

   Channel Load : #{ data[0].load } transactions \r\n

   Transaction Average Response : #{ data[0].avgResp } \r\n

 "
-
-
 afterEmail = (callback) ->
   logger.info callback


Remove relativeTime helper and change format of display time

--- assets/javascripts/helpers.js.coffee
+++ assets/javascripts/helpers.js.coffee
@@ -1,18 +1,7 @@
-Em.Handlebars.helper 'relativeTime', (value, options)->
-  time = moment(value)
-  difference = moment().unix() - time.unix()
-  if difference > 31536000
-    time.format("MMM D, YYYY")
-  else if difference > 86400
-    time.format("MMM D")
-  else
-    time.fromNow(true)
-
-
 Em.Handlebars.helper 'readableTime', (value, options)->
   time = moment(value)
   difference = moment().unix() - time.unix()
   if difference > 31536000
-    time.format("MMM D, YYYY, h:mm a")
+    time.format("h:mma, D MMM YYYY")
   else
-    time.format("MMM D, h:mm a")
+    time.format("h:mma, D MMM")


fix titles

fix titles

--- HTML/osx.coffee
+++ HTML/osx.coffee
@@ -62,7 +62,7 @@
         sender: 'editor'

   title: (text) ->
-#     App.title = text
+    Chrome.activeWindow().setTitle text

   toggleFullscreen: ->
     if Chrome.fullscreen?


Support TEXTJOIN

Support TEXTJOIN

--- src/formula_evaluator.coffee
+++ src/formula_evaluator.coffee
@@ -949,6 +949,17 @@
       x = ""
     String(x)

+  TEXTJOIN: (args)->
+    @checkArgumentSize(args, 3, Number.MAX_VALUE)
+    delim = @expectString(args[0])
+    ignore_empty = @expectBoolean(args[1])
+    strings = @expandRange(TYPE_STRING, args.slice(2))
+    if ignore_empty
+      strings = strings.filter (str)->
+        str.length > 0
+    strings.join(delim)
+
+

   SUM: (args)->
     @checkArgumentSize(args, 1, Number.MAX_VALUE)


[IMPAC-805]: Include the option to active the timesheet modifier for forecast payroll

--- src/components/widgets-settings/forecast-payroll/forecast-payroll.directive.coffee
+++ src/components/widgets-settings/forecast-payroll/forecast-payroll.directive.coffee
@@ -31,7 +31,7 @@
       (config) ->
         currentDashboard = config.currentDashboard
         $scope.selectedForecastPayroll = {enable: false, time_sheet: false}
-        if w.metadata? && w.metadata.forecast_payroll? && w.metadata.forecast_payroll
+        if w.metadata? && w.metadata.forecast_payroll? && typeof(w.metadata.forecast_payroll) == 'object'
           $scope.selectedForecastPayroll = w.metadata.forecast_payroll

         setting.isInitialized = true


made render cause have a default value

made render cause have a default value

--- modules/meter/main/index.coffee
+++ modules/meter/main/index.coffee
@@ -72,8 +72,7 @@
     else
       @_.data

-  render: (cause) ->
-    cause ?= 'api'
+  render: (cause = 'api') ->
     _ = @_
     options = @options
     data = _.data


small change

small change

--- dev/coffee/script.coffee
+++ dev/coffee/script.coffee
@@ -295,3 +295,4 @@
   Rusnet.research_engine()
   Rusnet.set_img()
   Rusnet.bind()
+  return


Removed dependence on lodash to all underscore

--- src/guts.coffee
+++ src/guts.coffee
@@ -300,11 +300,11 @@

   remove: (model) =>
     # REVIEW(will): check that where is not a lodash-only-ism
-    _viewToRemove = _.where @_child_views, (view) -> view.model is model
+    _viewToRemove = _.findWhere @_child_views, {model: model}
     if not _viewToRemove or not _viewToRemove[0]
       throw "BaseCollectionView : error : couldn\'t find view to remove from collection corresponding to model #{model.cid}"
     viewToRemove = _viewToRemove[0]
-    @_child_views = _.where @_child_views, (view) -> view isnt viewToRemove
+    @_child_views = _.find @_child_views, (view) -> view isnt viewToRemove
     @$(viewToRemove.el).remove()

   at: (index) =>


Increase the height of the job list.

Increase the height of the job list.

--- app/assets/javascripts/jobs_list/views/jobs_list_view.js.coffee
+++ app/assets/javascripts/jobs_list/views/jobs_list_view.js.coffee
@@ -18,11 +18,12 @@
     $(window).bind 'resize', => this.setHeight()

   setHeight: ->
-    height = $(window).height() - 350;
+    height = $(window).height() - 310;
     $(@list).css(maxHeight: height)

   clearAll: ->
     if confirm("Are you sure you want to remove all the saved jobs in your jobs list?")
+      # this is a bit of a hack - we duplicate the array so we're not removing elements from the same array we're iterating over. Damn Javascript.
       _.each(jobsList.models.slice(0), (job) -> job.destroy())

     return false


Show Earth if there is no locationTag defined

--- workers/social/lib/social/models/account/render-homepage.coffee
+++ workers/social/lib/social/models/account/render-homepage.coffee
@@ -108,7 +108,7 @@

#{firstName} #{lastName}

-

#{locationTags[0] if locationTags}

+

#{if locationTags then locationTags[0] else 'Earth'}

                         #{nickname}.koding.com
                         member for #{if amountOfDays < 2 then 'a' else amountOfDays} day#{if amountOfDays > 1 then 's' else ''}.
@@ -131,7 +131,7 @@

#{about}

-
SKILLS

+
SKILLS

...


ComputeProvider: Koding: calculate next default label and pass storage option

--- workers/social/lib/social/models/computeproviders/koding.coffee
+++ workers/social/lib/social/models/computeproviders/koding.coffee
@@ -45,17 +45,48 @@
     callback null, "Koding is the best #{ client.r.account.profile.nickname }!"

+  calculateNextLabel = (user, group, label, callback)->
+
+    return callback null, label  if label?
+
+    JMachine  = require './machine'
+
+    selector   =
+      provider : "koding"
+      users    : $elemMatch: id: user.getId()
+      groups   : $elemMatch: id: group.getId()
+      label    : /^koding-vm-[0-9]*$/
+    options    =
+      limit    : 1
+      sort     : createdAt : -1
+
+    JMachine.one selector, options, (err, machine)->
+
+      return callback err  if err?
+      unless machine?
+        callback null, "koding-vm-0"
+      else
+
+        index = +(machine.label.split 'koding-vm-')[1]
+        callback null, "koding-vm-#{index+1}"
+
+
   @create = (client, options, callback)->

-    { instanceType } = options
+    { instanceType, label, storage } = options
+    { r: { group, user } } = client

-    meta =
-      type          : "amazon"
-      region        : "us-east-1"
-      source_ami    : "ami-2651904e"
-      instance_type : instanceType
+    calculateNextLabel user, group, label, (err, label)->

-    callback null, { meta, credential: client.r.user.username }
+      meta =
+        type          : "amazon"
+        region        : "us-east-1"
+        source_ami    : "ami-2651904e"
+        instance_type : "t2.micro"
+        storage_size  : storage ? 3
+        alwaysOn      : no
+
+      callback null, { meta, label, credential: client.r.user.username }

   @fetchUsage = (client, options, callback)->


Minor

Minor

--- src/stories.coffee
+++ src/stories.coffee
@@ -153,5 +153,6 @@
 #-----------------------------------------------
 # ### API
 #-----------------------------------------------
-mainStory = _createStory [], 'storyboard', 'ROOT STORY'
+title = (if k.IS_BROWSER then 'BROWSER' else 'SERVER') + ' ROOT STORY'
+mainStory = _createStory [], 'storyboard', title
 module.exports = mainStory


Send image url after restaurant info

Send image url after restaurant info

--- src/tabelog.coffee
+++ src/tabelog.coffee
@@ -51,12 +51,12 @@
       restaurant = _.sample(restaurants, 1)[0]
       console.log restaurant
       if restaurant
-        msg.send restaurant.image
         messages = []
         messages.push restaurant.name
         if restaurant.stars? and restaurant.stars != '' and restaurant.score? and restaurant.score != ''
           messages.push restaurant.stars + ' ' + restaurant.score
         messages.push restaurant.link
+        messages.push restaurant.image
         message = messages.join("\n")
       msg.send message


accept error on forms and display them

accept error on forms and display them

--- BackofficeBundle/Resources/public/coffee/FullPageFormView.coffee
+++ BackofficeBundle/Resources/public/coffee/FullPageFormView.coffee
@@ -50,6 +50,9 @@
         success: (response) ->
           options.html = response
           view = new FullPageFormView(options)
+        error: (response) ->
+          options.html = response.responseText
+          view = new FullPageFormView(options)
       return

   changeLanguage: (event) ->


Rewrite tip plugin to be clearer and more optimized.

Rename, since in hindsight, I can't handle
abbreviations: cls, $ts, $ctx, $t, _$tCurrent, c,
cDir, dir, evt, checkDir, tPosition, tWidth,
tHeight, etc.

Also differentiate between compound direction
objects and direction components.

Simplify options property by merging it into the
instance, so accessing option properties is
shorter and faster. This also gets rid of some
accessors.

For CoffeeScript, stop using _.each when a list
comprehension would do, and use do statements when
appropriate. Update chaining statements per parser
improvements. Keep one-liners short.

Minor white-spacing and reformatting.

--- src/js/jquery.hlf.tip.coffee
+++ src/js/jquery.hlf.tip.coffee
@@ -25,8 +25,8 @@
   #
   # - `ms.duration`- Duration of sleep and wake animations.
   # - `ms.delay` - Delay before sleeping and waking.
-  # - `cls.stem` - Empty to remove the stem.
-  # - `cls.follow` - Empty to disable cursor following.
+  # - `classNames.stem` - Empty to remove the stem.
+  # - `classNames.follow` - Empty to disable cursor following.
   # - `safeToggle` - Prevents orphan tips, since timers are sometimes unreliable.
   hlf.tip =
     debug: off
@@ -37,7 +37,7 @@
         when 'class'  then 'js-tips'
         else 'hlf.tip'

-    defaults: do (pre='js-tip-') ->
+    defaults: do (pre = 'js-tip-') ->
       ms:
         duration:
           in: 200
@@ -49,13 +49,12 @@
       defaultDirection: ['south', 'east']
       safeToggle: on
       autoDirection: on
-      cls: (->
-        cls = {}
-        _.each ['inner', 'content', 'stem', 'north', 'east', 'south', 'west', 'follow', 'trigger'],
-          (key) -> cls[key] = "#{pre}#{key}"
-        cls.tip = 'js-tip'
-        return cls
-      )()
+      classNames: do ->
+        classNames = {}
+        keys = ['inner', 'content', 'stem', 'north', 'east', 'south', 'west', 'follow', 'trigger']
+        (classNames[key] = "#{pre}#{key}") for key in keys
+        classNames.tip = 'js-tip'
+        classNames

   # Snap-Tip
   # --------
@@ -80,94 +79,107 @@
         when 'class'  then 'js-snap-tips'
         else 'hlf.snapTip'

-    defaults: do (pre='js-snap-tip-') ->
-      $.extend true, {}, hlf.tip.defaults,
+    defaults: do (pre = 'js-snap-tip-') ->
+      $.extend (deep = yes), {}, hlf.tip.defaults,
         snap:
           toTrigger: on
           toXAxis: off
           toYAxis: off
-        cls: (->
-          cls =
+        classNames: do ->
+          classNames =
             snap: {}
-          _.each
+          dictionary =
             toXAxis:   'x-side'
             toYAxis:   'y-side'
             toTrigger: 'trigger'
-          , (val, key) -> cls.snap[key] = "#{pre}#{val}"
-          cls.tip = 'js-tip js-snap-tip'
-          return cls
-        )()
+          (classNames.snap[key] = "#{pre}#{value}") for key, value of dictionary
+          classNames.tip = 'js-tip js-snap-tip'
+          classNames

   # Tip API
   # -------
   class Tip

-    constructor: (@$ts, @o, @$ctx) ->
-      _.bindAll @, '_onTriggerMouseMove', '_setBounds'
+    constructor: (@$triggers, options, @$context) ->
+
+      # - Extend self with `options`.
+      #   See default options for property names.
+      $.extend (deep = yes), @, options
+      # - Public properties.
+      #   Also includes `$triggers`, `$context`.
       @$tip = $ '
'
-      @doStem = @o.cls.stem isnt ''
-      @doFollow = @o.cls.follow isnt ''
-      # - Toggle state: `awake`, `asleep`, `waking`, `sleeping`.
+      @doStem = @classNames.stem isnt ''
+      @doFollow = @classNames.follow isnt ''
+      # - Protected properties.
+      #   `_state` toggles between: `awake`, `asleep`, `waking`, `sleeping`.
       @_state = 'asleep'
-      @_$tCurrent = null
-      # - Process tip
+      @_$currentTrigger = null
+      # - Process tip.
       @_render()
       @_bind()
-      # - Process triggers
-      @$ts.each (idx, el) =>
-        $t = $ el
-        $t.addClass @o.cls.trigger
-        @_saveTriggerContent $t
-        @_bindTrigger $t
-        @_updateDirectionByTrigger $t
+      # - Process triggers.
+      @$triggers.each (i, el) =>
+        $trigger = $ el
+        $trigger.addClass @classNames.trigger
+        @_saveTriggerContent $trigger
+        @_bindTrigger $trigger
+        @_updateDirectionByTrigger $trigger
+      # - Bind handler methods.
+      _.bindAll @, '_onTriggerMouseMove', '_setBounds'

     # ###Protected

     _defaultHtml: ->
-      do (c=@o.cls) =>
-        cDir = $.trim _.reduce @o.defaultDirection, ((cls, dir) => "#{cls} #{c[dir]}"), ''
-        containerClass = $.trim [c.tip, c.follow, cDir].join ' '
-        stemHtml = "

" if @doStem is on
-        # - Not using block strings b/c Docco 0.3.0 can't correctly parse them.
-        html = "

#{stemHtml}
"+
-               "

"
-
-    _saveTriggerContent: ($t) ->
-      title = $t.attr 'title'
-      if title then $t.data(@attr('content'), title).removeAttr 'title'
+      directionClass = $.trim(
+        _.reduce @defaultDirection, (classListMemo, directionComponent) =>
+          "#{classListMemo} #{@classNames[directionComponent]}"
+        , ''
+      )
+      containerClass = $.trim [@classNames.tip, @classNames.follow, directionClass].join ' '
+      stemHtml = "

" if @doStem is on
+      # - Not using block strings b/c Docco 0.3.0 can't correctly parse them.
+      html = "

#{stemHtml}
"+
+             "

"
+
+    _saveTriggerContent: ($trigger) ->
+      title = $trigger.attr 'title'
+      if title?
+        $trigger
+          .data @attr('content'), title
+          .removeAttr 'title'

     # - Link the trigger to the tip for:
     #   1. mouseenter, mouseleave (uses special events)
     #   2. mousemove
-    _bindTrigger: ($t) ->
-      $t.on @evt('truemouseenter'), (evt) =>
-        @debugLog evt
-        @_onTriggerMouseMove evt
-      $t.on @evt('truemouseleave'), (evt) => @sleepByTrigger $t
+    _bindTrigger: ($trigger) ->
+      $trigger.on @evt('truemouseenter'), (event) =>
+        @debugLog event
+        @_onTriggerMouseMove event
+      $trigger.on @evt('truemouseleave'), (event) => @sleepByTrigger $trigger
       if @doFollow is on
         if window.requestAnimationFrame?
-          onMouseMove = (evt) =>
+          onMouseMove = (event) =>
             requestAnimationFrame (timestamp) =>
-              @_onTriggerMouseMove evt
+              @_onTriggerMouseMove event
         else
           onMouseMove = _.throttle @_onTriggerMouseMove, 16
-        $t.on 'mousemove', onMouseMove
+        $trigger.on 'mousemove', onMouseMove

     # - Bind to the tip on hover so the toggling makes an exception.
     _bind: () ->
       @$tip
-        .on 'mouseenter', (evt) =>
+        .on 'mouseenter', (event) =>
           @debugLog 'enter tip'
-          if @_$tCurrent?
-            @_$tCurrent.data @attr('is-active'), yes
-            @wakeByTrigger @_$tCurrent
-        .on 'mouseleave', (evt) =>
+          if @_$currentTrigger?
+            @_$currentTrigger.data @attr('is-active'), yes
+            @wakeByTrigger @_$currentTrigger
+        .on 'mouseleave', (event) =>
           @debugLog 'leave tip'
-          if @_$tCurrent?
-            @_$tCurrent.data @attr('is-active'), no
-            @sleepByTrigger @_$tCurrent
+          if @_$currentTrigger?
+            @_$currentTrigger.data @attr('is-active'), no
+            @sleepByTrigger @_$currentTrigger
       # - Handle adapting to window resize.
-      if @o.autoDirection is on
+      if @autoDirection is on
         $(window).resize _.debounce @_setBounds, 300

     # - The tip should only need to be rendered once.
@@ -175,102 +187,114 @@
       return no if @$tip.html().length
       html = @htmlOnRender()
       if not (html? and html.length) then html = @_defaultHtml()
-      @$tip = $(html).addClass @o.cls.follow
-      @$tip.prependTo @$ctx
+      @$tip = $(html).addClass @classNames.follow
+      @$tip.prependTo @$context

     # - The tip content will change as it's being refreshed / initialized.
-    _inflateByTrigger: ($t) ->
-      do (c=@o.cls) =>
-        dir = if $t.data(@attr 'direction') then $t.data(@attr 'direction').split(' ') else @o.defaultDirection
-        @debugLog 'update direction class', dir
-        @$tip.find(".#{c.content}").text($t.data @attr 'content').end()
-             .removeClass([c.north, c.south, c.east, c.west].join ' ')
-             .addClass($.trim _.reduce dir, ((cls, dir) => "#{cls} #{c[dir]}"), '')
-
+    _inflateByTrigger: ($trigger) ->
+      compoundDirection = if $trigger.data(@attr 'direction') then $trigger.data(@attr 'direction').split(' ') else @defaultDirection
+      @debugLog 'update direction class', compoundDirection
+      @$tip
+        .find ".#{@classNames.content}"
+          .text $trigger.data @attr 'content'
+        .end()
+        .removeClass [
+          @classNames.north
+          @classNames.south
+          @classNames.east
+          @classNames.west
+        ].join ' '
+        .addClass $.trim(
+          _.reduce compoundDirection, (classListMemo, directionComponent) =>
+            "#{classListMemo} #{@classNames[directionComponent]}"
+          , ''
+        )

     # - The main toggle handler. Hooked into by `offsetOnTriggerMouseMove`.
-    _onTriggerMouseMove: (evt) ->
-      return no if not evt.pageX?
-      $t = if ($t = $(evt.currentTarget)) and $t.hasClass(@o.cls.trigger) then $t else $t.closest(@o.cls.trigger)
-      return no if not $t.length
-      @wakeByTrigger $t, evt, =>
+    _onTriggerMouseMove: (event) ->
+      return no if not event.pageX?
+      $trigger = if (
+        $trigger = $(event.currentTarget)) and
+        $trigger.hasClass(@classNames.trigger
+      ) then $trigger else $trigger.closest(@classNames.trigger)
+      return no if not $trigger.length
+      @wakeByTrigger $trigger, event, =>
         offset =
-          top: evt.pageY
-          left: evt.pageX
-        offset = @offsetOnTriggerMouseMove(evt, offset, $t) or offset
-        if @isDirection 'north', $t then offset.top -= @$tip.outerHeight() + @o.cursorHeight
-        if @isDirection 'west',  $t then offset.left -= @$tip.outerWidth()
-        if @isDirection 'south', $t then offset.top += @o.cursorHeight
-        offset.top += @o.cursorHeight
+          top: event.pageY
+          left: event.pageX
+        offset = @offsetOnTriggerMouseMove(event, offset, $trigger) or offset
+        if @isDirection('north', $trigger) then offset.top -= @$tip.outerHeight() + @cursorHeight
+        if @isDirection('west',  $trigger) then offset.left -= @$tip.outerWidth()
+        if @isDirection('south', $trigger) then offset.top += @cursorHeight
+        offset.top += @cursorHeight
         @$tip.css offset
         @debugLog '_onTriggerMouseMove', @_state, offset

     # - Auto-direction support. Given the context boundary, choose the best
     #   direction. The data is stored with the trigger and gets accessed elsewhere.
-    _updateDirectionByTrigger: ($t) ->
-      return no if @o.autoDirection is off
+    _updateDirectionByTrigger: ($trigger) ->
+      return no if @autoDirection is off
       # - Check if adapting is needed. Adapt and store as needed.
-      checkDir = (dir) =>
+      checkDirectionComponent = (component) =>
         if not @_bounds? then @_setBounds()
         ok = yes
-        switch dir
-          when 'south' then ok = (edge = tPosition.top + tHeight + size.height) and @_bounds.bottom > edge
-          when 'east'  then ok = (edge = tPosition.left + size.width)  and @_bounds.right > edge
-          when 'north' then ok = (edge = tPosition.top - size.height) and @_bounds.top < edge
-          when 'west'  then ok = (edge = tPosition.left - size.width) and @_bounds.left < edge
-        @debugLog 'checkDir', "'#{$t.html()}'", dir, edge, size
+        switch component
+          when 'south' then ok = (edge = triggerPosition.top + triggerHeight + tipSize.height) and @_bounds.bottom > edge
+          when 'east'  then ok = (edge = triggerPosition.left + tipSize.width) and @_bounds.right > edge
+          when 'north' then ok = (edge = triggerPosition.top - tipSize.height) and @_bounds.top < edge
+          when 'west'  then ok = (edge = triggerPosition.left - tipSize.width) and @_bounds.left < edge
+        @debugLog 'checkDirectionComponent', "'#{$trigger.html()}'", component, edge, tipSize
         if not ok
-          switch dir
-            when 'south' then newDir[0] = 'north'
-            when 'east'  then newDir[1] = 'west'
-            when 'north' then newDir[0] = 'south'
-            when 'west'  then newDir[1] = 'east'
-          $t.data @attr('direction'), newDir.join ' '
+          switch component
+            when 'south' then newDirection[0] = 'north'
+            when 'east'  then newDirection[1] = 'west'
+            when 'north' then newDirection[0] = 'south'
+            when 'west'  then newDirection[1] = 'east'
+          $trigger.data @attr('direction'), newDirection.join ' '
       # - Prepare for checking subroutine.
-      tPosition = $t.position()
-      tWidth    = $t.outerWidth()
-      tHeight   = $t.outerHeight()
-      size      = @sizeForTrigger $t
-      newDir = _.clone @o.defaultDirection
-      # - Check each direction.
-      checkDir dir for dir in @o.defaultDirection
+      triggerPosition = $trigger.position()
+      triggerWidth    = $trigger.outerWidth()
+      triggerHeight   = $trigger.outerHeight()
+      tipSize         = @sizeForTrigger $trigger
+      newDirection    = _.clone @defaultDirection
+      # - Check each direction component.
+      checkDirectionComponent component for component in @defaultDirection

     _setBounds: ->
-      $ctx = if @$ctx.is('body') then $(window) else @$ctx
+      $context = if @$context.is('body') then $(window) else @$context
       @_bounds =
-        top:    parseInt @$ctx.css('padding-top'), 10
-        left:   parseInt @$ctx.css('padding-left'), 10
-        bottom: $ctx.innerHeight()
-        right:  @$ctx.innerWidth()
+        top:    parseInt @$context.css('padding-top'), 10
+        left:   parseInt @$context.css('padding-left'), 10
+        bottom: $context.innerHeight()
+        right:  @$context.innerWidth()

     # ###Public

-    # Accessors
-    options: -> @o
-    tip: -> @$tip
     # - Does a stealth render to find tip size. The data is stored with the
     #   trigger and gets accessed elsewhere.
-    sizeForTrigger: ($t, force=no) ->
+    sizeForTrigger: ($trigger, force=no) ->
       # - Try cached.
       size =
-        width:  $t.data @attr 'width'
-        height: $t.data @attr 'height'
+        width:  $trigger.data @attr 'width'
+        height: $trigger.data @attr 'height'
       return size if size.width and size.height
       # - Otherwise new.
-      @$tip.find(".#{@o.cls.content}").text($t.data @attr 'content').end()
+      @$tip.find(".#{@classNames.content}").text($trigger.data @attr 'content').end()
         .css
           display: 'block',
           visibility: 'hidden'
-      $t.data @attr('width'),  (size.width = @$tip.outerWidth())
-      $t.data @attr('height'), (size.height = @$tip.outerHeight())
+      $trigger.data @attr('width'),  (size.width = @$tip.outerWidth())
+      $trigger.data @attr('height'), (size.height = @$tip.outerHeight())
       @$tip.css
         display: 'none',
         visibility: 'visible'
       size

     # - Direction is actually an array.
-    isDirection: (dir, $t) -> (@$tip.hasClass @o.cls[dir]) or
-      ((not $t? or not $t.data @attr 'direction') and _.include @o.defaultDirection, dir)
+    isDirection: (directionComponent, $trigger) ->
+      (@$tip.hasClass @classNames[directionComponent]) or
+      ((not $trigger? or not $trigger.data @attr 'direction') and
+        _.include @defaultDirection, directionComponent)

     # Methods

@@ -282,29 +306,29 @@
     #   4. If we are in the middle of sleeping, stop and speed up our waking
     #      transition.
     #   5. Update our trigger cache.
-    wakeByTrigger: ($t, evt, cb) ->
+    wakeByTrigger: ($trigger, event, onWake) ->
       # - Check.
-      triggerChanged = not $t.is @_$tCurrent
+      triggerChanged = not $trigger.is @_$currentTrigger
       if triggerChanged
-        @_inflateByTrigger $t
-        @_$tCurrent = $t
+        @_inflateByTrigger $trigger
+        @_$currentTrigger = $trigger
       # - Guard.
-      if @_state is 'awake' and cb?
-        cb()
+      if @_state is 'awake' and onWake?
+        onWake()
         @debugLog 'quick update'
         return yes
-      if evt? then @debugLog evt.type
+      if event? then @debugLog event.type
       return no if @_state in ['awake', 'waking']
       # - Prepare.
-      delay = @o.ms.delay.in
-      duration = @o.ms.duration.in
+      delay = @ms.delay.in
+      duration = @ms.duration.in
       wake = =>
-        @onShow triggerChanged, evt
+        @onShow triggerChanged, event
         @$tip.fadeIn duration, =>
           if triggerChanged
-            cb() if cb?
-          if @o.safeToggle is on then @$tip.siblings(@o.cls.tip).fadeOut()
-          @afterShow triggerChanged, evt
+            onWake() if onWake?
+          if @safeToggle is on then @$tip.siblings(@classNames.tip).fadeOut()
+          @afterShow triggerChanged, event
           @_state = 'awake'
       # - Run.
       if @_state is 'sleeping'
@@ -312,7 +336,7 @@
         clearTimeout @_sleepCountdown
         duration = 0
         wake()
-      else if (evt? and evt.type is 'truemouseenter')
+      else if event? and event.type is 'truemouseenter'
         triggerChanged = yes
         @_state = 'waking'
         @_wakeCountdown = setTimeout wake, delay
@@ -320,92 +344,91 @@
       yes

     # - Much simpler toggler. As long as tip isn't truly visible, sleep is unneeded.
-    sleepByTrigger: ($t) ->
+    sleepByTrigger: ($trigger) ->
       return no if @_state isnt 'awake'
       @_state = 'sleeping'
       clearTimeout @_wakeCountdown
       @_sleepCountdown = setTimeout =>
         @onHide()
-        @$tip.fadeOut @o.ms.duration.out, =>
+        @$tip.fadeOut @ms.duration.out, =>
           @_state = 'asleep'
           @afterHide()
-
-      , @o.ms.delay.out
+      , @ms.delay.out
       # - Success.
       yes

     # Hooks
-    onShow: (triggerChanged, evt) -> return
+    onShow: (triggerChanged, event) -> return
     onHide: $.noop
-    afterShow: (triggerChanged, evt) -> return
+    afterShow: (triggerChanged, event) -> return
     afterHide: $.noop
     htmlOnRender: $.noop
-    offsetOnTriggerMouseMove: (evt, offset, $t) -> no
+    offsetOnTriggerMouseMove: (event, offset, $trigger) -> no

   # SnapTip API
   # -----------
   class SnapTip extends Tip

-    constructor: ($ts, o, $ctx) ->
-      super $ts, o, $ctx
-      if @o.snap.toTrigger is off
-        @o.snap.toTrigger = @o.snap.toXAxis is on or @o.snap.toYAxis is on
-      if @o.snap.toXAxis is on then @o.cursorHeight = 0
-      if @o.snap.toYAxis is on then @o.cursorHeight = 2
+    constructor: ($triggers, options, $context) ->
+      super $triggers, options, $context
+      if @snap.toTrigger is off
+        @snap.toTrigger = @snap.toXAxis is on or @snap.toYAxis is on
+      if @snap.toXAxis is on then @cursorHeight = 0
+      if @snap.toYAxis is on then @cursorHeight = 2
       @_offsetStart = null
       # - Add snapping config as classes.
-      _.each @o.snap, (active, prop) => if active then @$tip.addClass @o.cls.snap[prop]
+      @$tip.addClass @classNames.snap[key] for key, active of @snap when active

     # ###Protected

     # - The main positioner. Uses the trigger offset as the base.
     #   TODO - Still needs to support all the directions.
-    _moveToTrigger: ($t, baseOffset) ->
-      # @debugLog baseOffset
-      offset = $t.offset()
-      if @o.snap.toXAxis is on
-        if @isDirection 'south' then offset.top += $t.outerHeight()
-        if @o.snap.toYAxis is off
+    _moveToTrigger: ($trigger, baseOffset) ->
+      #@debugLog baseOffset
+      offset = $trigger.offset()
+      if @snap.toXAxis is on
+        if @isDirection 'south' then offset.top += $trigger.outerHeight()
+        if @snap.toYAxis is off
           offset.left = baseOffset.left - (@$tip.outerWidth() - 12)/ 2 # Note arbitrary buffer offset.
-      if @o.snap.toYAxis is on
-        if @isDirection 'east' then offset.left += $t.outerWidth()
-        if @o.snap.toXAxis is off
+      if @snap.toYAxis is on
+        if @isDirection 'east' then offset.left += $trigger.outerWidth()
+        if @snap.toXAxis is off
           offset.top = baseOffset.top - @$tip.outerHeight() / 2
       offset

     # - Bind to get initial position for snapping. This is only for snapping
     #   without snapping to the trigger, which is only what's currently supported.
     #   See `afterShow` hook.
-    _bindTrigger: ($t) ->
-      super $t
-      $t.on @evt('truemouseleave'), (evt) => @_offsetStart = null
+    _bindTrigger: ($trigger) ->
+      super $trigger
+      $trigger.on @evt('truemouseleave'), (event) => @_offsetStart = null

     # ###Public

     # Hooked

     # - Make the tip invisible while it's being positioned, then reveal it.
-    onShow: (triggerChanged, evt) ->
+    onShow: (triggerChanged, event) ->
       if triggerChanged is yes
         @$tip.css 'visibility', 'hidden'

-    afterShow: (triggerChanged, evt) ->
+    afterShow: (triggerChanged, event) ->
       if triggerChanged is yes
         @$tip.css 'visibility', 'visible'
         @_offsetStart =
-          top: evt.pageY
-          left: evt.pageX
+          top: event.pageY
+          left: event.pageX

     # - Main positioning handler.
-    offsetOnTriggerMouseMove: (evt, offset, $t) ->
+    offsetOnTriggerMouseMove: (event, offset, $trigger) ->
       newOffset = _.clone offset
-      if @o.snap.toTrigger is on
-        newOffset = @_moveToTrigger $t, newOffset
+      if @snap.toTrigger is on
+        newOffset = @_moveToTrigger $trigger, newOffset
       else
-        if @o.snap.toXAxis is on
+        if @snap.toXAxis is on
           newOffset.top = @_offsetStart.top
           @debugLog 'xSnap'
-        if @o.snap.toYAxis is on
+        if @snap.toYAxis is on
           newOffset.left = @_offsetStart.left
           @debugLog 'ySnap'
       newOffset


Send exceptionmain after showing the error in the console.

--- src/main.coffee
+++ src/main.coffee
@@ -281,9 +281,10 @@
     # Handle uncaught exceptions from the main process
     process.on 'uncaughtException', (msg) ->
         #
-        ipcsend 'exceptioninmain', JSON.stringify(msg)
         console.error "Error on main process:\n#{msg}\n" +
             "--- End of error message. More details:\n", msg
+
+        ipcsend 'exceptioninmain', JSON.stringify(msg)

     #
     #


tweaked readability

tweaked readability

--- src/main.coffee
+++ src/main.coffee
@@ -46,9 +46,9 @@
 possiblyUpdate = ->
   return if code == textarea.getValue()

+  code = textarea.getValue()
   dirty = true

-  code = textarea.getValue()
   md = markdown(code)
   outputarea.find('.output').html(md)
   jsa = []


Attach to DOM in specs that alter the mini editor

This is now required since populateList() is only
calls when the timeout is fired and the select list
is still on the DOM.

--- spec/autocomplete-spec.coffee
+++ spec/autocomplete-spec.coffee
@@ -288,6 +288,9 @@
       expect(editor.lineForBufferRow(10)).toBe matchToSelect.text()

   describe "when the mini-editor receives keyboard input", ->
+    beforeEach ->
+      editor.attachToDom()
+
     describe "when text is removed from the mini-editor", ->
       it "reloads the match list based on the mini-editor's text", ->
         editor.getBuffer().insert([10,0] ,"t")


Update: ele::replaceWithの実装

Update: ele::replaceWithの実装

--- src/DOMExtention.coffee
+++ src/DOMExtention.coffee
@@ -46,6 +46,10 @@
 ele::removeChildren = ->
   @textContent = null
   return @
+if ele::replaceWith?
+  ele::replaceWith = (a) ->
+    @parentNode.replaceChild(a, @)
+    return
 # get/set family
 ele::parent = ->
   return @parentElement


BUG-FIX Route should return new controller

--- src/neck.coffee
+++ src/neck.coffee
@@ -435,6 +435,8 @@
       @_root().trigger 'route', controller
       @.trigger 'route', controller

+    controller
+
   ### RELEASE ###

   release: ->


Handle ECONNRESET errors when saving

Handle ECONNRESET errors when saving

Closes #7849

--- src/pane.coffee
+++ src/pane.coffee
@@ -700,6 +700,8 @@
       addWarningWithPath('Unable to save file: I/O error writing file')
     else if error.code is 'EINTR'
       addWarningWithPath('Unable to save file: Interrupted system call')
+    else if error.code is 'ECONNRESET'
+      addWarningWithPath('Unable to save file: Connection reset')
     else if error.code is 'ESPIPE'
       addWarningWithPath('Unable to save file: Invalid seek')
     else if errorMatch = /ENOTDIR, not a directory '([^']+)'/.exec(error.message)


Also on detail page

Also on detail page

--- SingularityUI/app/views/request.coffee
+++ SingularityUI/app/views/request.coffee
@@ -268,11 +268,8 @@
                             @refresh()
                         , 3000

-            if requestType is 'on-demand'
-                dialogType = vex.dialog.prompt
-                dialogOptions.message += '
Additional command line input (optional):
'
-            else
-                dialogType = vex.dialog.confirm
+            dialogType = vex.dialog.prompt
+            dialogOptions.message += '
Additional command line input (optional):
'

             dialogType dialogOptions


texnotes

texnotes

--- chrome/content/zotero-better-bibtex/zotero-better-bibtex.coffee
+++ chrome/content/zotero-better-bibtex/zotero-better-bibtex.coffee
@@ -1102,7 +1102,7 @@
     for dir in @searchpath
       path = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile)
       path.initWithPath(dir)
-      path.append(@executable)
+#      path.append(@executable)
 #      if path.exists()
 #        @pandoc = path.path
 #        break


texnotes

texnotes

--- chrome/content/zotero-better-bibtex/zotero-better-bibtex.coffee
+++ chrome/content/zotero-better-bibtex/zotero-better-bibtex.coffee
@@ -1094,10 +1094,10 @@
       @searchpath = env.get('PATH').split((if Zotero.isWin then ';' else ':'))
     else
       @searchpath = []
-#
-#    @executable = 'pandoc'
-#    @executable += '.exe' if Zotero.isWin
-#
+
+    @executable = 'pandoc'
+    @executable += '.exe' if Zotero.isWin
+
 #    @pandoc = null
 #    for dir in @searchpath
 #      path = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile)


Classroom: Removed loader from thumbs.

Classroom: Removed loader from thumbs.

--- client/landing/app/Applications/Classroom.kdapplication/Views/classroomclassthumbview.coffee
+++ client/landing/app/Applications/Classroom.kdapplication/Views/classroomclassthumbview.coffee
@@ -34,20 +34,13 @@
         @emit "EnrollmentCancelled"

     @cancelIcon = new KDCustomHTMLView cancelIconOptions
-    @loader     = new KDLoaderView
-      size      :
-        width   : 40
-
-    @loader.hide()

   click: ->
     data    = @getData()
     appView = @getDelegate()
     chapter = data.chapter

-    @loader.show()
     appView.goToClass data.name, =>
-      @loader.hide()
     @emit "EnrollmentRequested", data  if @getOptions().type isnt "enrolled"

   pistachio: ->
@@ -65,5 +58,4 @@
         #{data.name}
         #{data.version}

-      {{> @loader}}
     """


activity/flux: don't special case public channel

--- client/activity/lib/flux/actions/realtime/actioncreators.coffee
+++ client/activity/lib/flux/actions/realtime/actioncreators.coffee
@@ -1,6 +1,5 @@
 kd = require 'kd'
 actions = require '../actiontypes'
-getGroup = require 'app/util/getGroup'

 dispatch = (args...) -> kd.singletons.reactor.dispatch args...

@@ -38,9 +37,6 @@
     dispatch actions.UNLIKE_MESSAGE_SUCCESS, { userId, messageId }

   message.on 'AddReply', (comment) ->
-    if getGroup().socialApiChannelId is channelId
-      channel = kd.singletons.socialapi.retrieveCachedItemById channelId
-      dispatch actions.LOAD_MESSAGE_SUCCESS, { message: comment, channelId, channel }
     dispatch actions.LOAD_COMMENT_SUCCESS, { messageId, comment }

   message.on 'RemoveReply', (comment) ->


Emit MachineMounted event

Emit MachineMounted event

--- client/finder/lib/filetree/controllers/nfindercontroller.coffee
+++ client/finder/lib/filetree/controllers/nfindercontroller.coffee
@@ -143,6 +143,8 @@

     machineItem = @treeController.addNode @machines.last

+    @emit 'MachineMounted', machine, path
+
     if options.fetchContent and machineItem

       kd.utils.defer =>


KodingClient: Added “changedToLoggedIn` event

--- client/landing/app/MainApp/maincontroller/maincontroller.coffee
+++ client/landing/app/MainApp/maincontroller/maincontroller.coffee
@@ -61,13 +61,8 @@

       console.timeEnd "Koding.com loaded"

-  accountChanged:(account, firstLoad = no)->
-    @userAccount             = account
-    connectedState.connected = yes
-
-    @on "pageLoaded.as.loggedIn", (account)=> # ignore othter parameters
-      KD.utils.setPreferredDomain account if account
-      if registerToKodingClient = $.cookie "register-to-koding-client"
+  registerKodingClient: ->
+    if registerToKodingClient = $.cookie "register-to-koding-client"
         clear = ->
           $.cookie "register-to-koding-client", erase:yes
           window.location.pathname = "/"
@@ -129,12 +124,23 @@
               hostname:result.hostID
           }, (err, res)=>
             fn = => k.tell "info", handleInfo
-            return showErrorModal err, fn if err
-            clear()
-            result.cb true
-            KD.utils.wait 500, clear
+            return showErrorModal err.message, fn if err
+            showSuccessfulModal res, =>
+              result.cb true
+              KD.utils.wait 500, clear

         k.tell "info", handleInfo
+
+  accountChanged:(account, firstLoad = no)->
+    @userAccount             = account
+    connectedState.connected = yes
+
+    @on "pageLoaded.as.loggedIn", (account)=> # ignore othter parameters
+      KD.utils.setPreferredDomain account if account
+      @emit "changedToLoggedIn"
+
+    @once "accountChanged.to.loggedIn", (account)=> # ignore othter parameters
+      @emit "changedToLoggedIn"

     account.fetchMyPermissionsAndRoles (err, permissions, roles)=>
       return warn err  if err
@@ -179,6 +185,9 @@
   attachListeners:->
     # @on 'pageLoaded.as.(loggedIn|loggedOut)', (account)=>
     #   log "pageLoaded", @isUserLoggedIn()
+
+    @once 'changedToLoggedIn', (account)=>
+      @registerKodingClient()

     # TODO: this is a kludge we needed.  sorry for this.  Move it someplace better C.T.
     wc = @getSingleton 'windowController'


webapp/latex: exclusive lock to avoid concurrent latex operations

--- src/smc-webapp/latex/document.coffee
+++ src/smc-webapp/latex/document.coffee
@@ -270,16 +270,28 @@
         sha_marker = misc.uuid()
         @_need_to_run ?= {}
         @_need_to_run.latex = false
+        # exclusive lock, wait 5 secs to run or fail, exit code on timeout acquiring lock is 99,
+        # release read lock to avoid stuck subprocesses to interfere, file descriptor 9 points to lockfile (derived from tex file)
+        flock = "flock -x -o -w 5 9 || exit 99;"
         # yes x business recommended by http://tex.stackexchange.com/questions/114805/pdflatex-nonstopmode-with-tikz-stops-compiling
-        latex_cmd = "yes x 2> /dev/null | #{command}; echo '#{sha_marker}'; test -r '#{sagetex_file}' && sha1sum '#{sagetex_file}'"
+        latex_cmd = "( #{flock} yes x 2> /dev/null | #{command}; echo '#{sha_marker}'; test -r '#{sagetex_file}' && sha1sum '#{sagetex_file}' ) 9> '.#{@filename_tex}.lock'"
+        #if DEBUG then console.log("_run_latex cmd:", latex_cmd)
         @_exec
             command     : latex_cmd
             bash        : true
-            timeout     : 30
+            timeout     : 45
             err_on_exit : false
             cb          : (err, output) =>
+                #if DEBUG then console.log("_run_latex done: output=", output, ", err=", err)
                 if err
                     cb?(err)
+                else if output.exit_code == 99
+                    #if DEBUG then console.log("_run_latex: most likely there was a lock-acquiring timeout.")
+                    # TODO schedule a retry?
+                    log = 'Timeout: ongoing concurrent LaTeX operation.'
+                    log += '\n\n' + output.stdout + '\n\n' + output.stderr
+                    @last_latex_log = log
+                    cb?(false, log)
                 else
                     i = output.stdout.lastIndexOf(sha_marker)
                     if i != -1


respond to all paths because haproxy does not like me today

--- feed/server.coffee
+++ feed/server.coffee
@@ -17,7 +17,7 @@
 debug "using API server at #{server}"
 debug "using self URL #{self}"

-app.get '/', Promise.coroutine (req, res, next) ->
+app.get '/*', Promise.coroutine (req, res, next) ->

     if not geocaches? or not lastFetch? or new Date - lastFetch > 60000
         debug 'fetching geocaches'


Change map to TERRAIN. Don't save datatables state.

--- app/assets/javascripts/bikeways.js.coffee
+++ app/assets/javascripts/bikeways.js.coffee
@@ -28,7 +28,8 @@
     # see https://developers.google.com/maps/documentation/javascript/reference?hl=fr#MapOptions
     provider: {
       scrollwheel: false,
-      zoom: 16
+      zoom: 16,
+      mapTypeId: google.maps.MapTypeId.TERRAIN
     }
     internal: { id: 'map' }
   handler.buildMap(opts, ->
@@ -45,5 +46,5 @@
     processing: true
     serverSide: true
     ajax: $('#segments').data('source')
-    stateSave: true
+    stateSave: false
     deferRender: true


update constant size when saved; add notice;

--- app/assets/javascripts/settings.js.coffee
+++ app/assets/javascripts/settings.js.coffee
@@ -1,16 +1,18 @@
 settingsonload = ->
   $('.edit-constant-content').click (e) ->
+    link = $(this)
     action = $(this).data('action')
     e.preventDefault();
+    notice = $('<div />',{style:"margin: 3px 0"}).text('Close this dialog to save content. Refresh page to cancel.')
     textarea = $('<textarea />', {cols:40, id: "constant_content", rows: 10}).val("Loading...")
     editor = null
-    $('<div />').append(textarea).appendTo('body').modal().on $.modal.BEFORE_CLOSE, (event, modal) ->
+    $('<div />').append(notice).append(textarea).appendTo('body').modal().on $.modal.BEFORE_CLOSE, (event, modal) ->
       $.ajax({
           url: action ,
           type: 'PUT',
           data: { content: editor.getValue() }
           success: (data) ->
-            console.log data
+            link.closest('tr').find('td.size').text(data.content) # update new constant size
       });
       $("div.modal").remove();
     editor = CodeMirror.fromTextArea document.getElementById("constant_content"), {


use defaultValue as input value if input empty

--- jsapp/xlform/src/view.params.templates.coffee
+++ jsapp/xlform/src/view.params.templates.coffee
@@ -1,12 +1,17 @@
 module.exports = do ->
-  numberParam = (label, number, defaultValue) ->
+  numberParam = (label, currentValue, defaultValue) ->
     if typeof defaultValue isnt 'undefined'
       defaultValueAttr = "placeholder='#{defaultValue}'"
+
+    if currentValue isnt ''
+      valueAttr = "value='#{currentValue}'"
+    else if typeof defaultValue isnt 'undefined'
+      valueAttr = "value='#{defaultValue}'"

     return """

       #{label}
-      <input class='text-box__input' type='number' value='#{number}' #{defaultValueAttr}/>
+      <input class='text-box__input' type='number' #{valueAttr} #{defaultValueAttr}/>

     """


Remove duplicate line

Remove duplicate line

--- services/web/public/coffee/ide/file-tree/controllers/FileTreeController.coffee
+++ services/web/public/coffee/ide/file-tree/controllers/FileTreeController.coffee
@@ -93,7 +93,6 @@
 				if !name? or name.length == 0
 					return
 				$scope.state.inflight = true
-				$scope.state.inflight = true
 				ide.fileTreeManager
 					.createFolder(name, parent_folder)
 					.error (e)->


Add failing spec for rightward movement over folds.

--- spec/atom/editor-spec.coffee
+++ spec/atom/editor-spec.coffee
@@ -750,4 +750,9 @@
         expect(editor.getCursorScreenPosition()).toEqual [6, 5]
         expect(editor.getCursorBufferPosition()).toEqual [9, 5]

-
+        editor.setCursorScreenPosition([4, 30])
+        expect(editor.getCursorScreenPosition()).toEqual [4, 29]
+        editor.moveCursorRight()
+        expect(editor.getCursorScreenPosition()).toEqual [4, 32]
+
+


Rename require from atom-api to atom

Rename require from atom-api to atom

--- spec/github-file-spec.coffee
+++ spec/github-file-spec.coffee
@@ -1,5 +1,5 @@
 GitHubFile = require '../lib/github-file'
-{fs} = require 'atom-api'
+{fs} = require 'atom'
 path = require 'path'

 describe "GitHubFile", ->


Warn on invalid JSON specs; fix

Warn on invalid JSON specs; fix

--- spec/schema/main-spec.coffee
+++ spec/schema/main-spec.coffee
@@ -48,7 +48,13 @@
       expect(sample).toEqual test.equal

 glob.sync("#{__dirname}/**/*.json").forEach (file) ->
-  suite = JSON.parse(fs.readFileSync(file))
+  suite = try
+    JSON.parse(fs.readFileSync(file))
+  catch e
+    console.log "Invalid JSON: #{file}"
+    console.log e.message
+    process.exit 1
+    null

   (if Array.isArray(suite) then suite else [suite]).forEach (suite) ->
     return if suite.xdescription


updates

updates

--- src/poll.coffee
+++ src/poll.coffee
@@ -11,38 +11,15 @@
 #   hubot stop poll [pollId]
 #   hubot vote [pollId] [#option]
 # Author:
-#   logikz
+#   logikz
+class Option
+	constructor: () ->
+class Poll
+	options
+	constructor: (@id) ->
+		options = {}

 module.exports = (robot) ->
-	# generateId = ->
-	# 	text = ""
-	# 	possibleValues = "0123456789abcdef"
-	# 	text += possibleValues.charAt(Math.floor(Math.random() * possibleValues.length)) for [1..5]
-
-	# parseOptions = (optionsString) ->
-	# 	(optionsString.split "option: ")[1..]
-
-	# createPoll = (topic, options) ->
-	# 	@robot.logger.info "Creating poll with #{topic}"
-	# 	id = generateId()
-	# 	pollOptions = parseOptions options
-	# 	@robot.logger.info "We have #{pollOptions.length()} options"
-	# 	@robot.brain.data.poll[id].topic = topic
-	# 	optionsString = ""
-
-	# 	for pollOption in pollOptions
-	# 		index = pollOptions.indexOf(pollOption)
-	# 		robot.brain.data.poll[id].option[index].text
-	# 		optionsString += "\t#{index}: #{pollOption}\n"
-	# 	@robot.brain.save()
-	# 	@robot.logger.info "Brain saved"
-
-	# 	text =  """
-	# 			POLL ID: #{id}
-	# 			Topic: #{topic}
-	# 			Options:
-	# 			#{optionsString}
-	# 			"""
 	robot.respond /start poll (.*?)\s(option:\s?.*)+/i, (msg) ->
 		try
 			@robot.logger.info "Create poll called: #{msg}"
@@ -59,12 +36,13 @@
 			pollOptions = (options.split "option: ")[1..]
 			@robot.logger.info "We have #{pollOptions.length} options"
 			@robot.brain.data.poll = {}
+			@robot.brain.data.poll[id] = new Poll(id)
 			@robot.brain.data.poll[id].topic = topic
 			optionsString = ""

 			for pollOption in pollOptions
 				index = pollOptions.indexOf(pollOption)
-				robot.brain.data.poll[id].option[index].text
+				robot.brain.data.poll[id].options[index].text = pollOption
 				optionsString += "\t#{index}: #{pollOption}\n"
 			@robot.brain.save()
 			@robot.logger.info "Brain saved"


Add spread-length to SpreadEnv (for toBooleanSpread)

--- src/Dataflow/SpreadEnv.coffee
+++ src/Dataflow/SpreadEnv.coffee
@@ -1,9 +1,11 @@
+_ = require "underscore"
+
 Spread = require "./Spread"

 # TODO: This should have tests for isEqualTo and contains

 module.exports = class SpreadEnv
-  constructor: (@parent, @origin, @index) ->
+  constructor: (@parent, @origin, @index, @length) ->

   lookup: (spread) ->
     if spread.origin == @origin
@@ -32,7 +34,7 @@
   # Note: assign is not a mutation, it returns a new SpreadEnv where spread is
   # assigned to index.
   assign: (spread, index) ->
-    return new SpreadEnv(this, spread.origin, index)
+    return new SpreadEnv(this, spread.origin, index, spread.items.length)

   isEqualTo: (spreadEnv) ->
     return false unless spreadEnv?
@@ -45,5 +47,17 @@
     return true if @isEqualTo(spreadEnv)
     return @contains(spreadEnv.parent)

+  # Returns a spread of booleans reporting "are you at the location marked by
+  # this SpreadEnv?"
+  toBooleanSpread: () ->
+    # Note: This often returns an irregular ("ragged") spread. These work fine.
+
+    if not @length then return true
+
+    items = _.range(@length).map(() => false)
+    items[@index] = @parent.toBooleanSpread()
+
+    new Spread(items, @origin)
+

 SpreadEnv.empty = new SpreadEnv()


Rename context menu item from "Open File" to "Jump to File"

--- menus/git.cson
+++ menus/git.cson
@@ -34,7 +34,7 @@
 'context-menu':
   '.github-FilePatchListView-item': [
     {
-      'label': 'Open File'
+      'label': 'Jump to File'
       'command': 'github:jump-to-file'
     }
   ]
@@ -43,7 +43,7 @@
       'type': 'separator'
     }
     {
-      'label': 'Open File'
+      'label': 'Jump to File'
       'command': 'github:jump-to-file'
       'after': ['core:confirm']
     }


Add comment about a possible ellipsis method (for future reference if needed)

--- core/app/backbone/views/ndp_interacting_users_names_view.coffee
+++ core/app/backbone/views/ndp_interacting_users_names_view.coffee
@@ -29,6 +29,8 @@
     numberNotDisplayed: => Math.max(0, @collection.totalRecords - @show_number_of_users)
     multipleNotDisplayed: => (@collection.totalRecords - @show_number_of_users) > 1

+  #Possible method restrict names to one line: http://jsbin.com/esikiv/3/edit
+
   show_all: (e) ->
     e.stopPropagation()
     e.preventDefault()


Fix signin redirect

Fix signin redirect

--- lib/assets/javascripts/routers/auth.js.coffee
+++ lib/assets/javascripts/routers/auth.js.coffee
@@ -8,7 +8,7 @@
   }

   signin: (params) =>
-    params.redirect = null if params.redirect && params.redirect.indexOf('://') < params.redirect.indexOf('/')
+    params.redirect = null if params.redirect && params.redirect.indexOf('://') != -1 && params.redirect.indexOf('://') < params.redirect.indexOf('/')
     params.redirect ?= TentStatus.config.PATH_PREFIX || '/'

     if TentStatus.config.authenticated


Update navigation controller stack history management

--- app/src/base/navigation_controller.coffee
+++ app/src/base/navigation_controller.coffee
@@ -1,5 +1,6 @@
 class @NavigationController extends @ViewController

+  _historyLength: 1
   viewControllers: []
   childViewControllerContentId: 'navigation_controller_content'

@@ -7,6 +8,8 @@
     if @topViewController()?
       @topViewController().onDetach()
       @topViewController().parentViewController = undefined
+    if @viewControllers.length >= @_historyLength
+      @viewController.splice(0, 1)
     @viewControllers.push viewController
     viewController.parentViewController = @
     viewController.onAttach()


Fix remove callback for Chrome 43

Fix remove callback for Chrome 43

--- app/src/utils/storage/chrome_store.coffee
+++ app/src/utils/storage/chrome_store.coffee
@@ -32,6 +32,10 @@
   # @see ledger.storage.Store#_raw_remove
   _raw_remove: (keys, cb=->) ->
     try
-      chrome.storage.local.remove(keys, cb)
+      if getChromeVersion() >= 42
+        chrome.storage.local.remove(keys)
+        _.defer(cb)
+      else
+        chrome.storage.local.remove(keys, cb)
     catch e
       console.error("chrome.storage.local.remove :", e)


refs #5 Fixes list context switcher of main navigation.

--- app/assets/javascripts/voluntary_ranking/controllers/navigation_controller.js.coffee
+++ app/assets/javascripts/voluntary_ranking/controllers/navigation_controller.js.coffee
@@ -1,9 +1,13 @@
 # TODO: why .reopen and not .extend?
-VoluntaryOnEmberjs.NavigationController = VoluntaryOnEmberjs.Controller.reopen
+Volontariat.NavigationController = Volontariat.Controller.reopen
   listContext: 'Global'

   listContextDidChange: ((sender, key, value, rev) ->
-    @transitionToRoute('rankings.reload')
+    unless $('.topic').val() == undefined
+      if @get('listContext') == 'Your'
+        @transitionToRoute('profile.rankings', $('.adjective').val(), $('.negative_adjective').val(), $('.topic').val(), $('.scope').val(), 1)
+      else
+        @transitionToRoute('rankings.show', $('.adjective').val(), $('.negative_adjective').val(), $('.topic').val(), $('.scope').val(), 1)
   ).observes('listContext')

-VoluntaryOnEmberjs.NavigationController.listContexts = ['Global', 'Your']+Volontariat.NavigationController.listContexts = ['Global', 'Your']


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/number_extensions.coffee
+++ src/number_extensions.coffee
@@ -468,7 +468,7 @@
     get: ->
       this * Math.TAU

-unless 1.rotation
+unless 1.turn
   Object.defineProperty Number::, 'rotation',
     get: ->
       this * Math.TAU


prevent exception when scrolling during rerender in pdfng

--- services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee
+++ services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee
@@ -137,7 +137,8 @@
 			if visible
 				# console.log 'found it', topPageIdx
 			else
-				console.log 'CANNOT FIND TOP PAGE'
+				# console.log 'CANNOT FIND TOP PAGE'
+				return

 			# console.log 'top page is', topPage.pageNum, topPage.elemTop, topPage.elemBottom, topPage
 			top = topPage.elemTop
@@ -296,7 +297,9 @@
 					scope.scrollHandlerTimeout = null
 					updateContainer()
 					scope.$apply()
-					scope.position = ctrl.getPdfPosition()
+					newPosition = ctrl.getPdfPosition()
+					if newPosition?
+						scope.position = newPosition
 					scope.$apply()

 				scope.$watch 'pdfSrc', (newVal, oldVal) ->


DOM: add space “small”

DOM: add space “small”

--- src/base/DOM/DOM.coffee
+++ src/base/DOM/DOM.coffee
@@ -1331,6 +1331,8 @@

 	@space: (style = null) ->
 		switch style
+			when "small"
+				@element("DIV", class: "cui-small-space")
 			when "large"
 				@element("DIV", class: "cui-large-space")
 			when "flexible"


Add 'pager incident NNNN' to make it easier to debug incidents. Fix formatIncident to not freak out if not assigned to someone

--- src/scripts/pagerduty.coffee
+++ src/scripts/pagerduty.coffee
@@ -79,6 +79,10 @@
             end = moment(json.override.end)
             msg.send "Rejoice, #{old_username}! #{json.override.user.name} has the pager until #{end.format()}"

+  robot.respond /(pager|major)( me)? incident (.*)$/, (msg) ->
+    pagerDutyIncident msg, msg.match[3], (incident) ->
+      msg.send formatIncident(incident)
+
   robot.respond /(pager|major)( me)? (inc|incidents|sup|problems)$/i, (msg) ->
     pagerDutyIncidents msg, (incidents) ->
       if incidents.length > 0
@@ -250,6 +254,10 @@
     else
       cb(pagerDutyUsers)

+  pagerDutyIncident = (msg, incident, cb) ->
+    pagerDutyGet msg, "/incidents/#{encodeURIComponent incident}", {}, (json) ->
+      cb(json)
+
   pagerDutyIncidents = (msg, cb) ->
     query =
       status:  "triggered,acknowledged"
@@ -277,7 +285,7 @@
      #   SERVICESTATE: 'CRITICAL',
      #   HOSTSTATE: 'UP' },

-    extra = if inc.trigger_summary_data
+    summary = if inc.trigger_summary_data
               # email services
               if inc.trigger_summary_data.subject
                 inc.trigger_summary_data.subject
@@ -289,12 +297,15 @@
                  "#{inc.trigger_summary_data.HOSTNAME}/#{inc.trigger_summary_data.HOSTSTATE}"
               else
                 ""
-                inspect inc
             else
               ""
-              inspect inc
-
-    "#{inc.incident_number}: #{inc.created_on} #{extra} - assigned to #{inc.assigned_to_user.name}\n"
+    assigned_to = if inc.assigned_to_user
+                    "- assigned to #{inc.assigned_to_user.name}"
+                  else
+                    ""
+
+
+    "#{inc.incident_number}: #{inc.created_on} #{summary} #{assigned_to}\n"

   updateIncident = (msg, incident_number, status) ->
     withPagerDutyUsers msg, (users) ->


Highlight Pic files which use hashbangs

Highlight Pic files which use hashbangs

The GNU pic2plot program enables users to "run" pic files as executables
to generate output. Such files won't always include calls to PS/PE.

--- grammars/roff.cson
+++ grammars/roff.cson
@@ -2172,6 +2172,12 @@
 				0: {name: "meta.function.end.picture.section.macro.roff"}
 				1: {name: "punctuation.definition.macro.roff"}
 				2: {name: "entity.name.function.roff"}
+		},{
+			#!/usr/bin/pic2plot: Pic hashbang
+			begin: "\\A#!?/.+/pic2plot(?=\\s|$)(.*)"
+			end:   "\\z"
+			patterns: [include: "#pic"]
+			beginCaptures: 0: name: "comment.line.shebang.pic.roff"
 		}]


update grunt available task messaging to reflect change in not building docs by default

--- gruntConfig.coffee
+++ gruntConfig.coffee
@@ -67,10 +67,10 @@
           filter: 'include'
           tasks: ['build', 'test', 'watch',  'clean', 'docs']
           descriptions:
-            build: "Builds everything including docs, examples"
+            build: "Builds everything except docs & examples"
             test: "Builds everything and then run tests in /test"
-            watch: "Watch for changing files and calls build. Also watches examples and docs"
-            docs: "Build the docs. To publish to github.io, you must pull master into gh-pages"
+            watch: "Watch for changing files and calls build."
+            docs: "Build the docs. To publish to github.io, you must pull master into gh-pages and run 'grunt build docs' in the gh-pages branch"
             clean: "Remove all compiled files. Use `grunt clean build` to rebuild everything from scratch"

     watch:


webapp: ignoring latex printing errors when requesting the subdirectory of temporary files

--- src/smc-webapp/editor.coffee
+++ src/smc-webapp/editor.coffee
@@ -1270,12 +1270,14 @@
                         path        : @filename
                         options     : options
                         cb          : (err, _pdf) =>
-                            if err
+                            if err and not is_subdir
                                 cb(err)
                             else
                                 pdf = _pdf
                                 cb()
                 (cb) =>
+                    if is_subdir or not pdf?
+                        cb(); return
                     # does the pdf file exist?
                     project_tasks(@project_id).file_nonzero_size
                         path    : pdf
@@ -1288,6 +1290,8 @@
                             else
                                 cb()
                 (cb) =>
+                    if is_subdir or not pdf?
+                        cb(); return
                     # pdf file exists -- show it in the UI
                     url = salvus_client.read_file_from_project
                         project_id  : @project_id


Use proper done callback.

Use proper done callback.

--- src/spec/mapping.spec.coffee
+++ src/spec/mapping.spec.coffee
@@ -1,11 +1,12 @@
 Mapping = require '../lib/mapping'
-config = require '../config'
+Config = require '../config'
 {parseString} = require 'xml2js'

 describe '#mapOrder', ->
   beforeEach ->
-    @mapping = new Mapping config
-  it 'simple', ->
+    @mapping = new Mapping Config
+
+  it 'simple', (done) ->
     order =
       id: 'abc'
       version: 1
@@ -16,8 +17,9 @@
       expect(result.order.version[0]).toBe '1'
       expect(result.order.orderState).toBeUndefined()
       expect(result.order.externalCustomerId[0]).toBe 'UNKNOWN'
+      done()

-  it 'lineItem', ->
+  it 'lineItem', (done) ->
     order =
       lineItems: [
         id: 'l1'
@@ -61,8 +63,9 @@
       expect(li.taxRate[0].name[0]).toBe 'Mehrwertsteuer'
       expect(li.taxRate[0].amount[0]).toBe '0.19'
       expect(li.taxRate[0].country[0]).toBe 'DE'
+      done()

-  it 'customLineItem', ->
+  it 'customLineItem', (done) ->
     order =
       customLineItems: [
         id: 'cl1'
@@ -100,8 +103,9 @@
       expect(cli.taxRate[0].name[0]).toBe 'Mehrwertsteuer'
       expect(cli.taxRate[0].amount[0]).toBe '0.19'
       expect(cli.taxRate[0].country[0]).toBe 'DE'
+      done()

-  it 'taxedPrice', ->
+  it 'taxedPrice', (done) ->
     order =
       taxedPrice:
         totalNet:
@@ -126,8 +130,9 @@
       expect(result.order.taxedPrice[0].taxPortions[0].rate[0]).toBe 'MwSt'
       expect(result.order.taxedPrice[0].taxPortions[0].amount[0].currencyCode[0]).toBe 'EUR'
       expect(result.order.taxedPrice[0].taxPortions[0].amount[0].centAmount[0]).toBe '190'
+      done()

-  it 'shippingAddress', ->
+  it 'shippingAddress', (done) ->
     order =
       shippingAddress:
         title: 'Prof. Dr.'
@@ -135,8 +140,9 @@
     parseString doc, (err, result) ->
       expect(result.order.shippingAddress).not.toBeUndefined()
       expect(result.order.shippingAddress[0].title[0]).toBe 'Prof. Dr.'
+      done()

-  it 'billingAddress', ->
+  it 'billingAddress', (done) ->
     order =
       billingAddress:
         pOBox: '123456789'
@@ -144,8 +150,9 @@
     parseString doc, (err, result) ->
       expect(result.order.billingAddress).not.toBeUndefined()
       expect(result.order.billingAddress[0].pOBox[0]).toBe '123456789'
+      done()

-  it 'customerGroup', ->
+  it 'customerGroup', (done) ->
     order =
       customerGroup:
         typeId: 'customer-group'
@@ -160,8 +167,9 @@
       expect(cg.id[0]).toBe '213'
       expect(cg.version[0]).toBe '3'
       expect(cg.name[0]).toBe 'B2B'
+      done()

-  it 'paymentInfo', ->
+  it 'paymentInfo', (done) ->
     order =
       paymentInfo:
         paymentID: '7'
@@ -171,8 +179,9 @@
       expect(result.order.paymentInfo).not.toBeUndefined()
       expect(result.order.paymentInfo[0].paymentID[0]).toBe '7'
       expect(result.order.paymentInfo[0].paymentMethod[0]).toBe 'Cash'
+      done()

-  it 'shippingInfo', ->
+  it 'shippingInfo', (done) ->
     order =
       shippingInfo:
         price:
@@ -185,4 +194,5 @@
       expect(result.order.shippingInfo).not.toBeUndefined()
       expect(result.order.shippingInfo[0].price[0].currencyCode[0]).toBe 'USD'
       expect(result.order.shippingInfo[0].price[0].centAmount[0]).toBe '999'
-      expect(result.order.shippingInfo[0].taxRate[0].includedInPrice[0]).toBe 'true'+      expect(result.order.shippingInfo[0].taxRate[0].includedInPrice[0]).toBe 'true'
+      done()


Remove unused function

Remove unused function

--- src/type.coffee
+++ src/type.coffee
@@ -15,9 +15,8 @@
  TypeName, PointerType, ArrowType, StructType} = require './nodes'
 {flatten, extend, tystr} = require './helpers'

-# HEAP is the byte-sized view.
-HEAP    = new Literal '_I8'
-# Views of other sizes.
+# Views.
+I8      = new Literal '_I8'
 U8      = new Literal '_U8'
 I16     = new Literal '_I16'
 U16     = new Literal '_U16'
@@ -524,8 +523,8 @@
   else
     for i in [0...ty.size]
       offset = new Value new Literal i
-      stmts.push new Assign new Value(HEAP, [new Index new Op '+', new Value(destPtr), offset]),
-                            new Value(HEAP, [new Index new Op '+', new Value(srcPtr), offset])
+      stmts.push new Assign new Value(U8, [new Index new Op '+', new Value(destPtr), offset]),
+                            new Value(U8, [new Index new Op '+', new Value(srcPtr), offset])
   stmts.push new Value destPtr
   new Value new Parens new Block stmts

@@ -545,14 +544,6 @@
     propList.push new Assign new Value(new Literal fname), propValue.transform(), 'object'
   obj = new Value new Obj propList
   new Value new Parens new Block [new Assign(new Value(ptr), v), obj]
-
-# Pull out the last non-comment, non-declaration, and non-type assign node of
-# a node list.
-lastNonCommentOrDeclaration = (list) ->
-  i = list.length
-  return i while i-- when list[i] not instanceof Comment and
-                          list[i] not instanceof DeclareType and
-                          list[i] not instanceof TypeAssign

 # Transform a function to have the right stack pointer computations upon entry
 # and exit. The safe way is to wrap the entire body of the function in a
@@ -685,7 +676,7 @@

 # Cache this for typing null values.
 anyPtrTy = new PointerType null
-byteTy   = new PrimitiveType 1, 'byte',  HEAP, yes
+byteTy   = new PrimitiveType 1, 'byte',  U8,  no
 shortTy  = new PrimitiveType 2, 'short', I16, yes
 intTy    = new PrimitiveType 4, 'int',   I32, yes
 uintTy   = new PrimitiveType 4, 'uint',  U32, no
@@ -728,7 +719,7 @@
       exprs.unshift new Assign obj, requireExpr 'heap/malloc'
     # Bring in the heap views.
     props = []
-    props.push new Value view for view in [HEAP, U8, I16, U16, I32, U32]
+    props.push new Value view for view in [I8, U8, I16, U16, I32, U32]
     obj = new Value new Obj props
     exprs.unshift new Assign obj, requireExpr 'heap/heap'


fix /github.com/sagemathinc/cocalc/issues/2561 (I think); also add comment about the root cause, which remains unsolved, but should be mitigated enough for us to get by for now.

--- src/smc-util/synctable.coffee
+++ src/smc-util/synctable.coffee
@@ -80,6 +80,20 @@
 this could be fine.  However, on reconnect, the first thing is that complete upstream state of
 table is set on server version of table, so reconnecting user only sends its changes if upstream
 hasn't changed anything in that same record.
+
+
+SERIOUS UNFINISHED ISSUE:
+1. Non-admin user is a collab on a project
+2. They open and edit a file
+3. They have some offline changes
+4. They are removed from that project as collab before those changes are saved
+5. There will be changes (and updates to file_use) that are denied, with
+   the error "FATAL: user must be an admin".  The client will just keep
+   retrying those forever, until the client refreshes their browser.
+6. Solving this is pretty tricky, e.g., the file_use table would have to selectively
+   have entries removed from it.  This just isn't solved.  The cb_fatal below
+   is just a workaround to reduce the impact of this problem, while hopefully
+   not breaking things too badly.
 ###

 # if true, will log to the console a huge amount of info about every get/set
@@ -98,8 +112,16 @@

 {defaults, required} = misc

-is_fatal = (err) ->
-    return typeof(err) == 'string' and err.slice(0,5) == 'FATAL'
+cb_fatal = (err, cb) ->
+    if not cb?
+        return
+    if typeof(err) == 'string' and err.slice(0,5) == 'FATAL'
+        # throw in an arbitrary pause to wait for proper connection or
+        # give the backend time to breath
+        setTimeout((->cb(err)), 5000 + Math.random()*5000)
+    else
+        # cb as usual
+        cb(err)

 # We represent synchronized tables by an immutable.js mapping from the primary
 # key to the object.  Since PostgresQL primary keys can be compound (more than
@@ -266,9 +288,6 @@
     _connect: (cb) =>
         dbg = @dbg("connect")
         dbg()
-        if @_fatal
-            cb?('fatal')
-            return
         if @_state == 'closed'
             cb?('closed')
             return
@@ -290,23 +309,11 @@
                 # 2. Now actually do the changefeed query.
                 @_reconnect(cb)
         ], (err) =>
-            if is_fatal(err)
-                # This happens, e.g., when a user is no longer a collaborator on a project, or they are signed out
-                # but still have a bunch of tabs open.  It avoids a huge amount of back and forth traffic between
-                # the client and server.   WORRY: when they sign in, things will not just start working again...
-                # but for now we need to defend ourselves.
-                dbg("FATAL error -- #{err}")
-                @_set_fatal(err)
-                cb?("fatal")
-            else
-                cb?()
+            cb_fatal(err, cb)
         )

     _reconnect: (cb) =>
         dbg = @dbg("_run")
-        if @_fatal
-            cb?('fatal')
-            return
         if @_state == 'closed'
             dbg("closed so don't do anything ever again")
             cb?()
@@ -328,11 +335,6 @@
                 if @_state == 'closed'
                     # already closed so ignore anything else.
                     cb?('closed')
-                    cb = undefined
-                    return
-
-                if @_fatal
-                    cb?('fatal')
                     cb = undefined
                     return

@@ -517,9 +519,6 @@
         return changed

     _save: (cb) =>
-        if @_fatal
-            cb?()
-            return
         if @_state == 'closed'
             cb?("closed")
             return
@@ -528,17 +527,14 @@
         else
             @__is_saving = true
             @__save (err) =>
-                @__is_saving = false
-                if is_fatal(err)
-                    @_set_fatal(err)
-                cb?(err)
+                cb_fatal err, (e) =>
+                    @__is_saving = false
+                    cb?(e)
+

     __save: (cb) =>
         if @_state == 'closed'
             cb?("closed")
-            return
-        if @_fatal
-            cb?()
             return
         # console.log("_save('#{@_table}')")
         # Determine which records have changed and what their new values are.
@@ -640,10 +636,6 @@
         if @_state == 'closed'
             cb?("closed")
             return
-        if @_fatal
-            cb?()
-            return
-
         if @_state != 'connected'
             cb?("not connected")    # do not change this error message; it is assumed elsewhere.
             return
@@ -949,27 +941,7 @@

         return new_val

-    # If we get a fatal error, then we wait a bit.  This could happen due to being signed out,
-    # or thinking we're signed in, but not being signed in (since we *just* are in the process of
-    # being signed out).  It's rare, but there are dozens of tables, so even a 1% chance can
-    # easily happen.
-    _set_fatal: (why) =>
-        if @_fatal
-            return
-        tm = 10000 + Math.random()*20000
-        #console.log("_set_fatal", @_query, tm, why)
-        @_fatal = true
-        @_fatal_interval = setTimeout(@_unset_fatal, tm)
-
-    _unset_fatal: =>
-        #console.log("_unset_fatal", @_query)
-        delete @_fatal
-        delete @_fatal_interval
-
     close: =>
-        if @_fatal_interval
-            clearTimeout(@_fatal_interval)
-            delete @_fatal_interval
         if @_state == 'closed'
             # already closed
             return


better synctable init (error involving first value in special case)

--- src/smc-util/synctable.coffee
+++ src/smc-util/synctable.coffee
@@ -256,7 +256,7 @@
                 #if @_table == 'patches'
                 #    console.log("#{this_id} -- @_id=#{@_id}; query #{@_table}: -- got result of doing query", resp)
                 #    console.log("#{this_id} -- query='#{misc.to_json(@_query)}'")
-                if first_resp
+                if first_resp and resp?.event != 'query_cancel'
                     first_resp = false
                     if @_closed
                         @_connected = false


eliminate terminal debounce focus hack -- just makes things worse

--- src/smc-webapp/console.coffee
+++ src/smc-webapp/console.coffee
@@ -105,8 +105,6 @@
             on_reconnecting: undefined
             on_reconnected : undefined
             set_title      : undefined
-
-        @_focus_hidden_textarea = debounce(@_focus_hidden_textarea, 250)

         @_init_default_settings()


Server: name ssoTokenLogin function

Server: name ssoTokenLogin function

--- servers/lib/server/handlers/api/ssotokenlogin.coffee
+++ servers/lib/server/handlers/api/ssotokenlogin.coffee
@@ -7,7 +7,7 @@

 { setSessionCookie } = require '../../helpers'

-module.exports = (req, res, next) ->
+module.exports = ssoTokenLogin = (req, res, next) ->

   { JUser, JSession, JAccount } = (require '../../bongo').models


* closure_compile_with_sandbox_cache: rename scriptObj -> fun, cause   it's more fun now!

--- src/view.coffee
+++ src/view.coffee
@@ -164,7 +164,7 @@
     @tokenObj               = null # constructed as needed
     @coffeeScript           = null # constructed as needed
     @javaScript             = null # constructed as needed
-    @scriptObj              = null # constructed as needed
+    @fun                    = null # constructed as needed
     @error                  = null # if err, instance of toffeeError class
     if options.cb
       @_prepAsync txt, =>
@@ -184,7 +184,7 @@
       setTimeout ->
         v.toJavaScript()
         setTimeout ->
-          v._toScriptObj()
+          v._toFun()
           v._log "Done async prep of #{if v.fileName? then v.fileName else 'unknown'}. Calling back."
           cb()
         , 0
@@ -211,11 +211,11 @@
     ###
     returns [err, str]
     ###
-    script = @_toScriptObj(ctx)
+    fun = @_toFun(ctx)
     res    = null
     if not @error
       try
-        res = script options
+        res = fun options
       catch e
         @error = new toffeeError @, errorTypes.RUNTIME, e

@@ -252,15 +252,15 @@

     @tokenObj

-  _toScriptObj: (ctx) ->
-    if not @scriptObj?
+  _toFun: (ctx) ->
+    if not @fun?
       txt = @toJavaScript()
       if not @error
         d = Date.now()
         vm.runInContext(txt, ctx)
-        @scriptObj = ctx['_TMPL_']
+        @fun = ctx['_TMPL_']
         @_log "#{@fileName} compiled to scriptObj in #{Date.now()-d}ms"
-    @scriptObj
+    @fun

   toJavaScript: ->
     if not @javaScript?