Don't include percentage to household-dwelling unit popups

--- src/models.coffee
+++ src/models.coffee
@@ -11,6 +11,7 @@
     alphabet                   = require 'cs!app/alphabet'
     accessibility              = require 'cs!app/accessibility'
     {mixOf, pad, withDeferred} = require 'cs!app/base'
+    dataviz                    = require 'cs!app/data-visualization'

     BACKEND_BASE = appSettings.service_map_backend
     LINKEDEVENTS_BASE = appSettings.linkedevents_backend
@@ -462,8 +463,11 @@
                 ((areas, key) ->
                     statistics = response.asuntokunnat[key]
                     statisticsName = key
+                    isHouseholdDwellingUnit = statisticsName == dataviz.getStatisticsLayer('household-dwelling_unit')
                     # Decide comparison value
-                    comparisonKey = if statistics[Object.keys(statistics)[0]].proportion != undefined then 'proportion' else 'value'
+                    comparisonKey = if statistics[Object.keys(statistics)[0]].proportion != undefined && !isHouseholdDwellingUnit
+                    then 'proportion'
+                    else 'value'
                     maxVal = Math.max(Object.keys(statistics).map( (id) ->
                         if isNaN(+statistics[id][comparisonKey]) then 0 else +statistics[id][comparisonKey]
                     )...)
@@ -471,10 +475,14 @@
                         statistic = statistics[id]
                         currentStatistic = {}
                         value = if isNaN(+statistic[comparisonKey]) then 0 else statistic[comparisonKey]
+                        # Filter out proportion for average household-dwelling unit sizes
+                        proportion = if isHouseholdDwellingUnit
+                        then undefined
+                        else statistic.proportion
                         currentStatistic[statisticsName] =
                             value: "" + statistic.value
                             normalized: value / maxVal
-                            proportion: statistic.proportion
+                            proportion: proportion
                         areas[id] = Object.assign({}, areas[id], currentStatistic)
                     )
                     areas


Remove unused method.

Remove unused method.

--- src/models.coffee
+++ src/models.coffee
@@ -508,14 +508,6 @@
                     console.log "Unknown search result type '#{type}'"
                     return new Backbone.Model(attrs, options)

-        autocomplete: (input, options) ->
-            opts = _.extend {}, options
-            opts.data =
-                input: input
-                language: p13n.getLanguage()
-            opts.reset = true
-            @fetch opts
-
         search: (query, options) ->
             @query = query
             opts = _.extend {}, options


fix bug.

fix bug.

--- lib/request/handle/get/index.coffee
+++ lib/request/handle/get/index.coffee
@@ -4,7 +4,7 @@
       _id: req.params.id
     , (err, entity) ->
         return next(err)  if err
-        next(new Error("Failed to find #{url} [#{req.params.id}]"))  unless entity
+        next(new Error("Failed to find [#{req.params.id}]"))  unless entity
         res.jsonp(entity)
         cb(entity)  if cb


Hide the initial element (reference + marker) in the iteration binding.

--- src/rivets.coffee
+++ src/rivets.coffee
@@ -192,6 +192,8 @@

 # Returns an iteration binding routine for the specified collection.
 iterationBinding = (name) -> (el, collection, binding) ->
+  Rivets.routines.hide el, true
+
   for iteration in binding.iterated
     iteration.view.unbind()
     iteration.el.parentNode.removeChild iteration.el
@@ -203,6 +205,7 @@
     data[name] = item

     itemEl = el.cloneNode true
+    Rivets.routines.show itemEl, true
     el.parentNode.insertBefore itemEl, el

     binding.iterated.push


runner: Don't complain about known unused runtime:packet events

--- src/runner.coffee
+++ src/runner.coffee
@@ -71,6 +71,8 @@
       # FIXME: also check # and d.graph == @currentGraphId
       if msg.command == 'packet' and d.event == 'data'
         onReceived d.port, d.payload
+      else if msg.command == 'packet' and ['begingroup', 'endgroup', 'connect', 'disconnect'].indexOf(d.event) != -1
+        # ignored
       else
         debug 'unknown runtime message', msg
     @client.on 'runtime', checkPacket


Parametrize color scheme and cell height

--- src/sample.coffee
+++ src/sample.coffee
@@ -1,23 +1,11 @@
-someVar = 1
 d3 = window.d3
 _ = window._

 constants =
-  WIDTH_TO_HEIGHT_RATIO : 0.4,
-  POS_FLAME_RGB : [ 254, 86, 67 ],
-  NEG_FLAME_RGB : [ 0, 200, 0 ],
-  EQ_FLAME_RGB : [ 198, 198, 143 ],
-  FLAME_DIFFERENTIAL : 40.0,
-  FLAME_RGB : [ 200, 125, 50 ],
   TOOLTIP_BORDER_COLOR_PLUS : '#FFB2B2',
   TOOLTIP_BORDER_COLOR_MINUS : '#99D699',
   TOOLTIP_BORDER_COLOD_DEFAULT : '#DDD',
-  MIN_LABEL_WIDTH : 40,
-  RX : 2,
-  RY : 2,
-  TOOLTIP_OFFSET: 3,
-  EM_OF_FLAME_BAR: 0.5,
-  EM_OF_LABEL_HEIGHT: ".25em"
+  TOOLTIP_OFFSET: 3

 convert = (rawData) ->
   value = 0
@@ -53,17 +41,6 @@

   node

-rgbToHex = (red, green, blue) ->
-  '#' + ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).substr(1)
-
-randomizeColor = (rgb) ->
-    # generates a random integer between -FLAME_DIFF / 2 and FLAME_DIFF / 2
-    offset = (color) ->
-      color + Math.round((Math.random() * constants.FLAME_DIFFERENTIAL) - (constants.FLAME_DIFFERENTIAL * 0.5))
-
-    "rgb(#{offset(rgb[0])}, #{offset(rgb[1])}, #{offset(rgb[2])})"
-
-maxY = 0
 maxDepth = (node) ->
   return 0 if not node
   return 1 if not node.children
@@ -72,23 +49,37 @@
   node.children.forEach (child) ->
     depth = maxDepth(child)
     max = depth if depth > max
-    maxY = child.y if child.y > maxY

   return max + 1
+
+
+getLastTwoTokens = (str) ->
+  tokens = str.split(".")
+  tokens.slice(tokens.length - 2).join(".")

 d3.flameGraph = ->

   class FlameGraph
-    constructor: (@containerId) ->
-      @_generateAccessors(['width', 'height'])
+    constructor: () ->
+      @_generateAccessors([
+        'width',
+        'height',
+        'cellHeight',
+        'containerId',
+        'colorScheme'])
       @_allData = []

     data: (data) ->
       return @_data if not data
       @_allData.push(data)

+      @_data = d3.layout.partition()
+        .sort((a,b) -> a.name.localeCompare(b.name))
+        .nodes(data)
+      @
+
+    breadcrumbs: () ->
       breadcrumbData = @_allData.map((prevData, idx) -> { name: prevData.name, value: idx })
-      console.log(breadcrumbData)
       breadcrumbs = d3.select('.breadcrumb')
         .selectAll('li')
         .data(breadcrumbData)
@@ -96,62 +87,46 @@
       breadcrumbs.enter()
         .append('li')
           .append('a')
-          .text((d) -> "#{d.name}")
+          .text((d) -> getLastTwoTokens(d.name))
           .on 'click', (breadcrumb) =>
             idx = breadcrumb.value
             displayed = @_allData[idx]
             @_allData = @_allData.slice(0, idx)
-            @data(displayed)
-              .render()
-              .interactivity()
+            @data(displayed).render()

       breadcrumbs.exit().remove()
-
-
-      @_data = d3.layout.partition()
-        .sort((a,b) -> a.name.localeCompare(b.name))
-        .nodes(data)
       @

     getLabelText: (label, dx) ->
       return "" if not label
-      shortLabel = label;
+      shortLabel = getLastTwoTokens(label)
+      maxLength = Math.round(@x(dx) / 4)
+      return shortLabel.substr(0, maxLength)

-      if (shortLabel.indexOf(".") != -1)
-        delimiter = "."
-        tokens = label.split(delimiter)
-        length = tokens.length
-        shortLabel = [tokens[length - 2], tokens[length - 1]].join(delimiter)
-
-        ratio = 4
-        maxLength = Math.round(@x(dx) / ratio)
-        return shortLabel.substr(0, maxLength)
+    color: (d) -> @colorScheme()[Math.floor(Math.random() * @colorScheme().length)]

     render: () ->
       # compute height dynamically so the fixed unit is the height of a cell
       console.time('rendering')

-      d3.select(@containerId)
+      d3.select(@containerId())
         .select('svg').remove()
-      @container = d3.select(@containerId)
+
+      @container = d3.select(@containerId())
         .append('svg')
           .attr('width', @width())
           .attr('height', @height())

-      @container.selectAll('.node', '.label').remove()
-
-      @cellHeight  = 10
-      @maxCells    = Math.floor(@height() / @cellHeight)
+      @maxCells    = Math.floor(@height() / @cellHeight())

       depth = maxDepth(@data()[0])
       @x = d3.scale.linear()
         .domain([0, d3.max(@data(), (d) -> d.x + d.dx)])
         .range([0, @width()])
       @y = d3.scale.quantize()
-        .domain([0, maxY])
-        .range(d3.range(depth, 0, -1)
-          .map((cell) =>  (cell  - depth - 1 + @maxCells) * @cellHeight))
-
+        .domain([d3.max(@data(), (d) -> d.y), 0])
+        .range(d3.range(depth)
+          .map((cell) =>  (cell  - depth + @maxCells) * @cellHeight()))

       @container
         .selectAll('.node')
@@ -161,40 +136,32 @@
           .append('rect')
             .attr('class', 'node')
             .attr 'width', (d) => @x(d.dx)
-            .attr('height', (d) => @cellHeight - 2)
+            .attr('height', (d) => @cellHeight() - 2)
             .attr('x', (d) => @x(d.x))
             .attr('y', (d) => @y(d.y))
-            # .attr('rx', constants.RX)
-            # .attr('ry', constants.RY)
-            .attr('stroke', (d) -> randomizeColor(constants.FLAME_RGB))
-            .attr('fill', (d) -> if d.color then d.color else randomizeColor(constants.FLAME_RGB))
+            .attr('stroke', "#bd0026")
+            .attr('fill', (d) => console.log(@color(d)); @color(d))
             .attr('fill-opacity', '0.8')

       @container
         .selectAll('.label')
-        .data(@data().filter((d) => d.name and @x(d.dx) > constants.MIN_LABEL_WIDTH))
+        .data(@data().filter((d) => d.name and @x(d.dx) > 40))
         .enter()
           .append('text')
             .attr('class', 'label')
             .attr('text-anchor', 'middle')
-            .attr('dy', constants.EM_OF_LABEL_HEIGHT)
+            .attr('dy', '.25em')
             .attr('x', (d) => @x(d.x) + @x(d.dx) / 2)
-            .attr('y', (d) => @y(d.y) + @cellHeight / 2)
+            .attr('y', (d) => @y(d.y) + @cellHeight() / 2)
             .text((d) => @getLabelText(d.name, d.dx))
-          # .on("mouseover", (d) -> @onMouseover(d))
-          # .on("mousemove", (d) -> @onMousemove())
-          # .on("mouseout", (d) -> @onMouseout())
-          # .on("click", (d) -> if (!d3.event.defaultPrevented) then @onSetRootCallback(d.location))

       console.timeEnd('rendering')
       console.log("Rendered #{@container.selectAll('.node')[0].length} elements")
-      return @
+      return @breadcrumbs().interactivity()

     interactivity: () ->
       console.time('interactivity')
-      clickHandler = (d) =>
-          console.log(d.y, @y(d.y))
-          @data(d).render().interactivity()
+      clickHandler = (d) => @data(d).render()

       @container
         .selectAll('.node')
@@ -203,7 +170,6 @@
       @container
         .selectAll('.label')
         .on 'click', clickHandler
-
       console.timeEnd('interactivity')
       @

@@ -215,10 +181,13 @@
             @["_#{accessor}"] = newValue
             return @

-  return new FlameGraph('#d3-flame-graph').width(1200).height(600)
+  return new FlameGraph()

 d3.json "data/profile-large.json", (err, data) ->
   window.flameGraph = d3.flameGraph()
-  flameGraph.data(convert(data.profile))
-    .render()
-    .interactivity()
+  flameGraph
+    .containerId('#d3-flame-graph')
+    .width(1200).height(600).cellHeight(10)
+    .data(convert(data.profile))
+    .colorScheme(["#ffffcc","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#bd0026"])
+    .render()


chore(coffeelint): Fix linter error

chore(coffeelint): Fix linter error

--- src/script.coffee
+++ src/script.coffee
@@ -4,11 +4,13 @@
 # Dependencies:
 #   "cne": "^1.0.0"
 #
+# coffeelint: disable=max_line_length
 # Commands:
 #   hubot cne obtener <combustible> - Obtiene la estación de servicio con el precio mas barato
 #   hubot cne obtener <combustible> en <comuna> - Obtiene la estación de servicio con el precio mas barato en una determinada comuna
 #   hubot cne listar combustibles - Obtiene el listado de combustibles disponibles
 #   hubot cne listar comunas - Obtiene el listado de comunas disponibles
+# coffeelint: enable=max_line_length
 #
 # Author:
 #   lgaticaq


allow proxy to work with https sites

allow proxy to work with https sites

--- src/server.coffee
+++ src/server.coffee
@@ -74,7 +74,7 @@
   for route, value of options.proxy
     display = "#{value.host}:#{value.port or 80}#{value.path}"
     log.info "> Proxy requests <yellow>#{route}</yellow> to <yellow>#{display}</yellow>"
-    backend.use(route, createRoutingProxy(value))
+    backend.use(route, createRoutingProxy(value, "#{options.host}:#{options.port}"))

   # return the custom middleware for connect to use
   return (req, res, next) ->
@@ -108,31 +108,42 @@
     else
       next()

-createRoutingProxy = (options) ->
-  proxy = new httpProxy.RoutingProxy()
+createRoutingProxy = (options, returnHost) ->
+  # handle https differently
+  if options.https
+    routingProxyOptions = {target: {https:true}}
+    defaultPort = 443
+  else
+    routingProxyOptions = {}
+    defaultPort = 80
+  # create proxy
+  proxy = new httpProxy.RoutingProxy(routingProxyOptions)
   # set options
   options.path or= ""
-  options.port or= 80
+  options.port or= defaultPort
   options.patchRedirect or= true
   # handle redirects
   if options.patchRedirect
     proxy.once "start", (req, res) ->
       # get the requesting hostname and port
-      returnHost = req.headers.host
       patchServerResponseForRedirects(options.host, returnHost)
   # return function used by connect to access proxy
   return (req, res, next) ->
     req.url = "#{options.path}#{req.url}"
+    req.headers.host = options.host
+    console.log req.url, req.headers.host
     proxy.proxyRequest(req, res, options)

 patchServerResponseForRedirects = (fromHost, returnHost) ->
   writeHead = http.ServerResponse.prototype.writeHead
   http.ServerResponse.prototype.writeHead = (status) ->
+    headers =  @_headers
     if status in [301,302]
-      headers =  @_headers
-      oldLocation = new RegExp(":\/\/#{fromHost}:?[0-9]*")
+      console.log 'before headers', headers.location
+      oldLocation = new RegExp("s?:\/\/#{fromHost}:?[0-9]*")
       newLocation = "://#{returnHost}"
       headers.location = headers.location.replace(oldLocation,newLocation)
+      console.log 'after headers', headers.location
     return writeHead.apply(@, arguments)

 # export the public functions


KodingAppsController: Much better script unloader

--- client/Main/kodingappscontroller.coffee
+++ client/Main/kodingappscontroller.coffee
@@ -36,22 +36,20 @@
   # Please make sure about your changes on it.
   @putAppScript = (app, callback = noop)->

-    @unloadAppScript app
-
-    identifier = app.identifier
-
     if app.style
-      @appendScriptElement 'style',  { url:app.style, identifier, callback }
+      @appendScriptElement 'style',  \
+        { url:app.style, identifier:app.identifier, callback }, yes

     if app.script
-      @appendScriptElement 'script', { url:app.script, identifier, callback }
+      @appendScriptElement 'script', \
+        { url:app.script, identifier:app.identifier, callback }, yes

   @unloadAppScript = (app, callback = noop)->

     identifier = app.identifier.replace /\./g, '_'

-    $("head .internal-style-#{identifier}").remove()
-    $("head .internal-script-#{identifier}").remove()
+    @destroyScriptElement "style", identifier
+    @destroyScriptElement "script", identifier

     KD.utils.defer -> callback()

@@ -108,7 +106,7 @@
           style      : "modal-cancel"
           callback   : -> modal.destroy()

-  @appendScriptElement = (type, {identifier, url, callback})->
+  @appendScriptElement = (type, {identifier, url, callback}, force)->

     identifier = identifier.replace /\./g, '_'
     domId      = "internal-#{type}-#{identifier}"
@@ -119,9 +117,11 @@
     if vmName

       file = FSHelper.createFileFromPath url
-      file.fetchContents (err, partial)->
+      file.fetchContents (err, partial)=>
         return  if err
         obj = new KDCustomHTMLView {domId, tagName, partial}
+
+        @destroyScriptElement type, identifier  if force

         if type is 'script'
           obj.once 'viewAppended', -> callback null
@@ -144,12 +144,16 @@
           type     : "text/javascript"
           src      : url
         bind       = "load"
-        load       = -> callback null
-
+        load       = -> callback? null
+
+      @destroyScriptElement type, identifier  if force

       document.head.appendChild (new KDCustomHTMLView {
         domId, tagName, attributes, bind, load
       }).getElement()
+
+  @destroyScriptElement = (type, identifier)->
+    (document.getElementById "internal-#{type}-#{identifier}")?.remove()

   # #
   # MAKE NEW APP


Client: Activity: Feed:  Updated selectedChannelThread to set messages by query

--- client/activity/lib/flux/getters.coffee
+++ client/activity/lib/flux/getters.coffee
@@ -231,8 +231,12 @@
 selectedChannelThread = [
   channelThreads
   selectedChannel
+  MessageLikersStore
+  allUsers
   selectedChannelPopularMessages
-  (threads, channel, popularMessages) ->
+  FilteredChannelMessagesIdsStore
+  channelMessagesSearchQuery
+  (threads, channel, likers, users, popularMessages, filteredIds, query) ->
     return null  unless channel
     thread = threads.get channel.get('id')
     thread = thread.set 'channel', channel
@@ -240,6 +244,17 @@
     if thread.getIn(['flags', 'resultListState']) is ResultStates.LIKED
       popularMessages = popularMessages or immutable.Map()
       thread = thread.set 'messages', popularMessages
+
+    if query
+      messages = thread.get 'messages'
+      messages = filteredIds.map (id) -> messages.get id
+      thread   = thread.set 'messages', messages
+
+    thread = thread.update 'messages', (messages) ->
+      messages.map (msg) ->
+        msg.update 'body', (body) ->
+          # don't show channel name on post body.
+          body.replace(///\##{channel.get('name')}($|\s)///, '').trim()

     return thread
 ]


defend against lack of exposed ports

defend against lack of exposed ports

--- client/views/instances/instances.coffee
+++ client/views/instances/instances.coffee
@@ -45,7 +45,7 @@

 findWebPort = (service) ->
   p = 80
-  service?.ports.split(' ').forEach (port) ->
+  service?.ports?.split(' ').forEach (port) ->
     if port in HTTPS_PORTS.concat(HTTP_PORTS) then p = port
   p


Adds speed ratio

Adds speed ratio

--- coffee/presenters/home_presenter.coffee
+++ coffee/presenters/home_presenter.coffee
@@ -3,7 +3,10 @@
   _initCar: () ->
     c = @grid.getSnap().image('imgs/car.png', 0, 0, 20, 20)
     c.addClass('js-car')
-    @car = new Car('.js-car', @grid, CONFIG.carSpeed)
+    speed = CONFIG.carSpeed
+    ratio = Math.max(@grid.getBlockWidth(), @grid.getBlockHeight()) / 800
+    speed *= ratio if ratio > 1
+    @car = new Car('.js-car', @grid, speed)

   _initRideEngine: () ->
     @rideEngine = new RideEngine(@grid, @car)


Add in a null check

Add in a null check

--- services/web/public/coffee/ide/editor/directives/aceEditor/track-changes/TrackChangesManager.coffee
+++ services/web/public/coffee/ide/editor/directives/aceEditor/track-changes/TrackChangesManager.coffee
@@ -399,11 +399,11 @@
 			session = @editor.getSession()
 			markers = session.getMarkers()
 			{background_marker_id, callout_marker_id} = @changeIdToMarkerIdMap[change_id]
-			if background_marker_id?
+			if background_marker_id? and markers[background_marker_id]?
 				background_marker = markers[background_marker_id]
 				background_marker.range.start = start
 				background_marker.range.end = end
-			if callout_marker_id?
+			if callout_marker_id? and markers[callout_marker_id]?
 				callout_marker = markers[callout_marker_id]
 				callout_marker.range.start = start
 				callout_marker.range.end = start


some bugfixes

some bugfixes

--- grammars/stata.cson
+++ grammars/stata.cson
@@ -366,7 +366,7 @@
           }
           {
             'comment': 'color options with parentheses'
-            'begin': '([\\S]+)(\\()'
+            'begin': '([^\\s\\[\\]]+)(\\()'
             'beginCaptures':
               '1':
                 'patterns': [
@@ -951,17 +951,6 @@
         'name': 'keyword.macro.extendedfcn.stata'
       }
       {
-        'begin': '\\b(display|displa|displ|disp|dis|di)\\b'
-        'end': '(?=//|\\n)'
-        'beginCaptures':
-          '0': 'keyword.macro.extendedfcn.stata'
-        'patterns': [
-          {
-            'include': '$self'
-          }
-        ]
-      }
-      {
         'match': '\\b(list)\\b'
         'name': 'keyword.macro.extendedfcn.stata'
       }
@@ -1056,6 +1045,9 @@
       }
       {
         'include': '#macro-global'
+      }
+      {
+        'include': '$self'
       }
     ]
   'macro-local-escaped':


[EVENTRIC-37] Since every store needs his own store instance we cant return a singleton

--- src/mongodb_store.coffee
+++ src/mongodb_store.coffee
@@ -75,4 +75,4 @@
       callback null, result

-module.exports = new MongoDBStore+module.exports = MongoDBStore


Added pagination for team members endpoint

--- src/octonode/team.coffee
+++ src/octonode/team.coffee
@@ -20,8 +20,10 @@

   # Get a teams's members
   # '/teams/37/members' GET
-  members: (cb) ->
-    @client.get "/teams/#{@id}/members", (err, s, b, h)  ->
+  # - page or query object, optional - params[0]
+  # - per_page, optional             - params[1]
+  members: (params..., cb) ->
+    @client.get "/teams/#{@id}/members", params..., (err, s, b, h)  ->
       return cb(err) if err
       if s isnt 200 then cb(new Error('Team members error')) else cb null, b, h


remove external nodes from paste

remove external nodes from paste

--- src/paste-manager.coffee
+++ src/paste-manager.coffee
@@ -1,11 +1,8 @@
 class TandemPasteManager
   constructor: (@editor) ->
-    this.initListeners()
-
-  initListeners: ->
-    pasteDiv = @editor.doc.root.ownerDocument.createElement('div')
-    pasteDiv.id = 'paste-container'
-    pasteDiv.setAttribute('contenteditable', true)
+    @container = @editor.doc.root.ownerDocument.createElement('div')
+    @container.id = 'paste-container'
+    @container.setAttribute('contenteditable', true)
     @editor.renderer.addStyles({
       '#paste-container': {
         'left': '-10000px'
@@ -13,16 +10,24 @@
         'top': '50%'
       }
     })
-    @editor.doc.root.parentNode.appendChild(pasteDiv)
+    @editor.doc.root.parentNode.appendChild(@container)
+    this.initListeners()
+
+  initListeners: ->
     @editor.doc.root.addEventListener('paste', =>
       @editor.selection.update()
       savedSelection = @editor.selection.save()
-      pasteDiv.focus()
+      @container.innerHTML = ""
+      @container.focus()
       _.defer( =>
         if savedSelection
           @editor.doc.root.focus()
           @editor.selection.restore(savedSelection)
-          console.log pasteDiv
+          extNodes = _.clone(@container.querySelectorAll(".#{Tandem.Constants.SPECIAL_CLASSES.EXTERNAL}"))
+          _.each(extNodes, (node) ->
+            node.parentNode.removeChild(node) if node.parentNode?
+          )
+          console.log @container.innerHTML
       )
     )


change factor by sqrt

change factor by sqrt

--- graphics/003-colorful-wahlque/viewer.coffee
+++ graphics/003-colorful-wahlque/viewer.coffee
@@ -23,6 +23,8 @@
         g = Math.floor((r + b) / 1.5)
         g = 255 if g > 255

+        factor = Math.sqrt(factor)
+        factor = Math.sqrt(factor)
         r = Math.floor(r * factor)
         g = Math.floor(g * factor)
         b = Math.floor(b * factor)


sprite docs

sprite docs

--- src/sprite.coffee
+++ src/sprite.coffee
@@ -1,3 +1,8 @@
+###*
+@name Sprite
+@constructor
+###
+
 ( ->
   LoaderProxy = ->
     draw: $.noop
@@ -68,8 +73,39 @@
       # Treat name as URL
       return window.Sprite.fromURL(name, callback)

+  ###*
+  A constant sprite that draws nothing.
+
+  @name EMPTY
+  @fieldOf Sprite
+  @type Sprite
+  ###
   window.Sprite.EMPTY = window.Sprite.NONE = LoaderProxy()
+
+  ###*
+  Loads a sprite with the given pixie id.
+
+  @name fromPixieId
+  @methodOf Sprite
+
+  @param id
+  @param [callback]
+
+  @type Sprite
+  ###
   window.Sprite.fromPixieId = fromPixieId
+
+  ###*
+  Loads a sprite from a given url.
+
+  @name fromURL
+  @methodOf Sprite
+
+  @param {String} url
+  @param [callback]
+
+  @type Sprite
+  ###
   window.Sprite.fromURL = Sprite.load

 )()


fixing require typo in admin.coffee

fixing require typo in admin.coffee

--- src/portals/admin.coffee
+++ src/portals/admin.coffee
@@ -1,4 +1,4 @@
-Contract = require('../models/Contract').Contract
+Contract = require('../models/contract').Contract
 CLI = require('../cli').CLI

 exports.Admin = class Admin


Nesting tests a little more in favor of organization

--- tests/www/tests/functional/routing.coffee
+++ tests/www/tests/functional/routing.coffee
@@ -5,149 +5,151 @@
 quit = require '../../utils/quit'

 exports.test = ( browser, browser_conf, base_url, timeout, mark_as_passed )->
+
   describe '★  testing routes', ->
     describe 'using ' + browser_conf.name, ->

-
       # ------------------------------------------------------------------------
       # menu
-      it 'wait until menu is visible', (done)->
-        browser.init browser_conf, ->
-          browser.get base_url, ->
-            browser.waitForElementByClassName 'menu', timeout, ->
-              browser.elementByClassName 'menu', (err, el)->
-                should.not.exist err
-                should.exist el
-                done null
-                console.log '\t---------------- /simple'.grey
+      describe 'menu must to exist', ->
+        it 'wait until menu is visible', (done)->
+          browser.init browser_conf, ->
+            browser.get base_url, ->
+              browser.waitForElementByClassName 'menu', timeout, ->
+                browser.elementByClassName 'menu', (err, el)->
+                  should.not.exist err
+                  should.exist el
+                  do done

       # ------------------------------------------------------------------------
       # /simple link
-      it 'click /simple link and check if redirect begun', (done)->
-        browser.elementById 'routing-simple', (err, el)->
-          browser.clickElement el, ->
-            browser.eval 'window.location.pathname', (err, pathname)->
-              should.not.exist err
-              should.exist pathname
-              pathname.should.equal '/routing/simple'
-              done null
+      describe 'simple route', ->

-      it 'wait until page is rendered', (done)->
-        browser.waitForCondition page_is_rendered, timeout, 30, (err, res)->
-          should.not.exist err
-          res.should.be.true
-          done null
+        it 'click /simple link and check if redirect begun', (done)->
+          browser.elementById 'routing-simple', (err, el)->
+            browser.clickElement el, ->
+              browser.eval 'window.location.pathname', (err, pathname)->
+                should.not.exist err
+                should.exist pathname
+                pathname.should.equal '/routing/simple'
+                do done

-      it 'check if `simple-container` is available', (done)->
-        browser.elementById 'simple-container', (err, el)->
-          should.not.exist err
-          should.exist el
-          done null
-          console.log '\t---------------- /deep'.grey
+        it 'wait until page is rendered', (done)->
+          browser.waitForCondition page_is_rendered, timeout, 30, (err, res)->
+            should.not.exist err
+            res.should.be.true
+            do done
+
+        it 'check if `simple-container` is available', (done)->
+          browser.elementById 'simple-container', (err, el)->
+            should.not.exist err
+            should.exist el
+            do done

       # ------------------------------------------------------------------------
       # /deep link
-      it 'click /deep link and check if redirect begun', (done)->
-        browser.elementById 'routing-deep', (err, el)->
-          el.click (err)->
+      describe 'deep route', ->
+        it 'click /deep link and check if redirect begun', (done)->
+          browser.elementById 'routing-deep', (err, el)->
+            el.click (err)->
+              should.not.exist err
+              browser.eval 'window.location.pathname', (err, pathname)->
+                should.exist pathname
+                pathname.should.equal '/routing/deep'
+                do done
+
+        it 'wait until page is rendered', (done)->
+          browser.waitForCondition page_is_rendered, timeout, 30, (err, res)->
             should.not.exist err
-            browser.eval 'window.location.pathname', (err, pathname)->
-              should.exist pathname
-              pathname.should.equal '/routing/deep'
-              done null
+            res.should.be.true
+            do done

-      it 'wait until page is rendered', (done)->
-        browser.waitForCondition page_is_rendered, timeout, 30, (err, res)->
-          should.not.exist err
-          res.should.be.true
-          done null
+        it 'check if `deep-param` is undefined', (done)->
+          browser.elementById 'deep-param', (err, el)->
+            should.not.exist err
+            should.exist el
+            el.text (err, text)->
+              should.exist text
+              text.should.equal 'undefined'
+              do done

-      it 'check if `deep-param` is undefined', (done)->
-        browser.elementById 'deep-param', (err, el)->
-          should.not.exist err
-          should.exist el
-          el.text (err, text)->
-            should.exist text
-            text.should.equal 'undefined'
-            done null
-
-      it 'check if `deep-container` is available', (done)->
-        browser.elementById 'deep-container', (err, el)->
-          should.not.exist err
-          should.exist el
-          done null
-          console.log '\t---------------- /dynamic'.grey
+        it 'check if `deep-container` is available', (done)->
+          browser.elementById 'deep-container', (err, el)->
+            should.not.exist err
+            should.exist el
+            do done

       # ------------------------------------------------------------------------
       # /dynamic link
-      it 'click /dynamic link and check if redirect begun', (done)->
-        browser.elementById 'routing-dynamic', (err, el)->
-          el.click (err)->
+      describe 'dyanmic route without params', ->
+        it 'click /dynamic link and check if redirect begun', (done)->
+          browser.elementById 'routing-dynamic', (err, el)->
+            el.click (err)->
+              should.not.exist err
+              browser.eval 'window.location.pathname', (err, pathname)->
+                should.exist pathname
+                pathname.should.equal '/routing/dynamic'
+                do done
+
+        it 'wait until page is rendered', (done)->
+          browser.waitForCondition page_is_rendered, timeout, 30, (err, res)->
             should.not.exist err
-            browser.eval 'window.location.pathname', (err, pathname)->
-              should.exist pathname
-              pathname.should.equal '/routing/dynamic'
-              done null
-
-      it 'wait until page is rendered', (done)->
-        browser.waitForCondition page_is_rendered, timeout, 30, (err, res)->
-          should.not.exist err
-          res.should.be.true
-          done null
+            res.should.be.true
+            do done

-      it 'check /deep route\'s state to assure it remains untouched' , (done)->
-        browser.eval '$("#deep-param").data("initial");', (err, status)->
-          should.not.exist err
-          status.should.be.true
-          done null
+        it 'check /deep route\'s state to assure it remains untouched' , (done)->
+          browser.eval '$("#deep-param").data("initial");', (err, status)->
+            should.not.exist err
+            status.should.be.true
+            do done

-      it 'check if `dynamic-param` is undefined', (done)->
-        browser.elementById 'dynamic-param', (err, el)->
-          should.not.exist err
-          should.exist el
-          el.text (err, text)->
-            should.exist text
-            text.should.equal 'undefined'
-            done null
-            console.log '\t---------------- /dynamic/theoricus'.grey
+        it 'check if `dynamic-param` is undefined', (done)->
+          browser.elementById 'dynamic-param', (err, el)->
+            should.not.exist err
+            should.exist el
+            el.text (err, text)->
+              should.exist text
+              text.should.equal 'undefined'
+              do done

       # ------------------------------------------------------------------------
       # /dynamic/theoricus link
-      it 'click /dynamic/theoricus link and check if redirect begun', (done)->
-        browser.elementById 'routing-dynamic-theoricus', (err, el)->
-          el.click (err)->
+      describe 'dynamic route with params', ->
+        it 'click /dynamic/theoricus link and check if redirect begun', (done)->
+          browser.elementById 'routing-dynamic-theoricus', (err, el)->
+            el.click (err)->
+              should.not.exist err
+              browser.eval 'window.location.pathname', (err, pathname)->
+                should.exist pathname
+                pathname.should.equal '/routing/dynamic/theoricus'
+                do done
+
+        it 'wait until page is rendered', (done)->
+          browser.waitForCondition page_is_rendered, timeout, 30, (err, res)->
             should.not.exist err
-            browser.eval 'window.location.pathname', (err, pathname)->
-              should.exist pathname
-              pathname.should.equal '/routing/dynamic/theoricus'
-              done null
+            res.should.be.true
+            do done

-      it 'wait until page is rendered', (done)->
-        browser.waitForCondition page_is_rendered, timeout, 30, (err, res)->
-          should.not.exist err
-          res.should.be.true
-          done null
+        it 'check if `deep-param` is theoricus', (done)->
+          browser.elementById 'deep-param', (err, el)->
+            should.not.exist err
+            should.exist el
+            el.text (err, text)->
+              should.exist text
+              text.should.equal 'theoricus'
+              do done

-      it 'check if `deep-param` is theoricus', (done)->
-        browser.elementById 'deep-param', (err, el)->
-          should.not.exist err
-          should.exist el
-          el.text (err, text)->
-            should.exist text
-            text.should.equal 'theoricus'
-            done null
+        it 'check /deep route\'s state to assure it has changed' , (done)->
+          browser.eval '$("#deep-param").data("initial");', (err, status)->
+            should.not.exist err
+            should.not.equal true
+            do done

-      it 'check /deep route\'s state to assure it has changed' , (done)->
-        browser.eval '$("#deep-param").data("initial");', (err, status)->
-          should.not.exist err
-          should.not.equal true
-          done null
-
-      it 'check if `dynamic-param` is theoricus', (done)->
-        browser.elementById 'dynamic-param', (err, el)->
-          should.not.exist err
-          should.exist el
-          el.text (err, text)->
-            should.exist text
-            text.should.equal 'theoricus'
-            quit browser, mark_as_passed, done+        it 'check if `dynamic-param` is theoricus', (done)->
+          browser.elementById 'dynamic-param', (err, el)->
+            should.not.exist err
+            should.exist el
+            el.text (err, text)->
+              should.exist text
+              text.should.equal 'theoricus'
+              quit browser, mark_as_passed, done


[master] bug fix

[master] bug fix

--- get_comment_count.coffee
+++ get_comment_count.coffee
@@ -81,7 +81,7 @@
         # Process next page
         redis.hset 'progress', symbol, page
         if page < maxPageNum
-          parseSinglePage symbol, page + 1, lastEntryDate, executionDate, callback
+          parseSinglePage symbol, page + 1, lastEntryDate, executionDate, redis, callback
         else
           callback()


fix the path being passed into modulerize() with the multi-platform friendly path.join()

--- src/stitch.coffee
+++ src/stitch.coffee
@@ -28,7 +28,7 @@
 class Module
   constructor: (@filename, @parent) ->
     @ext = npath.extname(@filename).slice(1)
-    @id  = modulerize(@filename.replace(@parent + '/', ''))
+    @id  = modulerize(@filename.replace(npath.join(@parent, '/'), ''))

   compile: ->
     compilers[@ext](@filename)


Bug fix

Bug fix

--- config/karma/run.coffee
+++ config/karma/run.coffee
@@ -2,7 +2,7 @@
 _ = require 'underscore'
 Queue = require 'queue-async'
 Wrench = require 'wrench'
-karma = require 'karma').server
+karma = (require 'karma').server
 gutil = require 'gulp-util'
 generate = require './generate'


Remove leftover env file

Remove leftover env file

--- SingularityUI/env_prod.coffee
+++ SingularityUI/env_prod.coffee
@@ -1,3 +0,0 @@
-module.exports =
-    env: 'prod'
-    SINGULARITY_BASE: ''


Replace old MapServer with new, working version

--- client/src/views/map_view.coffee
+++ client/src/views/map_view.coffee
@@ -58,7 +58,7 @@
   renderDataToMap: ->
     serviceName = @visualisation.get('indicator').get('indicatorDefinition').serviceName
     serviceName ||= "NRT_AD_ProtectedArea"
-    L.esri.dynamicMapLayer("http://196.218.36.14/ka/rest/services/#{serviceName}/MapServer",
+    L.esri.dynamicMapLayer("http://nrtstest.ead.ae/ka/rest/services/#{serviceName}/MapServer",
       opacity: 0.6
     ).addTo(@map)


Properly load existing plans that have already been bought

--- js/inner.coffee
+++ js/inner.coffee
@@ -409,6 +409,7 @@
 class Billing extends Obj
   observables: =>
     teamMembers: {} # github data; map of org->[users]
+    existingPlans: {}
     collaborators: []

     availablePlans: [] # the list of plans that a user can choose
@@ -488,8 +489,11 @@
       write: (value) =>
         @selectedOrganization(value)
         if value
-          cs = for v in @teamMembers()[value]
-            {login: v, plan: ko.observable(@selectedPlan())}
+          cs = for login in @teamMembers()[value]
+            plan = ko.observable @selectedPlan()
+            existing = @existingPlans()[login]
+            plan(@availablePlans()[existing]) if existing
+            {login: login, plan: plan}
           @collaborators(cs)
           SammyApp.setLocation "/account/plans/users"

@@ -569,6 +573,7 @@
       @cardInfo(data.card_info)
       @oldTotal(data.amount / 100)
       @payer(data.payer)
+      @existingPlans(data.team_plans)

       # we want the first plan/org, but iteration is the only way to get that from an object
       for k,v of data.orgs


codeblocks text content

codeblocks text content

--- js/nodes.coffee
+++ js/nodes.coffee
@@ -1,17 +1,6 @@
 Mod.require 'Weya.Base',
  'Weya'
  (Base, Weya) ->
-
-  ENTITY_MAP =
-    "&": "&"
-    "<": "<"
-    ">": ">"
-    '"': '"'
-    "'": '''
-    "/": '/'
-
-  escapeHtml = (string) ->
-   String(string).replace /[&<>"'\/]/g, (s) -> ENTITY_MAP[s]

   TYPES =
    article: 'article'
@@ -198,7 +187,7 @@
      @$.elem = @pre "##{PREFIX}#{@$.id}.codeBlock", ->
       codeElem = @code @$.cssClass, ""

-    codeElem.innerHTML = escapeHtml code
+    codeElem.textContent = code

   class Table extends Node
    @extend()


Model bug fixes, added more Model attribute matchers


avoid exceptions

avoid exceptions

--- src/ui/app.coffee
+++ src/ui/app.coffee
@@ -66,7 +66,7 @@
             mainWindow.webContents.focus()
             el = window.document.getElementById('message-input')
             # focus on specific element
-            el.focus()
+            el?.focus()

     # hide menu bar in all platforms but darwin
     unless process.platform is 'darwin'


filter out empty ranges for flash

filter out empty ranges for flash

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -79,10 +79,13 @@
     return unless @needFlash()

     @onDidFinishOperation =>
-      ranges = @mutations.getMarkerBufferRanges()
-      highlightRanges @editor, ranges,
-        class: 'vim-mode-plus-flash'
-        timeout: settings.get('flashOnOperateDuration')
+      ranges = @mutations.getMarkerBufferRanges().filter (range) ->
+        not range.isEmpty()
+
+      if ranges.length
+        highlightRanges @editor, ranges,
+          class: 'vim-mode-plus-flash'
+          timeout: settings.get('flashOnOperateDuration')

   trackChangeIfNecessary: ->
     return unless @trackChange


:art: improve error handling for TransformStringByExternalCommand

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -301,13 +301,17 @@
             args: args
             stdout: @onStdout(index)
             exit: @onExit(numberOfProcess)
-            stdin: selection.getText()
+            stdin: @getStdin(selection)
           }
           restorePoint?(selection)

   # For easily extend by vmp plugin.
   getCommand: (selection) ->
     {@command, @args}
+
+  # For easily extend by vmp plugin.
+  getStdin: (selection) ->
+    selection.getText()

   onStdout: (index) ->
     (output) =>
@@ -324,6 +328,14 @@
     {stdin} = options
     delete options.stdin
     bufferedProcess = new BufferedProcess(options)
+    bufferedProcess.onWillThrowError ({error, handle}) =>
+      # Suppress command not found error intentionally.
+      if error.code is 'ENOENT' and error.syscall.indexOf('spawn') is 0
+        commandName = @constructor.getCommandName()
+        console.log "#{commandName}: Failed to spawn command #{error.path}."
+      @cancelOperation()
+      handle()
+
     if stdin
       bufferedProcess.process.stdin.write(stdin)
       bufferedProcess.process.stdin.end()


no semicolons in cs

no semicolons in cs

--- src/update.coffee
+++ src/update.coffee
@@ -14,7 +14,7 @@
     false if textarea.val().length <= 0 || textarea.val().length > 140

   shareText = (update) ->
-    "RS @" + $(update).data("name") + ": " + $(update).find(".text").text().trim();
+    "RS @" + $(update).data("name") + ": " + $(update).find(".text").text().trim()

   focusTextArea = (update) ->
     $(update_field).attr("value", $(update).data("id"))
@@ -28,13 +28,13 @@
     update = $(this)

     $(this).find(".reply").bind "click", (ev) ->
-      ev.preventDefault();
+      ev.preventDefault()
       textarea.text("@" + $(update).data("name") + " ")
       focusTextArea(update)

     $(this).find(".share").bind "click", (ev) ->
-      ev.preventDefault();
+      ev.preventDefault()
       textarea.text(shareText(update))
       focusTextArea(update)

-  +


Removed obsolete code and added some debug logging

--- lib/shortcut.coffee
+++ lib/shortcut.coffee
@@ -1,15 +1,20 @@
-{globalShortcut, BrowserWindow} = require 'electron'
+{globalShortcut} = require 'electron'
 config = require './config'
 Window = require './window'

+log = (acc, usage) ->
+  console.log "Registering shortcut: #{acc}\t=> #{usage}" if process.env.DEBUG?
+
 registerBossKey = ->
   accelerator = config.get('poi.shortcut.bosskey', '')
-  console.log accelerator
   if accelerator
+    log accelerator, 'Boss Key'
     globalShortcut.register accelerator, Window.toggleAllWindowsVisibility

 registerDevToolShortcut = ->
-  globalShortcut.register 'Ctrl+Shift+I', Window.openFocusedWindowDevTools
+  accelerator = 'Ctrl+Shift+I'
+  log accelerator, 'Open Focused Window Dev Tools'
+  globalShortcut.register accelerator, Window.openFocusedWindowDevTools

 module.exports =
   register: ->


Treat snippet as Atom snippet when missing all TextMate fields

The gfm and toml packages are now treated like TextMate packages
but use the Atom snippet format so just degrade gracefully when
trying to parse a TextMate snippet that doesn't have any of the
standard TextMate snippet keys.

--- lib/snippets.coffee
+++ lib/snippets.coffee
@@ -84,7 +84,13 @@
         return done()
       async.eachSeries(paths, loadSnippetFile, done)

-  translateTextmateSnippet: ({ scope, name, content, tabTrigger }) ->
+  translateTextmateSnippet: (snippet) ->
+    {scope, name, content, tabTrigger} = snippet
+
+    # Treat it as an Atom snippet if none of the TextMate snippet fields
+    # are present
+    return snippet unless scope or name or content or tabTrigger
+
     scope = syntax.cssSelectorFromScopeSelector(scope) if scope
     scope ?= '*'
     snippetsByScope = {}


fix tags

fix tags

--- modules/tags.coffee
+++ modules/tags.coffee
@@ -40,7 +40,7 @@
         true
       # Save the changes
       await Core.data.set("Tag:#{args[0].toLowerCase()}", filtered)
-      msg.reply "Deleted #{tags.length - filtered.length} tag(s)!"
+      msg.reply "Deleted #{tag.length - filtered.length} tag(s)!"

     @registerCommand '!', { argSeparator: ' ' }, (msg, args, d)=>
       return if msg.author.bot or args.length < 1
@@ -60,8 +60,8 @@
       # Generate a list of responses
       r = ''
       for res in tag
-        u = bot.Users.get(tag.by) or { username: 'Unknown', discriminator: tag.by }
-        r += "\n(#{u.username}##{u.discriminator}): #{tag.reply.substr(0,32)}..."
+        u = bot.Users.get(res.by) or { username: 'Unknown', discriminator: res.by }
+        r += "\n(#{u.username}##{u.discriminator}): #{res.reply.substr(0,32)}..."
       # Send it
       msg.channel.sendMessage r


Fix login dialog

Fix login dialog

--- coffee/views/dialog_login.coffee
+++ coffee/views/dialog_login.coffee
@@ -28,7 +28,6 @@

     submit: (e) ->
       e.preventDefault()
-      return if $("#login-form-submit").prop("disabled")
       submit = $("#login-form-submit").prop("disabled", true)
       cancel = $("#login-form-cancel").prop("disabled", true)
       i = submit.children("i").toggleClass("icon-refresh icon-spin")


refactored many functions, but tests don't pass yet

--- platform/src/gamEvolve.coffee
+++ platform/src/gamEvolve.coffee
@@ -38,7 +38,7 @@
   # The model copies itself as you call functions on it, like a Crockford-style monad
   Model: class Model
     constructor: (data = {}, @previous = null) ->
-      @data = GE.cloneData(data)
+      @data = GE.deepFreeze(GE.cloneData(data))
       @version = if @previous? then @previous.version + 1 else 0

     setData: (data) -> return new Model(data, @)
@@ -61,6 +61,22 @@
       newData = GE.applyPatches(patches, @data)
       return new Model(newData, @)

+  # Constants are modelData, assets, actions, and serviceData
+  NodeVisitorConstants: class NodeVisitorConstants
+    constructor: (@modelData, @serviceData, @assets, @actions) ->
+
+  NodeVisitorResult: class NodeVisitorResult
+    constructor: (@result = null, @modelPatches = [], @servicePatches = []) ->
+
+    # Return new results with combination of this and other
+    appendWith: (other) ->
+      # TODO: this is probably incorrect
+      newResult = result || other.result
+
+      newModelPatches = GE.concatenate(modelPatches, other.modelPatches)
+      newServicePatches = GE.concatenate(servicePatches, other.servicePatches)
+      return new NodeVisitorResult(newResult, newModelPatches, newServicePatches)
+
   signals: makeConstantSet("DONE", "ERROR")

   extensions:
@@ -74,6 +90,9 @@

   # Reject arrays as objects
   isOnlyObject: (o) -> return _.isObject(o) and not _.isArray(o)
+
+  # Create new array with the value of these arrays
+  concatenate: (rest...) -> _.flatten(rest, true)

   # Logging functions could be used later
   logError: (x) -> console.error(x)
@@ -139,37 +158,30 @@
       if key of affectedKeys then return true
       affectedKeys[key] = true

+
   # Catches all errors in the function
-  sandboxFunctionCall: (model, assets, bindings, functionName, parameters) ->
-    modelData = model.clonedData()
-    compiledParams = (GE.compileParameter(modelData, assets, bindings, parameter) for parameter in parameters)
-    evaluatedParams = (param.get() for param in compiledParams)
-
-    try
-      globals[functionName].apply({}, evaluatedParams)
-    catch e
-      GE.logWarning("Calling function #{functionName} raised an exception #{e}")
-
-  # Catches all errors in the function
-  sandboxActionCall: (model, assets, bindings, actions, actionName, methodName, layoutParameters, childNames, signals) ->
-    action = actions[actionName]
+  # The signals paramter is only used in the "handleSignals" call
+  sandboxActionCall: (node, constants, bindings, methodName, signals = {}) ->
+    action = constants.actions[actionName]
+    childNames = if node.children? then [0..node.children.length - 1] else []

     # TODO: insure that all params values are POD
     # TODO: allow paramDefs to be missing

-    modelData = model.clonedData()
+    modelData = GE.cloneData(constants.modelData)
+    serviceData = GE.cloneData(constants.serviceData)
     compiledParams = {}
     evaluatedParams = {}
     for paramName, defaultValue of action.paramDefs
       # Resolve parameter value. In order, try layout, bindings, and finally default
-      if layoutParameters and paramName of layoutParameters
-        paramValue = layoutParameters[paramName]
+      if node.params and paramName of node.params
+        paramValue = node.params[paramName]
       else if paramName of bindings
         paramValue = bindings[paramName]
       else
         paramValue = defaultValue

-      compiledParams[paramName] = GE.compileParameter(modelData, assets, bindings, paramValue)
+      compiledParams[paramName] = GE.compileParameter(paramValue, constants, bindings)
       evaluatedParams[paramName] = compiledParams[paramName].get()
     locals =
       params: evaluatedParams
@@ -187,17 +199,17 @@
       paramValue.set(evaluatedParams[paramName])

     # return result and patches, if any
-    return [result, model.makePatches(modelData)]
-
-  calculateBindingSet: (modelData, assets, oldBindings, bindingLayout) ->
+    return new NodeVisitorResult(result, GE.makePatches(constants.modelData, modelData), GE.makePatches(constants.serviceData, serviceData))
+
+  calculateBindingSet: (node, constants, oldBindings) ->
     bindingSet = []

     # TODO: multiply from values together in order to make every combination
-    if "from" of bindingLayout
-      for bindingName, bindingExpression of bindingLayout.from
+    if "from" of node
+      for bindingName, bindingExpression of node.from
         # Evaluate values of the "from" clauses
         # TODO: in the case of models, get reference to model rather than evaluate the data here
-        bindingValues = GE.compileParameter(modelData, assets, oldBindings, bindingExpression).get()
+        bindingValues = GE.compileParameter(bindingExpression, constants, oldBindings).get()
         for bindingIndex in [0..bindingValues.length - 1]
           # Avoid polluting old object, and avoid creating new properties
           newBindings = Object.create(oldBindings)
@@ -209,38 +221,86 @@
             newBindings[bindingName] = bindingValues[bindingIndex]

           # Handle select
-          for name, value of bindingLayout.select
-            newBindings[name] = GE.compileParameter(modelData, assets, newBindings, value).get()
+          for name, value of node.select
+            newBindings[name] = GE.compileParameter(value, constants, newBindings).get()

           bindingSet.push(newBindings)
     else
       # Avoid polluting old object, and avoid creating new properties
       newBindings = Object.create(oldBindings)
       # Handle select
-      for name, value of bindingLayout.select
+      for name, value of node.select
         newBindings[name] = value
       bindingSet.push(newBindings)

     return bindingSet

-  handleSetModel: (model, assets, bindings, setModelLayout) ->
-    modelData = model.clonedData()
+  visitActionNode: (node, constants, bindings) ->
+    if node.action not of constants.actions then throw new Error("Cannot find action '#{node.action}'")
+
+    if "update" of constants.actions[node.action]
+      results = GE.sandboxActionCall(node, constants, bindings, "update")
+
+    # check which children should be activated
+    if "listActiveChildren" of constants.actions[node.action]
+      activeChildrenResults = GE.sandboxActionCall(node, constants, bindings, "listActiveChildren")
+      activeChildren = activeChildrenResults.result
+    else
+      # By default, all children are considered active
+      activeChildren = if node.children? then [0..node.children.length - 1] else []
+
+    # Continue with children
+    childSignals = []
+    for childIndex in activeChildren
+      child = node.children[childIndex]
+      childResults = GE.visitNode(node, constants, bindings)
+      results = results.appendWith(childResults)
+
+    # Handle signals
+    # TODO: if handler not defined, propogate error signals upwards? How to merge them?
+    if "handleSignals" of constants.actions[node.action]
+      errorResults = GE.sandboxActionCall(node, constants, bindings, "handleSignals", childSignals)
+      results = results.appendWith(errorResults)
+
+  # Catches all errors in the function
+  visitCallNode: (node, constants, bindings) ->
+    modelData = GE.cloneData(constants.modelData)
+    compiledParams = (GE.compileParameter(paramter, constants, bindings) for parameter in parameters)
+    evaluatedParams = (param.get() for param in compiledParams)
+
+    try
+      globals[functionName].apply({}, evaluatedParams)
+    catch e
+      GE.logWarning("Calling function #{functionName} raised an exception #{e}")
+
+  visitBindNode: (node, constants, oldBindings) ->
+    bindingSet = GE.calculateBindingSet(node, constants, oldBindings)
+    result = new NodeVisitorResult()
+    for newBindings in bindingSet
+      # Continue with children
+      for child in (layout.children or [])
+        childResult = GE.runStep(node, constants, newBindings)
+        result = result.appendWith(childResult)
+    return result
+
+  visitSetModelNode: (node, constants, bindings) ->
+    modelData = GE.cloneData(constants.modelData)

     # TODO: handle bindings?
-    for name, value of setModelLayout
-      evaluatedParam = GE.compileParameter(modelData, assets, bindings, value).get()
-      GE.makeModelEvaluator(modelData, name).set(evaluatedParam)
+    for name, value of node
+      evaluatedParam = GE.compileParameter(value, constants, bindings).get()
+      GE.makeModelEvaluator(constants, name).set(evaluatedParam)

-    return model.makePatches(modelData)
+    return GE.makePatches(constants.modelData, modelData)

   nodeVisitors:
-    "action": visitActionNode
-    "call": visitCallNode
-    "bind": visitBindNode
-    "setModel": visitSetModelNode
+    "action": GE.visitActionNode
+    "call": GE.visitCallNode
+    "bind": GE.visitBindNode
+    "setModel": GE.visitSetModelNode

   # Constants are modelData, assets, actions, and serviceData
-  visitNode: (node, bindings, constants) ->
+  visitNode: (node, constants, bindings = {}) ->
     # TODO: defer action and call execution until whole tree is evaluated?
     # TODO: handle children as object in addition to array

@@ -252,62 +312,8 @@

     return makeNodeVisitorResult()

-    # List of patches to apply, across all actions
-    modelPatches = []
-    servicePatches = {}
-    result = undefined
-
-      if layout.action not of actions then throw new Error("Cannot find action '#{layout.action}'")
-
-      childNames = if layout.children? then [0..layout.children.length - 1] else []
-
-      if "update" of actions[layout.action]
-        [result, actionPatches] = GE.sandboxActionCall(model, assets, bindings, actions, layout.action, "update", layout.params, childNames)
-        # Concatenate patches array in place
-        patches.push(actionPatches...)
-
-      # check which children should be activated
-      if "listActiveChildren" of actions[layout.action]
-        [activeChildren, __] = GE.sandboxActionCall(model, assets, bindings, actions, layout.action, "listActiveChildren", layout.params, childNames)
-      else
-        # By default, all children are considered active
-        activeChildren = childNames
-
-      # Continue with children
-      childSignals = []
-      for childIndex in activeChildren
-        child = layout.children[childIndex]
-        [childSignals[childIndex], childPatches] = GE.runStep(model, assets, actions, child, bindings)
-        # Concatenate patches array in place
-        patches.push(childPatches...)
-
-      # Handle signals
-      # TODO: if handler not defined, propogate error signals upwards? How to merge them?
-      if "handleSignals" of actions[layout.action]
-        [result, actionPatches] = GE.sandboxActionCall(model, assets, bindings, actions, layout.action, "handleSignals", layout.params, childNames, childSignals)
-        # Concatenate patches array in place
-        patches.push(actionPatches...)
-    else if "call" of layout
-      GE.sandboxFunctionCall(model, assets, bindings, layout.call, layout.params, bindings)
-    else if "bind" of layout
-      bindingSet = GE.calculateBindingSet(model.data, assets, bindings, layout.bind)
-      for newBindings in bindingSet
-        # Continue with children
-        for child in (layout.children or [])
-          [__, childPatches] = GE.runStep(model, assets, actions, child, newBindings)
-          # Concatenate patches array in place
-          patches.push(childPatches...)
-    else if "setModel" of layout
-      setModelPatches = GE.handleSetModel(model, assets, bindings, layout.setModel)
-      # Concatenate the array in place
-      patches.push(setModelPatches...)
-    else
-      GE.logError("Layout item is not understood")
-
-    return [result, patches]
-
   # Parameter names are always strings
-  makeModelEvaluator: (modelData, name) ->
+  makeModelEvaluator: (constants, name) ->
     if not name? then throw new Error("Model evaluator requires a name")

     [parent, key] = GE.getParentAndKey(modelData, name.split("."))
@@ -316,7 +322,7 @@
       set: (x) -> parent[key] = x
     }

-  makeAssetEvaluator: (assets, name) ->
+  makeAssetEvaluator: (constants, name) ->
     if not name? then throw new Error("Asset evaluator requires a name")

     return {
@@ -324,17 +330,23 @@
       set: (x) -> # Noop. Cannot set asset
     }

-  makeConstantEvaluator: (value) ->
+  makeConstantEvaluator: (constants, value) ->
     return {
       get: -> return value
       set: -> # Noop. Cannot set constant value
     }

+  parameterEvaluators:
+    "model": GE.makeModelEvaluator
+    "asset": GE.makeAssetEvaluator
+    "service": GE.makeServiceEvaluator
+    "constant": GE.makeConstantEvaluator

   # Compile parameter text into 'executable' object containing get()/set() methods
-  # TODO: include piping expressions
+  # The set() function returns a NodeVisitorResult, containing patches
+  # TODO: support expressions
   # TODO: insure that parameter constants are only JSON
-  compileParameter: (modelData, assets, bindings, layoutParameter) ->
+  compileParameter: (layoutParameter, constants, bindings) ->
     if _.isString(layoutParameter) and layoutParameter.length > 0
       # It might be an binding to be evaluated
       if layoutParameter[0] == "$"
@@ -349,17 +361,15 @@
           layoutParameter = "#{bindingKey}#{layoutParameter.slice(endChar)}"
         else
           # WRONG: This is a hack, but will not work for more complex expressions
-          return GE.makeConstantEvaluator(bindingKey)
+          return GE.makeConstantEvaluator(constants, bindingKey)

       if layoutParameter[0] == "@"
         # The argument is optional
         # TODO: include multiple arguments? As list or map?
         [matcherName, argument] = layoutParameter.slice(1).split(":")
-        switch matcherName
-          when "model" then return GE.makeModelEvaluator(modelData, argument)
-          when "asset" then return GE.makeAssetEvaluator(assets, argument)
-          else throw new Error("Cannot handle evaluator #{matcherName}")
-      # Nope, just a string. Fall through...
+        if not matcherName of GE.parameterEvaluators
+          throw new Error("Cannot handle evaluator #{matcherName}")
+        return GE.parameterEvaluators[matcherName](constants, argument)

     # Return as a constant value
     return GE.makeConstantEvaluator(layoutParameter)
@@ -411,11 +421,3 @@

 # Install the GE namespace in the global scope
 globals.GE = GE
-
-
-
-
-
-
-
-


add keymaps for jump-* commands

add keymaps for jump-* commands

--- keymaps/md.cson
+++ keymaps/md.cson
@@ -1,12 +1,14 @@
 ".platform-darwin .editor":
+  "cmd-j cmd-h": "markdown-writer:jump-to-next-heading"
+  "cmd-j cmd-d": "markdown-writer:jump-between-reference-definition"
+  "cmd-j cmd-t": "markdown-writer:jump-to-next-table-cell"
   "shift-cmd-K": "markdown-writer:insert-link"
   "shift-cmd-I": "markdown-writer:insert-image"
-  "cmd-i": "markdown-writer:toggle-italic-text"
-  "cmd-b": "markdown-writer:toggle-bold-text"
-  "cmd-'": "markdown-writer:toggle-code-text"
-  "cmd-k": "markdown-writer:toggle-keystroke-text"
-  "cmd-h": "markdown-writer:toggle-strikethrough-text"
-  "shift-cmd-\"": "markdown-writer:toggle-codeblock-text"
+  "cmd-i":       "markdown-writer:toggle-italic-text"
+  "cmd-b":       "markdown-writer:toggle-bold-text"
+  "cmd-'":       "markdown-writer:toggle-code-text"
+  "cmd-k":       "markdown-writer:toggle-keystroke-text"
+  "cmd-h":       "markdown-writer:toggle-strikethrough-text"
   "ctrl-alt-1":  "markdown-writer:toggle-h1"
   "ctrl-alt-2":  "markdown-writer:toggle-h2"
   "ctrl-alt-3":  "markdown-writer:toggle-h3"
@@ -15,29 +17,30 @@
   "shift-cmd-O": "markdown-writer:toggle-ol"
   "shift-cmd-U": "markdown-writer:toggle-ul"
   "shift-cmd->": "markdown-writer:toggle-blockquote"
+  'shift-cmd-"': "markdown-writer:toggle-codeblock-text"

 ".platform-win32 .editor":
   "shift-ctrl-K": "markdown-writer:insert-link"
   "shift-ctrl-I": "markdown-writer:insert-image"
-  "ctrl-i": "markdown-writer:toggle-italic-text"
-  "ctrl-b": "markdown-writer:toggle-bold-text"
-  "ctrl-'": "markdown-writer:toggle-code-text"
-  "ctrl-h": "markdown-writer:toggle-strikethrough-text"
-  "ctrl-1": "markdown-writer:toggle-h1"
-  "ctrl-2": "markdown-writer:toggle-h2"
-  "ctrl-3": "markdown-writer:toggle-h3"
-  "ctrl-4": "markdown-writer:toggle-h4"
-  "ctrl-5": "markdown-writer:toggle-h5"
+  "ctrl-i":       "markdown-writer:toggle-italic-text"
+  "ctrl-b":       "markdown-writer:toggle-bold-text"
+  "ctrl-'":       "markdown-writer:toggle-code-text"
+  "ctrl-h":       "markdown-writer:toggle-strikethrough-text"
+  "ctrl-1":       "markdown-writer:toggle-h1"
+  "ctrl-2":       "markdown-writer:toggle-h2"
+  "ctrl-3":       "markdown-writer:toggle-h3"
+  "ctrl-4":       "markdown-writer:toggle-h4"
+  "ctrl-5":       "markdown-writer:toggle-h5"

 ".platform-linux .editor":
   "shift-ctrl-K": "markdown-writer:insert-link"
   "shift-ctrl-I": "markdown-writer:insert-image"
-  "ctrl-i": "markdown-writer:toggle-italic-text"
-  "ctrl-b": "markdown-writer:toggle-bold-text"
-  "ctrl-'": "markdown-writer:toggle-code-text"
-  "ctrl-h": "markdown-writer:toggle-strikethrough-text"
-  "ctrl-1": "markdown-writer:toggle-h1"
-  "ctrl-2": "markdown-writer:toggle-h2"
-  "ctrl-3": "markdown-writer:toggle-h3"
-  "ctrl-4": "markdown-writer:toggle-h4"
-  "ctrl-5": "markdown-writer:toggle-h5"
+  "ctrl-i":       "markdown-writer:toggle-italic-text"
+  "ctrl-b":       "markdown-writer:toggle-bold-text"
+  "ctrl-'":       "markdown-writer:toggle-code-text"
+  "ctrl-h":       "markdown-writer:toggle-strikethrough-text"
+  "ctrl-1":       "markdown-writer:toggle-h1"
+  "ctrl-2":       "markdown-writer:toggle-h2"
+  "ctrl-3":       "markdown-writer:toggle-h3"
+  "ctrl-4":       "markdown-writer:toggle-h4"
+  "ctrl-5":       "markdown-writer:toggle-h5"


route touchstart on anchors

route touchstart on anchors

--- ui/index.coffee
+++ ui/index.coffee
@@ -406,7 +406,10 @@
     'auth/:provider': 'auth'

   events:
-    'click a': (e) ->
+    'click a': 'onClick'
+    'touchstart a': 'onClick'
+
+  onClick: (e) ->
       href = e.currentTarget.attributes?.href?.value
       if href? and not /https?:/.exec href
         e.preventDefault()


domain: implement JDomain.makeTransaction

--- workers/social/lib/social/models/domain.coffee
+++ workers/social/lib/social/models/domain.coffee
@@ -226,78 +226,48 @@
           return

         # Make transaction
-        @makeTransaction client, data, (err, charge)=>
+        @makeTransaction client, data.transaction, (err, charge)=>
           return callback err  if err

           console.log "Transaction is done."

-          domainManager.domainService.registerDomain params, (err, data)->
-
-            console.log "ResellerAPI response:", err, data
+          domainManager.domainService.registerDomain params, (err, response)->
+
+            console.log "ResellerAPI response:", err, response

             if err
               return charge.cancel client, ->
                 callback err, data

-            if data.actionstatus is "Success"
+            if response.actionstatus is "Success"

               console.log "Creating new JDomain..."
               model = new JDomain
-                domain         : data.description
+                domain         : response.description
                 hostnameAlias  : []
                 regYears       : params.years
                 orderId        :
-                  resellerClub : data.entityid
+                  resellerClub : response.entityid
                 loadBalancer   :
                   mode         : "" # "roundrobin"
                 domainType     : "new"

               model.save (err) ->
-
                 return callback err if err

-                # Why are adding this manually? ~ GG
-                account = client.connection.delegate
-                rel = new Relationship
-                  targetId    : model.getId()
-                  targetName  : 'JDomain'
-                  sourceId    : account.getId()
-                  sourceName  : 'JAccount'
-                  as          : 'owner'
-
-                rel.save (err)->
+                { delegate } = client.connection
+
+                delegate.addDomain model, (err) ->
                   return callback err if err

-                callback err, model
+                  callback err, model

             else
               callback {message: "Domain registration failed"}

-  @makeTransaction: (client, data, callback)->
-#
-#    {delegate} = client.connection
-#    {nickname} = delegate.profile
-#
-#    if nickname in ['devrim', 'chris', 'gokmen']
-#      console.log "#{nickname} made a test transaction for #{data.domain} (#{data.year} year/s)"
-#      console.log "we charged him $#{data.price} ...."
-#      callback null,
-#        cancel :->
-#          console.log "Payment cancelled..."
-#    else
-#      console.log message = "Transaction is not valid."
-#      callback {message}
-
+  @makeTransaction: secure (client, data, callback)->
     JPaymentCharge = require './payment/charge'
-
-    amount = 10 * 10 * data.years
-
-    JPaymentCharge.charge client,
-      code   : 'domain_abc'
-      amount : amount
-      desc   : "Domain registration fee - #{data.domainName} (#{data.years} year(s)})"
-    , (err) ->
-      console.log { arguments }
+    JPaymentCharge.charge client, data, callback

   bound: require 'koding-bound'


JMachine: inform account owners when machine share/unshare happened

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -210,6 +210,14 @@
     return newUsers

+  informAccounts = (users, machineUid)->
+
+    users.forEach (user)->
+      user.fetchOwnAccount (err, account)->
+        return if err or not account
+        account.sendNotification 'MachineListUpdated', machineUid
+
+
   # Private Methods
   # ---------------

@@ -287,7 +295,9 @@
       callback new KodingError \
         "Machine sharing is limited up to 10 users."
     else
-      @update $set: { users }, (err)-> callback err
+      @update $set: { users }, (err)->
+        informAccounts targets, @getAt 'uid'
+        callback err

   removeUsers: (options, callback)->
@@ -299,7 +309,9 @@
     for user in targets
       users = excludeUser { users, user, permanent }

-    @update $set: { users }, (err)-> callback err
+    @update $set: { users }, (err)->
+      informAccounts targets, @getAt 'uid'
+      callback err

   shareWith: (options, callback)->


need to munge concat_sourcemap to get typescript-gen'd JS into the final build

--- config/plugins/typescript.coffee
+++ config/plugins/typescript.coffee
@@ -1,4 +1,6 @@
 module.exports = (lineman) ->
+  app = lineman.config.application
+
   files:
     typescript:
       app: "app/js/**/*.ts"
@@ -9,10 +11,10 @@
       generatedSpecHelpers: "generated/js/spec-helpers.ts.js"

   config:
-    loadNpmTasks: lineman.config.application.loadNpmTasks.concat('grunt-typescript')
+    loadNpmTasks: app.loadNpmTasks.concat('grunt-typescript')

     prependTasks:
-      common: lineman.config.application.prependTasks.common.concat('typescript')
+      common: app.prependTasks.common.concat('typescript')

     typescript:
       compile:
@@ -21,6 +23,10 @@
           "<%= files.typescript.generatedSpec %>": "<%= files.typescript.spec %>"
           "<%= files.typescript.generatedSpecHelpers %>": "<%= files.typescript.specHelpers %>"

+    concat_sourcemap:
+      js:
+        src: app.concat_sourcemap.js.src.concat("<%= files.typescript.generated %>")
+
     watch:
       typescript:
         files: "<%= files.typescript.app %>"


Better documentation for roles.coffee

Better documentation for roles.coffee

--- src/scripts/roles.coffee
+++ src/scripts/roles.coffee
@@ -2,8 +2,8 @@
 #   Assign roles to people you're chatting with
 #
 # Commands:
-#   hubot <user> is a badass guitarist - assign a role to a user
-#   hubot <user> is not a badass guitarist - remove a role from a user
+#   hubot <user> is <role> - assign a role to a user
+#   hubot <user> is not <role> - remove a role from a user
 #   hubot who is <user> - see what roles a user has
 #
 # Examples:


another bugfix (dbg not defined)

another bugfix (dbg not defined)

--- src/smc-hub/proxy.coffee
+++ src/smc-hub/proxy.coffee
@@ -450,15 +450,16 @@
     _ws_proxy_servers = {}
     http_proxy_server.on 'upgrade', (req, socket, head) ->

+        # Strip remember_me cookie from req used for websocket upgrade.
+        req.headers['cookie'] = exports.strip_remember_me_cookie(req.headers['cookie']).cookie
+
+        req_url = req.url.slice(base_url.length)  # strip base_url for purposes of determining project location/permissions
+        dbg = (m) -> winston.debug("http_proxy_server websocket(#{req_url}): #{m}")
+
         if exports.version_check(req, undefined, base_url)
             dbg("websocket upgrade -- version check failed")
             return

-        # Strip remember_me cookie from req used for websocket upgrade.
-        req.headers['cookie'] = exports.strip_remember_me_cookie(req.headers['cookie']).cookie
-
-        req_url = req.url.slice(base_url.length)  # strip base_url for purposes of determining project location/permissions
-        dbg = (m) -> winston.debug("http_proxy_server websocket(#{req_url}): #{m}")
         target undefined, req_url, (err, location, internal_url) ->
             if err
                 dbg("websocket upgrade error -- #{err}")


(chore) type fix

(chore) type fix

--- src/steroids/Help.coffee
+++ src/steroids/Help.coffee
@@ -92,7 +92,7 @@
       You have: AppGyver Scanner for #{platform} v#{opts.currentVersion}
       Latest available is: AppGyver Scanner for #{platform} v#{opts.latestVersion}

-      Plese update from #{appStore}.
+      Please update from #{appStore}.
     """

   @loggedOut: ->


add bower metadata

add bower metadata

Signed-off-by: Pierre Tardy <bb5a2a16eebb4a48138fca46fede24b3c8d635fe@intel.com>

--- guanlecoja/config.coffee
+++ guanlecoja/config.coffee
@@ -11,10 +11,11 @@
 gulp.task "publish", ['default'], ->
     if not exec "git diff --no-ext-diff --quiet --exit-code"
         echo "print commit your changes"
-        exit(1)
+        return
     bower_json =
         name: "guanlecoja-ui"
-        version: "1.0.1"
+        version: "1.0.2"
+        main: ["scripts.js", "styles.css", "fonts/*", "img/*"]
         description: "Sets of widgets and integrated bower dependencies useful for dashboard SPAs"
         dependencies: {}


fixed negative column width

fixed negative column width

--- src/utils/columns.coffee
+++ src/utils/columns.coffee
@@ -36,7 +36,7 @@
               .reduce((prev, cur, i, arr) ->
                 # Get the difference from the current value
                 # with the previous value in the array
-                diff = if i > 0 then cur - arr[i - 1] else Number.MAX_VALUE
+                diff = if i > 0 then Math.max(cur - arr[i - 1], 0) else Number.MAX_VALUE
                 # Return the new difference if it is smaller
                 # than the previous difference
                 return if diff < prev then diff else prev
@@ -70,7 +70,9 @@
         # number of series to display
         nSeries = keys.length

-        return parseInt((delta - options.columnsHGap) / nSeries)
+        return if options.columnsHGap > delta
+          then parseInt((delta - options.columnsHGap) / nSeries)
+          else parseInt(delta / nSeries)

       getColumnAxis: (data, columnWidth, options) ->
         {pseudoColumns, keys} = this.getPseudoColumns(data, options)


Added modal open to NavGroup

Added modal open to NavGroup

--- Framework/Views/iOS/NavGroup_Framework_iOS.coffee
+++ Framework/Views/iOS/NavGroup_Framework_iOS.coffee
@@ -1,12 +1,14 @@
 root.NavGroup_Framework_iOS = class NavGroup_Framework_iOS
   constructor:(options = {}) ->
-    options = root._.extend({}, options)
+    options = root._.extend({
+      modal: false
+    }, options)

     @window = Ti.UI.createWindow({ navBarHidden: true })
     @navGroup = Ti.UI.iPhone.createNavigationGroup(options)
     @window.add(@navGroup)

-    @window.open()
+    @window.open({ modal: options.modal })

   close: =>
     @window.close()


Added option stopOnFail to tell test harness to stop when a test fails. This should make it easier to probe failed tests.

--- src/main/coffeescript/scxml/test/multi-process-browser/harness.coffee
+++ src/main/coffeescript/scxml/test/multi-process-browser/harness.coffee
@@ -18,6 +18,7 @@
 		forwardX11 = args['-forwardX11'] or (xserver is 'Xephyr')
 		projectSrcDir = args['-projectSrcDir'] or '/home/jacob/workspace/scion'
 		fileServerRoot = args['-fileServerRoot'] or "#{projectSrcDir}/build"
+		stopOnFail = args['-stopOnFail']

 		console.log "received args",args

@@ -32,6 +33,7 @@
 		console.log "forwardX11",forwardX11
 		console.log "projectSrcDir",projectSrcDir
 		console.log "fileServerRoot",fileServerRoot
+		console.log "stopOnFail",stopOnFail

 		serverTestRunnerUrl = "http://#{hostServerHostName}:#{hostServerPort}/runner"

@@ -66,6 +68,27 @@

 		finishedClients = []

+		finish = ->
+			console.error "All clients finished. Wrapping up."
+
+			report =
+				testCount : results.testCount
+				testsPassed : result.id for result in results.testsPassed
+				testsFailed : result.id for result in results.testsFailed
+				testsErrored : result.id for result in results.testsErrored
+
+
+			console.error report2string report
+
+			endTime = new Date()
+
+			console.error "Running time: #{(endTime - startTime)/1000} seconds"
+
+			#TODO: kill processes, then exit
+			#serverClientComm.killClientProcesses()
+
+			process.exit results.testCount == results.testsPassed
+
 		console.error "starting server"
 		server = http.createServer (request,response) ->
 			url = urlModule.parse request.url
@@ -130,27 +153,7 @@

 						#once all clients are finished, then we're finished
 						#print report and exit
-						if finishedClients.length == clientAddresses.length
-							console.error "All clients finished. Wrapping up."
-
-							report =
-								testCount : results.testCount
-								testsPassed : result.id for result in results.testsPassed
-								testsFailed : result.id for result in results.testsFailed
-								testsErrored : result.id for result in results.testsErrored
-
-
-							console.error report2string report
-
-							endTime = new Date()
-
-							console.error "Running time: #{(endTime - startTime)/1000} seconds"
-
-							#TODO: kill processes, then exit
-							#serverClientComm.killClientProcesses()
-
-							process.exit results.testCount == results.testsPassed
-
+						if finishedClients.length == clientAddresses.length then finish()

 				when "/statechart-initialized"
 					#signal recieved when a statechart is initialized
@@ -174,7 +177,7 @@
 								console.error "Cannot find testData with id #{o.id}"

 							#send the events to the browser, via a proxy
-							serverClientComm.sendEventsToBrowser testData.sourceAddress,testData.test.testScript.events.slice(),projectSrcDir
+							testData.sendEventProcess = serverClientComm.sendEventsToBrowser testData.sourceAddress,testData.test.testScript.events.slice(),projectSrcDir

 				when "/check-configuration"
 					do ->
@@ -213,6 +216,7 @@

 										serverClientComm.sendResetEventToClient testData.sourceAddress
 								else
+									#test has failed
 									response.writeHead 500,{"Content-Type":"text/plain"}
 									errMsg = "Did not match expected configuration. Received: #{JSON.stringify(configuration)}. Expected:#{JSON.stringify(expectedConfiguration)}."
 									response.write errMsg
@@ -222,8 +226,23 @@

 									results.testsFailed.push testData.test

-									#test has failed, so we send reset event
-									serverClientComm.sendResetEventToClient testData.sourceAddress
+									#if stopOnFail is set, then wrap up
+									if stopOnFail
+										console.error "Test #{testData.test.id} failed and stopOnFail is set. Wrapping up..."
+										finish()
+									else
+										#if the event sending process is still active
+										if testData.sendEventProcess.pid
+											#wait for exit event
+											testData.sendEventProcess.on "exit", ->
+												serverClientComm.sendResetEventToClient testData.sourceAddress
+
+											#kill the event process
+											testData.sendEventProcess.kill()
+										else
+											#otherwise just wait for the reset event
+											serverClientComm.sendResetEventToClient testData.sourceAddress
+
 							catch e
 								console.error e.message
 								console.error e.type


correct line numbers

correct line numbers

--- lib/eval.coffee
+++ lib/eval.coffee
@@ -49,7 +49,7 @@

   showError: (r, lines) ->
     @errorLines?.lights.destroy()
-    lights = @ink.highlights.errorLines lines
+    lights = @ink.highlights.errorLines (file: file, line: line-1 for {file, line} in lines)
     @errorLines = {r, lights}

     destroyResult = r.destroy.bind r


Add blank line

Add blank line

--- config.coffee
+++ config.coffee
@@ -39,6 +39,7 @@
   # RTMP stream name
   rtmpApplicationName: 'live'

+
   ##########################
   ## Advanced configurations
   ##########################


Remove the default highlight copy

Remove the default highlight copy

--- config.coffee
+++ config.coffee
@@ -30,7 +30,7 @@
   GALLERIES_NUM:           '2,000'
   FAIRS_NUM:               '80'
   MUSEUMS_NUM:             '800'
-  PARTNER_HIGHLIGHT_COPY:  'Gagosian Gallery, Pace Gallery, White Cube, The Guggenheim, SFMOMA, The British Museum, TEFAF, and The Armory Show.'
+  PARTNER_HIGHLIGHT_COPY:  'X, Y and Z'

 # Override any values with env variables if they exist
 module.exports[key] = (process.env[key] or val) for key, val of module.exports


Inlcude .hpp files when compiling

Inlcude .hpp files when compiling


Use variable package name in main file

Use variable package name in main file

--- lib/main.coffee
+++ lib/main.coffee
@@ -43,6 +43,13 @@
   compileCloudPromise: null
   flashCorePromise: null

+  packageName: ->
+    if @_packageName
+      return @_packageName
+
+    pjson = require('../package.json');
+    @_packageName = pjson.name
+
   activate: (state) ->
     # Require modules on activation
     @StatusView ?= require './views/status-bar-view'
@@ -51,7 +58,7 @@
     {@File} = require 'atom'

     # Install packages we depend on
-    require('atom-package-deps').install('spark-dev', true)
+    require('atom-package-deps').install(@packageName(), true)

     @workspaceElement = atom.views.getView(atom.workspace)
     {CompositeDisposable, Emitter} = require 'atom'
@@ -64,38 +71,39 @@
     @statusView = new @StatusView()

     # Hook up commands
-    @disposables.add atom.commands.add 'atom-workspace',
-      'spark-dev:login': => @login()
-      'spark-dev:logout': => @logout()
-      'spark-dev:select-device': => @selectCore()
-      'spark-dev:rename-device': => @renameCore()
-      'spark-dev:remove-device': => @removeCore()
-      'spark-dev:claim-device': => @claimCore()
-      'spark-dev:try-flash-usb': => @tryFlashUsb()
-      'spark-dev:update-menu': => @MenuManager.update()
-      'spark-dev:show-compile-errors': => @showCompileErrors()
-      'spark-dev:show-serial-monitor': => @showSerialMonitor()
-      'spark-dev:identify-device': => @identifyCore()
-      'spark-dev:compile-cloud': => @compileCloud()
-      'spark-dev:flash-cloud': => @flashCloud()
-      'spark-dev:flash-cloud-file': (event) => @flashCloudFile event
-      'spark-dev:setup-wifi': => @setupWifi()
-      'spark-dev:enter-wifi-credentials': => @enterWifiCredentials()
+    commands = {}
+    commands["#{@packageName()}:login"] = => @login()
+    commands["#{@packageName()}:logout"] = => @logout()
+    commands["#{@packageName()}:select-device"] = => @selectCore()
+    commands["#{@packageName()}:rename-device"] = => @renameCore()
+    commands["#{@packageName()}:remove-device"] = => @removeCore()
+    commands["#{@packageName()}:claim-device"] = => @claimCore()
+    commands["#{@packageName()}:try-flash-usb"] = => @tryFlashUsb()
+    commands["#{@packageName()}:update-menu"] = => @MenuManager.update()
+    commands["#{@packageName()}:show-compile-errors"] = => @showCompileErrors()
+    commands["#{@packageName()}:show-serial-monitor"] = => @showSerialMonitor()
+    commands["#{@packageName()}:identify-device"] = => @identifyCore()
+    commands["#{@packageName()}:compile-cloud"] = => @compileCloud()
+    commands["#{@packageName()}:flash-cloud"] = => @flashCloud()
+    commands["#{@packageName()}:flash-cloud-file"] = (event) => @flashCloudFile event
+    commands["#{@packageName()}:setup-wifi"] = => @setupWifi()
+    commands["#{@packageName()}:enter-wifi-credentials"] = => @enterWifiCredentials()
+    @disposables.add atom.commands.add 'atom-workspace', commands

     # Hook up events
-    @emitter.on 'spark-dev:identify-device', (event) =>
+    @emitter.on "#{@packageName()}:identify-device", (event) =>
       @identifyCore(event.port)

-    @emitter.on 'spark-dev:compile-cloud', (event) =>
+    @emitter.on "#{@packageName()}:compile-cloud", (event) =>
       @compileCloud(event.thenFlash)

-    @emitter.on 'spark-dev:flash-cloud', (event) =>
+    @emitter.on "#{@packageName()}:flash-cloud", (event) =>
       @flashCloud(event.firmware)

-    @emitter.on 'spark-dev:setup-wifi', (event) =>
+    @emitter.on "#{@packageName()}:setup-wifi", (event) =>
       @setupWifi(event.port)

-    @emitter.on 'spark-dev:enter-wifi-credentials', (event) =>
+    @emitter.on "#{@packageName()}:enter-wifi-credentials", (event) =>
       @enterWifiCredentials(event.port, event.ssid, event.security)

     # Update menu (default one in CSON file is empty)
@@ -108,7 +116,7 @@
       catch error
         return

-      return unless protocol is 'spark-dev:'
+      return unless protocol is "#{@packageName()}:"

       try
         @initView pathname.substr(1)
@@ -116,9 +124,10 @@
         return

     # Updating toolbar
-    @disposables.add atom.commands.add 'atom-workspace',
-      'spark-dev:update-login-status': => @updateToolbarButtons()
-      'spark-dev:update-core-status': => @updateToolbarButtons()
+    commands = {}
+    commands["#{@packageName()}:update-login-status"] = => @updateToolbarButtons()
+    commands["#{@packageName()}:update-core-status"] = => @updateToolbarButtons()
+    @disposables.add atom.commands.add 'atom-workspace', commands

     # Monitoring changes in settings
     settings ?= require './vendor/settings'
@@ -137,7 +146,7 @@
         @watchConfig()
         @updateToolbarButtons()
         @MenuManager.update()
-        atom.commands.dispatch @workspaceElement, 'spark-dev:update-login-status'
+        atom.commands.dispatch @workspaceElement, "#{@packageName()}:update-login-status"

       @watchConfig()

@@ -159,18 +168,18 @@
     @statusView.updateLoginStatus()

   consumeToolBar: (toolBar) ->
-    @toolBar = toolBar 'spark-dev-tool-bar'
+    @toolBar = toolBar "#{@packageName()}-tool-bar"

     @toolBar.addSpacer()
     @flashButton = @toolBar.addButton
       icon: 'flash'
-      callback: 'spark-dev:flash-cloud'
+      callback: "#{@packageName()}:flash-cloud"
       tooltip: 'Compile in cloud and upload code using cloud'
       iconset: 'ion'
       priority: 51
     @compileButton = @toolBar.addButton
       icon: 'android-cloud-done'
-      callback: 'spark-dev:compile-cloud'
+      callback: "#{@packageName()}:compile-cloud"
       tooltip: 'Compile in cloud and show errors if any'
       iconset: 'ion'
       priority: 52
@@ -187,19 +196,19 @@
       priority: 54
     @coreButton = @toolBar.addButton
       icon: 'pinpoint'
-      callback: 'spark-dev:select-device'
+      callback: "#{@packageName()}:select-device"
       tooltip: 'Select which device you want to work on'
       iconset: 'ion'
       priority: 55
     @wifiButton = @toolBar.addButton
       icon: 'wifi'
-      callback: 'spark-dev:setup-wifi'
+      callback: "#{@packageName()}:setup-wifi"
       tooltip: 'Setup device\'s WiFi credentials'
       iconset: 'ion'
       priority: 56
     @toolBar.addButton
       icon: 'usb'
-      callback: 'spark-dev:show-serial-monitor'
+      callback: "#{@packageName()}:show-serial-monitor"
       tooltip: 'Show serial monitor'
       iconset: 'ion'
       priority: 57
@@ -276,7 +285,7 @@

   # Open view in bottom panel
   openPane: (uri) ->
-    uri = 'spark-dev://editor/' + uri
+    uri = "#{@packageName()}://editor/" + uri
     pane = atom.workspace.paneForURI uri

     if pane?
@@ -323,7 +332,7 @@
       @accessToken = @SettingsHelper.get 'access_token'
       @updateToolbarButtons()
       @MenuManager.update()
-      atom.commands.dispatch @workspaceElement, 'spark-dev:update-login-status'
+      atom.commands.dispatch @workspaceElement, "#{@packageName()}:update-login-status"

   processDirIncludes: (dirname) ->
     settings ?= require './vendor/settings'
@@ -348,7 +357,7 @@

     files = utilities.globList dirname, includes

-    notSourceExtensions = atom.config.get('spark-dev.filesExcludedFromCompile').split ','
+    notSourceExtensions = atom.config.get("#{@packageName()}.filesExcludedFromCompile").split ','
     ignores = ('**/*' + _s.trim(extension).toLowerCase() for extension in notSourceExtensions)

     if fs.existsSync(ignoreFile)
@@ -421,8 +430,9 @@
     @initView 'login'
     # You may ask why commands aren't registered in LoginView?
     # This way, we don't need to require/initialize login view until it's needed.
-    @disposables.add atom.commands.add 'atom-workspace',
-      'spark-dev:cancel-login': => @loginView.cancelCommand()
+    commands = {}
+    commands["#{@packageName}:cancel-login"] = => @loginView.cancelCommand()
+    @disposables.add atom.commands.add 'atom-workspace', commands
     @loginView.show()

   # Log out current user
@@ -459,8 +469,8 @@
         if !@removePromise
           return
         @SettingsHelper.clearCurrentCore()
-        atom.commands.dispatch @workspaceElement, 'spark-dev:update-core-status'
-        atom.commands.dispatch @workspaceElement, 'spark-dev:update-menu'
+        atom.commands.dispatch @workspaceElement, "#{@packageName()}:update-core-status"
+        atom.commands.dispatch @workspaceElement, "#{@packageName()}:update-menu"

         @removePromise = null
       , (e) =>
@@ -489,7 +499,7 @@
   # Identify core via serial
   identifyCore: (port=null) -> @loginRequired =>
     if !port
-      @choosePort('spark-dev:identify-device')
+      @choosePort("#{@packageName()}:identify-device")
     else
       @SerialHelper ?= require './utils/serial-helper'
       promise = @SerialHelper.askForCoreID port
@@ -523,11 +533,11 @@
       @statusView.clearAfter 5000
       return

-    if atom.config.get('spark-dev.saveAllBeforeCompile')
+    if atom.config.get("#{@packageName()}.saveAllBeforeCompile")
       atom.commands.dispatch @workspaceElement, 'window:save-all'

     @SettingsHelper.setLocal 'compile-status', {working: true}
-    atom.commands.dispatch @workspaceElement, 'spark-dev:update-compile-status'
+    atom.commands.dispatch @workspaceElement, "#{@packageName()}:update-compile-status"

     invalidFiles = files.filter (file) ->
       path.basename(file).indexOf(' ') > -1
@@ -542,8 +552,8 @@

       @CompileErrorsView ?= require './views/compile-errors-view'
       @SettingsHelper.setLocal 'compile-status', {errors: errors}
-      atom.commands.dispatch @workspaceElement, 'spark-dev:show-compile-errors'
-      atom.commands.dispatch @workspaceElement, 'spark-dev:update-compile-status'
+      atom.commands.dispatch @workspaceElement, "#{@packageName()}:show-compile-errors"
+      atom.commands.dispatch @workspaceElement, "#{@packageName()}:update-compile-status"
       return

     options = {}
@@ -560,7 +570,7 @@
         # Download binary
         @compileCloudPromise = null

-        if atom.config.get('spark-dev.deleteOldFirmwareAfterCompile')
+        if atom.config.get("#{@packageName()}.deleteOldFirmwareAfterCompile")
           # Remove old firmwares
           files = fs.listSync rootPath
           for file in files
@@ -573,10 +583,10 @@

         @downloadBinaryPromise.then (e) =>
           @SettingsHelper.setLocal 'compile-status', {filename: filename}
-          atom.commands.dispatch @workspaceElement, 'spark-dev:update-compile-status'
+          atom.commands.dispatch @workspaceElement, "#{@packageName()}:update-compile-status"
           if !!thenFlash
             setTimeout =>
-              atom.commands.dispatch @workspaceElement, 'spark-dev:flash-cloud'
+              atom.commands.dispatch @workspaceElement, "#{@packageName()}:flash-cloud"
               @downloadBinaryPromise = null
             , 500
           else
@@ -595,16 +605,16 @@
             @SettingsHelper.setLocal 'compile-status', {error: e.output}
           else
             @SettingsHelper.setLocal 'compile-status', {errors: errors}
-            atom.commands.dispatch @workspaceElement, 'spark-dev:show-compile-errors'
+            atom.commands.dispatch @workspaceElement, "#{@packageName()}:show-compile-errors"
         else
           @SettingsHelper.setLocal 'compile-status', {error: e.output}

-        atom.commands.dispatch @workspaceElement, 'spark-dev:update-compile-status'
+        atom.commands.dispatch @workspaceElement, "#{@packageName()}:update-compile-status"
         @compileCloudPromise = null
     , (e) =>
       @requestErrorHandler e
       @SettingsHelper.setLocal 'compile-status', null
-      atom.commands.dispatch @workspaceElement, 'spark-dev:update-compile-status'
+      atom.commands.dispatch @workspaceElement, "#{@packageName()}:update-compile-status"

   # Show compile errors list
   showCompileErrors: ->
@@ -628,7 +638,7 @@

     if files.length == 0 && (!firmware)
       # If no firmware file, compile
-      @emitter.emit 'spark-dev:compile-cloud', {thenFlash: true}
+      @emitter.emit "#{@packageName()}:compile-cloud", {thenFlash: true}
     else if (files.length == 1) || (!!firmware)
       # If one firmware file, flash

@@ -651,7 +661,7 @@
             @statusView.setStatus e.status + '...'
             @statusView.clearAfter 5000

-            if atom.config.get 'spark-dev.deleteFirmwareAfterFlash'
+            if atom.config.get "#{@packageName()}.deleteFirmwareAfterFlash"
               if fs.existsSync firmware
                 fs.unlink firmware

@@ -699,7 +709,7 @@
   # Set up core's WiFi
   setupWifi: (port=null) -> @loginRequired =>
     if !port
-      @choosePort 'spark-dev:setup-wifi'
+      @choosePort "#{@packageName()}:setup-wifi"
     else
       @initView 'select-wifi'
       @selectWifiView.port = port
@@ -715,7 +725,7 @@
     @wifiCredentialsView.show(ssid, security)

   tryFlashUsb: -> @projectRequired =>
-    if !atom.commands.registeredCommands['spark-dev-dfu-util:flash-usb']
+    if !atom.commands.registeredCommands["#{@packageName()}-dfu-util:flash-usb"]
       # TODO: Ask for installation
     else
-      atom.commands.dispatch @workspaceElement, 'spark-dev-dfu-util:flash-usb'
+      atom.commands.dispatch @workspaceElement, "#{@packageName()}-dfu-util:flash-usb"


add flag spec back into cloning

add flag spec back into cloning

--- lib/main.coffee
+++ lib/main.coffee
@@ -9,7 +9,7 @@
   regex[k] = v for own k,v of BetterRegExp::
   return regex

-BetterRegExp::clone = -> BetterRegExp @
+BetterRegExp::clone = (flags=@flags()) -> BetterRegExp @source, flags
 BetterRegExp::flags = -> util.getFlags @
 BetterRegExp::addFlag = (flag) -> @setFlag @flags()+flag
 BetterRegExp::setFlag = (flag) ->


:art: cleanup

:art: cleanup

--- lib/main.coffee
+++ lib/main.coffee
@@ -61,27 +61,25 @@
       'quick-highlight:clear':  => @clear()

     subs.add atom.workspace.observeTextEditors (editor) =>
-      subs.add editor.onDidStopChanging =>
+      editorSubs = new CompositeDisposable
+      editorSubs.add editor.onDidStopChanging =>
         return unless getEditor() is editor
         URI = editor.getURI()
         @refreshEditor(e) for e in getVisibleEditor() when (e.getURI() is URI)

-      subs.add editor.onDidChangeScrollTop => @refreshEditor(editor)
-      subs.add editor.onDidChangeScrollLeft => @refreshEditor(editor)
+      editorSubs.add editor.onDidChangeScrollTop => @refreshEditor(editor)
+      editorSubs.add editor.onDidChangeScrollLeft => @refreshEditor(editor)

-      subs.add me = editor.onDidDestroy =>
+      editorSubs.add editor.onDidDestroy =>
         @clearEditor editor
-        me.dispose()
-        subs.remove(me)
+        editorSubs.dispose()
+        subs.remove(editorSubs)
+
+      subs.add editorSubs

     subs.add atom.workspace.onDidChangeActivePaneItem (item) =>
       @statusBarManager?.clear()
-      if item instanceof TextEditor
-        @refreshEditor item
-
-  getNextColor: ->
-    @colorIndex = (@colorIndex + 1) % @colors.length
-    @colors[@colorIndex]
+      @refreshEditor(item) if item instanceof TextEditor

   deactivate: ->
     @clear()
@@ -98,7 +96,8 @@
       delete @keyword2color[keyword]
       @statusBarManager?.clear()
     else
-      @keyword2color[keyword] = @getNextColor()
+      @colorIndex = (@colorIndex + 1) % @colors.length
+      @keyword2color[keyword] = @colors[@colorIndex]
       @statusBarManager?.update @getCountForKeyword(editor, keyword)

     @refreshEditor(e) for e in getVisibleEditor()


remove verbose condition check

remove verbose condition check

--- lib/main.coffee
+++ lib/main.coffee
@@ -17,13 +17,12 @@
     subs.add(@observeStopChangingActivePaneItem())
     subs.add(@registerCommands())

-    if settings.get('queryCurrentWordByDoubleClick')
-      onMouseDown = @onMouseDown.bind(this)
-      subs.add atom.workspace.observeTextEditors (editor) ->
-        editor.element.addEventListener('mousedown', onMouseDown, true)
-        removeListener = -> editor.element.removeEventListener('mousedown', onMouseDown, true)
-        subs.add(sub = new Disposable(removeListener))
-        editor.onDidDestroy -> subs.remove(sub)
+    onMouseDown = @onMouseDown.bind(this)
+    subs.add atom.workspace.observeTextEditors (editor) ->
+      editor.element.addEventListener('mousedown', onMouseDown, true)
+      removeListener = -> editor.element.removeEventListener('mousedown', onMouseDown, true)
+      subs.add(sub = new Disposable(removeListener))
+      editor.onDidDestroy -> subs.remove(sub)

   isControlBarElementClick: (event) ->
     editor = event.currentTarget.getModel()


listen for 'error' events from sclang and render them

--- lib/repl.coffee
+++ lib/repl.coffee
@@ -83,6 +83,9 @@
           d = d.replace(sc3, '')
           @bus.push("
#{d}
")

+        @sclang.on 'error', (err) =>
+          @bus.push rendering.renderError(err, null)
+
         onBoot = () =>
           @sclang.initInterpreter()
                       .then(pass, fail)


Fix HTTP request timing metrics

Fix HTTP request timing metrics

The conversion between high resolution time and milliseconds was
incorrect.

--- http.coffee
+++ http.coffee
@@ -11,7 +11,7 @@
 		res.end = () ->
 			end.apply(this, arguments)
 			responseTime = process.hrtime(startTime)
-			responseTimeMs = Math.round(responseTime[0] * 1000 + responseTime[1] / 1000)
+			responseTimeMs = Math.round(responseTime[0] * 1000 + responseTime[1] / 1000000)
 			requestSize = parseInt(req.headers["content-length"], 10)
 			if req.route?.path?
 				routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1)


fixing additional problem with visiting dash and logging in

Former-commit-id: 10e2ff6b77c26f3f6a36828f95c80f7db24b7364 [formerly 256c2606268f0d711d9b1e9b458b685447af7755] [formerly 3a76aff2499218fe17603acf6c2da80059ea542c [formerly 3a76aff2499218fe17603acf6c2da80059ea542c [formerly f99b48d70be72386d8bfd3a2364c6032891c779a]]]
Former-commit-id: f9eed61ebe89a9a05ec933addfdbcd4e678aeae7 [formerly 59c2c4cefb4341472049c2b1ea0ec475fb1627b1]
Former-commit-id: bf64eaeee850aa5adb1732fd7d823c18449fe2c2
Former-commit-id: f152cc6070ddbc8ab611ff30287d00e7447a991b

--- app/assets/javascripts/backbone/apps/dash/_dash_controller.coffee
+++ app/assets/javascripts/backbone/apps/dash/_dash_controller.coffee
@@ -9,8 +9,8 @@
         @sidebar.render() if @sidebar

       App.vent.on 'user:signin', =>
-        @layout.mainRegion.currentView.render() if @layout.mainRegion.currentView
-        @layout.sidebarRegion.currentView.render() if @layout.sidebarRegion.currentView
+        @layout.mainRegion.currentView.render() if @layout.mainRegion && @layout.mainRegion.currentView
+        @layout.sidebarRegion.currentView.render() if @layout.sidebarRegion && @layout.sidebarRegion.currentView

       App.vent.on 'user:signout', =>
         @layout.close()


ssl setup

ssl setup