More validations

More validations

--- app/controllers/interactive/graphs.coffee
+++ app/controllers/interactive/graphs.coffee
@@ -115,21 +115,33 @@

     # Validation
     switch @options.graphType
-      when "histogram"
-        xaxis_el = $('#x-axis')
-        unless xaxis_el.val()
-          xaxis_el.addClass 'error'
+      when 'histogram'
+        unless $('#x-axis').val()
+          $('#x-axis').addClass 'error'
           return
         else
-          xaxis_el.removeClass 'error'
+          $('#x-axis').removeClass 'error'
+      when 'scatterplot'
+        unless $('#x-axis').val()
+          $('#x-axis').addClass 'error'
+          return
+        else
+          $('#x-axis').removeClass 'error'
+
+        unless $('y-axis').val()
+          $('#y-axis').addClass 'error'
+          return
+        else
+          $('#y-axis').removeClass 'error'

     unless @options.sampleSize
       $('#sample-size').addClass 'error'
       return
     else
       $('#sample-size').removeClass 'error'
-
-
+    # End validation
+
+    # Clear previous graph
     @el.find('svg').empty()

     switch @options.graphType


add function randomLetter

add function randomLetter

--- cf/spell.coffee
+++ cf/spell.coffee
@@ -34,9 +34,11 @@
   emptyInput = () ->
     $("input#input_answer").val("")

+  randomLetter = () ->
+    n = Math.floor(Math.random * @current.length)
   revealLetter = () ->
     i = randomLetter()
-
+
   update_keyHandler = () ->
     $("#input_answer").off()
     $("#input_answer").keydown((e) =>


Remove collection2 definitions builder function

--- timestampable.coffee
+++ timestampable.coffee
@@ -21,12 +21,6 @@
     addAfDefs = (definition) ->
       _.extend definition, afDefinition

-    c2Definition =
-      denyInsert: true
-
-    addC2Defs = (definition) ->
-      _.extend definition, c2Definition
-
     definition = {}

     if createdAt
@@ -48,22 +42,20 @@

     if updatedAt
       def = definition[updatedAt] =
+        denyInsert: true
         optional: true
         type: Date

       addAfDefs def if af?

-      addC2Defs def
-
     if updatedBy
       def = definition[updatedBy] =
+        denyInsert: true
         optional: true
         regEx: regEx
         type: String

       addAfDefs def if af?
-
-      addC2Defs def

     @collection.attachSchema new SimpleSchema definition


Updating the weather to a dark sky based script

--- scripts/weather.coffee
+++ scripts/weather.coffee
@@ -1,99 +1,58 @@
-# Description:
-#   Returns weather information from Forecast.io with a sprinkling of Google maps.
+# Description
+#   Grabs the current forecast from Dark Sky
 #
-# Configuration:
-#   HUBOT_WEATHER_CELSIUS - Display in celsius
-#   HUBOT_FORECAST_API_KEY - Forecast.io API Key
+# Dependencies
+#   None
+#
+# Configuration
+#   HUBOT_DARK_SKY_API_KEY
+#   HUBOT_DARK_SKY_DEFAULT_LOCATION
+#   HUBOT_DARK_SKY_UNITS (optional - us, si, ca, or uk)
 #
 # Commands:
-#   hubot weather <city> - Get the weather for a location.
-#   hubot forecast <city> - Get the 3 day forecast for a location.
-#   hubot forecast - Get the 3 day forecast for a location.
+#   hubot weather - Get the weather for HUBOT_DARK_SKY_DEFAULT_LOCATION
+#   hubot weather <location> - Get the weather for <location>
+#
+# Notes:
+#   If HUBOT_DARK_SKY_DEFAULT_LOCATION is blank, weather commands without a location will be ignored
 #
 # Author:
-#   markstory
-#   mbmccormick
-#   bmnick
-env = process.env
+#   kyleslattery
+module.exports = (robot) ->
+  robot.respond /weather ?(.+)?/i, (msg) ->
+    location = msg.match[1] || process.env.HUBOT_DARK_SKY_DEFAULT_LOCATION
+    return if not location

-forecastIoUrl = 'https://api.forecast.io/forecast/' + process.env.HUBOT_FORECAST_API_KEY + '/'
-googleMapUrl = 'http://maps.googleapis.com/maps/api/geocode/json'
+    googleurl = "http://maps.googleapis.com/maps/api/geocode/json"
+    q = sensor: false, address: location
+    msg.http(googleurl)
+      .query(q)
+      .get() (err, res, body) ->
+        result = JSON.parse(body)

-lookupAddress = (msg, location, cb) ->
-  msg.http(googleMapUrl).query(address: location, sensor: true)
+        if result.results.length > 0
+          lat = result.results[0].geometry.location.lat
+          lng = result.results[0].geometry.location.lng
+          darkSkyMe msg, lat,lng , (darkSkyText) ->
+            response = "Weather for #{result.results[0].formatted_address}\n#{darkSkyText}"
+            msg.send response
+        else
+          msg.send "Couldn't find #{location}"
+
+darkSkyMe = (msg, lat, lng, cb) ->
+  url = "https://api.forecast.io/forecast/#{process.env.HUBOT_DARK_SKY_API_KEY}/#{lat},#{lng}/"
+  if process.env.HUBOT_DARK_SKY_UNITS
+    url += "?units=#{process.env.HUBOT_DARK_SKY_UNITS}"
+  msg.http(url)
     .get() (err, res, body) ->
-      try
-        body = JSON.parse body
-        coords = body.results[0].geometry.location
-      catch err
-        err = "Could not find #{location}"
-        return cb(msg, null, err)
-      cb(msg, coords, err)
+      result = JSON.parse(body)

-lookupWeather = (msg, coords, err) ->
-  return msg.send err if err
-  return msg.send "You need to set env.HUBOT_FORECAST_API_KEY to get weather data" if not env.HUBOT_FORECAST_API_KEY
+      if result.error
+        cb "#{result.error}"
+        return

-  url = forecastIoUrl + coords.lat + ',' + coords.lng
-
-  msg.http(url).query(units: 'ca').get() (err, res, body) ->
-    return msg.send 'Could not get weather data' if err
-    try
-      body = JSON.parse body
-      current = body.currently
-    catch err
-      return msg.send "Could not parse weather data."
-    humidity = (current.humidity * 100).toFixed 0
-    temperature = getTemp(current.temperature)
-    text = "It is currently #{temperature} #{current.summary}, #{humidity}% humidity"
-    msg.send text
-
-lookupForecast = (msg, coords, err) ->
-  return msg.send err if err
-  return msg.send "You need to set env.HUBOT_FORECAST_API_KEY to get weather data" if not env.HUBOT_FORECAST_API_KEY
-
-  url = forecastIoUrl + coords.lat + ',' + coords.lng
-  msg.http(url).query(units: 'ca').get() (err, res, body) ->
-    return msg.send 'Could not get weather forecast' if err
-    try
-      body = JSON.parse body
-      forecast = body.daily.data
-      today = forecast[0]
-      tomorrow = forecast[1]
-      dayAfter = forecast[2]
-    catch err
-      return msg.send 'Unable to parse forecast data.'
-    text = "The weather for:\n"
-
-    appendText = (text, data) ->
-      dateToday = new Date(data.time * 1000)
-      month = dateToday.getMonth() + 1
-      day = dateToday.getDate()
-      humidity = (data.humidity * 100).toFixed 0
-      maxTemp = getTemp data.temperatureMax
-      minTemp = getTemp data.temperatureMin
-
-      text += "#{month}/#{day} - High of #{maxTemp}, low of: #{minTemp} "
-      text += "#{data.summary} #{humidity}% humidity\n"
-      text
-
-    text = appendText text, today
-    text = appendText text, tomorrow
-    text = appendText text, dayAfter
-    msg.send text
-
-getTemp = (c) ->
-  if env.HUBOT_WEATHER_CELSIUS
-    return c.toFixed(0) + "ºC"
-  return ((c * 1.8) + 32).toFixed(0) + "ºF"
-
-
-module.exports = (robot) ->
-
-  robot.respond /weather(?: me|for|in)?\s(.*)/i, (msg) ->
-    location = msg.match[1]
-    lookupAddress(msg, location, lookupWeather)
-
-  robot.respond /forecast(?: me|for|in)?\s(.*)/i, (msg) ->
-    location = msg.match[1]
-    lookupAddress(msg, location, lookupForecast)
+      response = "Currently: #{result.currently.summary} (#{result.currently.temperature}°)"
+      response += "\nToday: #{result.hourly.summary}"
+      response += "\nComing week: #{result.daily.summary}"
+      cb response
+


Added some utility functions, removed modal in library

--- src/provider.coffee
+++ src/provider.coffee
@@ -199,55 +199,29 @@
         ###
         forms = @forms
         reindexFormObject = @reindexFormObject
-        $modal = $injector.get '$modal'
-        id = @forms[name][index].id
-        elems = []
-        for key,value of @forms
-          value.forEach (elem) ->
-            if elem.id isnt id and elem.logic and elem.logic.component and angular.fromJson(elem.logic.component).id is id
-              elems.push elem
-        if elems.length >= 0
-          modal = $modal.open({
-            template: """
-

-              <form ng-submit="$close()">
-

-                  ×Close
-
-
Delete Component?

-

-

-
Warning!
You are about to delete this element!

-
Warning!
The following elements are logically dependent on the element you are trying to delete!

-

-

-                      {{elem.label}}
-

-

-

-

-                  <btn class="btn btn-default pull-left" ng-click="$dismiss()">Cancel</btn>
-                  <input type="submit" class="btn btn-primary pull-right" value="OK"></input>
-

-              </form>
-

-            """,
-            controller: ($scope, $modal) ->
-              $scope.elems = elems
-            elems: () ->
-              elems
-            })
-
-          modal.result.then () ->
-            elems.forEach (elem) ->
-              elem.logic = {action: 'Hide'}
-            formObjects = forms[name]
-            formObjects.splice index, 1
-            reindexFormObject name
-        else
-          formObjects = forms[name]
-          formObjects.splice index, 1
-          reindexFormObject name
+        formObjects = forms[name]
+        formObjects.splice index, 1
+        reindexFormObject name
+
+    @clearForm = (name) =>
+        ###
+        Clears all components from the form object.
+        @param name: The form name.
+        ###
+        forms = @forms
+        formObjects = @forms[name]
+        formObjects.splice 0, formObjects.length
+        @reindexFormObject name
+
+    @loadFromArray = (name, formObjects) =>
+        ###
+        Adds a list of objects to the specified form
+        @param name: The form name.
+        @param formObjects: The form compoennts to add.
+        ###
+        forms = @forms
+        for component of formObjects
+          addFormObject(name, component)

     @updateFormObjectIndex = (name, oldIndex, newIndex) =>
         ###
@@ -261,6 +235,23 @@
         formObject = formObjects.splice(oldIndex, 1)[0]
         formObjects.splice newIndex, 0, formObject
         @reindexFormObject name
+
+    @resetProviderData = () =>
+        ###
+        Clears the data of this provider. Resets as if forst load.
+        ###
+        $injector = null
+        $http = null
+        $templateCache = null
+        @config =
+            popoverPlacement: 'right'
+            max_id: 0
+        @components = {}
+        @groups = []
+        @broadcastChannel =
+            updateInput: '$updateInput'
+        @skipLogicComponents = []
+        @forms = {}

     # ----------------------------------------
     # $get


Framework: fix jquery install.

Framework: fix jquery install.

--- src/framework/index.coffee
+++ src/framework/index.coffee
@@ -19,4 +19,4 @@
 		done()

 Generator::dependencies = ->
-	@installFromBower 'jquery'
+	@installFromBower ['jquery']


nothing

nothing


Fix push src reference

Fix push src reference

Apparently libgit2 does not support commit ids as a src ref even though
git command line does.

--- lib/git.coffee
+++ lib/git.coffee
@@ -74,6 +74,14 @@
     .catch (err) ->
       reject "Commit #{err}"

+tag = (repo, oid) ->
+  new Promise (resolve, reject) ->
+    repo.creatLightWeightTag oid, "#{oid}-tag"
+    .then (reference) ->
+      resolve reference
+    .catch (err) ->
+      reject "Tag #{err}"
+
 push = (repo, src, dst) ->
   new Promise (resolve, reject) ->
     repo.getRemote 'origin'
@@ -135,7 +143,9 @@
     .then () ->
       commit opts.repo, opts.user, opts.message
     .then (oid) ->
-      push opts.repo, oid, opts.branch
+      tag opts.repo, oid
+    .then (tag) ->
+      push opts.repo, tag, opts.branch
     .then () ->
       newPullRequest opts.message, opts.branch
     .then (pr) ->


Refactor  `dir` function in git.coffee

Refactor  `dir` function in git.coffee

--- lib/git.coffee
+++ lib/git.coffee
@@ -133,12 +133,10 @@
 #
 # @param andSubmodules boolean determining whether to account for submodules
 dir = (andSubmodules=true) ->
-  found = false
   if andSubmodules
     if submodule = getSubmodule()
       return submodule.getWorkingDirectory()
-  if not found
-    return getRepo()?.getWorkingDirectory() ? atom.project.getPath()
+  return getRepo()?.getWorkingDirectory() ? atom.project.getPath()

 # returns filepath relativized for either a submodule or repository
 #   otherwise just a full path


Add number support

Add number support

--- src/reactive.coffee
+++ src/reactive.coffee
@@ -723,7 +723,7 @@
         if classes
           atts.class = (cls.replace(/^\./, '') for cls in classes).join(' ')
         atts
-
+

     rxt.mktag = mktag = (tag) ->
       (arg1, arg2) ->
@@ -733,7 +733,7 @@
         #   (contents: Contents)
         #   (attrs: Object, contents: Contents)
         # where Contents is:
-        #   string | Element | RawHtml | $ | Array | ObsCell | ObsArray
+        #   string | number | Element | RawHtml | $ | Array | ObsCell | ObsArray
         [attrs, contents] =
           if not arg1? and not arg2?
             [{}, null]
@@ -741,7 +741,7 @@
             [arg1, arg2]
           else if _.isString(arg1) and arg2?
             [mkAtts(arg1), arg2]
-          else if not arg2? and _.isString(arg1) or arg1 instanceof Element or
+          else if not arg2? and _.isString(arg1) or _.isNumber(arg1) or arg1 instanceof Element or
               arg1 instanceof RawHtml or arg1 instanceof $ or _.isArray(arg1) or
               arg1 instanceof ObsCell or arg1 instanceof ObsArray
             [{}, arg1]
@@ -754,7 +754,7 @@
         if contents?
           toNodes = (contents) ->
             for child in contents
-              if _.isString(child)
+              if _.isString(child) or _.isNumber(child)
                 document.createTextNode(child)
               else if child instanceof Element
                 child
@@ -766,7 +766,7 @@
                 throw new Error('jQuery object must wrap a single element') if child.length != 1
                 child[0]
               else
-                throw new Error("Unknown element type in array: #{child.constructor.name} (must be string, Element, RawHtml, or jQuery objects)")
+                throw new Error("Unknown element type in array: #{child.constructor.name} (must be string, number, Element, RawHtml, or jQuery objects)")
           updateContents = (contents) ->
             elt.html('')
             if _.isArray(contents)
@@ -782,11 +782,11 @@
                     .addClass('updated-element').offset({top,left})
                     .width($(node).width()).height($(node).height())
                 setTimeout (-> $(cover).remove() for cover in covers), 2000
-            else if _.isString(contents) or contents instanceof Element or
+            else if _.isString(contents) or _.isNumber(contents) or contents instanceof Element or
                 contents instanceof RawHtml or contents instanceof $
               updateContents([contents])
             else
-              throw new Error("Unknown type for element contents: #{contents.constructor.name} (accepted types: string, Element, RawHtml, jQuery object of single element, or array of the aforementioned)")
+              throw new Error("Unknown type for element contents: #{contents.constructor.name} (accepted types: string, number, Element, RawHtml, jQuery object of single element, or array of the aforementioned)")
           if contents instanceof ObsArray
             rx.autoSub contents.onChange, ([index, removed, added]) ->
               elt.contents().slice(index, index + removed.length).remove()
@@ -894,5 +894,5 @@
     module.exports = rx
   else if root._? and root.$?
     root.rx = factory(root._, undefined, root.$)
-  else
+  else
     throw "Dependencies are not met for reactive: _ and $ not found"


Turns out you actually have to return something from a transformer.

--- api/v1/members.coffee
+++ api/v1/members.coffee
@@ -72,5 +72,6 @@
   api.v1.getMemberVotesBySession = (req, res) ->
     memberVoteImplementation db, req, res, (baseQuery) ->
       baseQuery.sessionId = req.legislativeSession._id
+      baseQuery

   api


Add: some skill effect

Add: some skill effect


Fix bug with missing fat arrow

Fix bug with missing fat arrow

--- src/reporter.coffee
+++ src/reporter.coffee
@@ -21,7 +21,7 @@
       promise

     _determineTransport: ->
-      BrowserHelper.checkImages().then (images_enabled)->
+      BrowserHelper.checkImages().then (images_enabled)=>
         @transport = 'script' unless images_enabled

     _enableProperJobHandler: =>


Tweak code-of-conduct message (trying to link to #presentaciones channel): rollback to msg.reply welcomeMsg('')

--- scripts/welcome-to-zihub.coffee
+++ scripts/welcome-to-zihub.coffee
@@ -61,14 +61,14 @@
       add_nicks user.name

   robot.respond /la bienvenida/i, (msg) ->
-#    msg.reply welcomeMsg('')
+    msg.reply welcomeMsg('')
 #    msg.reply 'hola #presentaciones # \#general \\#general \\\#general '
 #    robot.adapter.client.web.postMessage(msg.message.room, welcomeMsg(''), {as_user: true, link_names: true})
 #    robot.adapter.client.chat.postMessage(msg.mes   sage.room, welcomeMsg(''), {as_user: true, link_names: true})

-    robot.adapter.client._apiCall("chat.postMessage", {
-      channel: msg.message.rawMessage.channel,
-      text: welcomeMsg(''),
-      as_user: true
-    })
+#    robot.adapter.client._apiCall("chat.postMessage", {
+#      channel: msg.message.rawMessage.channel,
+#      text: welcomeMsg(''),
+#      as_user: true
+#    })


Zmq error handling

Zmq error handling


Force reload of all machines on server reconnect

--- public/js/models/Machine.coffee
+++ public/js/models/Machine.coffee
@@ -58,6 +58,7 @@
 socket = io('/machines')
 socket.on 'initial-list', (machines) ->
   console.log 'initial-list', machines
+  Machine.list.set []
   Machine.list.set machines.map (m) -> new Machine m
   Machine.list.trigger 'ready'
   Machine.ready = (fn) -> fn()


Nodejs: metrics: use on-finished and remove timer instance

--- servers/datadog.coffee
+++ servers/datadog.coffee
@@ -1,5 +1,5 @@
-onHeaders            = require 'on-headers'
-{ MetricsBase }      = require 'koding-datadog'
+onFinished      = require 'on-finished'
+{ MetricsBase } = require 'koding-datadog'

 module.exports = class MetricsMiddleware extends MetricsBase

@@ -9,7 +9,6 @@
   @sanitizeMetricName : (string) ->

     return string
-      .replace /\/$/g,                 'home'  # replace last / with home
       .replace /[\/-]/g,               '.'     # replace all / with .
       .replace /\.{2,}/g,              '.'     # remove adjacent dots
       .replace /[^a-zA-Z0-9_\.]/g,     '_'     # replace invalid chars with _
@@ -22,6 +21,7 @@
       when req?.route?              then req.route.path
       else                               req.path

+    path = 'home'  if path is '/'
     @sanitizeMetricName "#{@prefix}.#{path}"

@@ -35,7 +35,7 @@
     return tags

-  @metricsOnHeaders : (opts) ->
+  @metricsOnFinished : (opts) ->

     return {
       increment         :
@@ -47,13 +47,13 @@

   @send : (req, res, next) =>

-    timer = new @timer
+    start = new Date()

-    onHeaders res, =>
+    onFinished res, =>
       metricName  = @generateName req
       tags        = @populateTags req, res
-      elapsedTime = timer.getElapsedTimeInMilliSecs()
-      @sendMetrics @metricsOnHeaders({ elapsedTime }), metricName, tags
+      elapsedTime = new Date() - start
+      @sendMetrics @metricsOnFinished({ elapsedTime }), metricName, tags

     next()


Load random source data

Load random source data

--- src/javascript/main.coffee
+++ src/javascript/main.coffee
@@ -21,8 +21,6 @@
 CharacterFacts = require './character_facts'

 dom = React.DOM
-
-source_json = './sampledata/null_pvp.json'

 samples = [
   'dscan.json'
@@ -117,10 +115,12 @@
         name: 'Bellatroix'
         id: 1412571394
       year: 2014
-      source: source_json
     }
   componentDidMount: ->
-    $.get @state.source, (data) =>
+    @loadData()
+  loadData: ->
+    source = _.sample samples
+    $.get "./sampledata/#{source}", (data) =>
       stats = new CharacterStats(data)
       @setState {stats: stats, year: data.aggregateYear}
   render: ->
@@ -308,7 +308,7 @@
     speedOfLightAu = speedKmPerS / 149597871
     totalAu = @props.distance
     travelSeconds = totalAu / speedOfLightAu
-    lightSpeedYears = Intl.NumberFormat().format(Math.round(travelSeconds / 60 / 60 / 24/ 365))
+    lightSpeedYears = Intl.NumberFormat().format(d3.round(travelSeconds / 60 / 60 / 24/ 365, 1))
     distanceText = "#{@state.vehicle.name} would take #{lightSpeedYears} years to cover your total distance travelled."
     dom.h4 {className: 'pull-right'}, dom.em(null,distanceText)
 )


fix a stupid mistake

fix a stupid mistake

--- salvus/page/projects.cjsx
+++ salvus/page/projects.cjsx
@@ -1059,5 +1059,5 @@

 top_navbar.on 'switch_from_page-projects', () ->
     window.history.pushState('', '', window.salvus_base_url + '/projects')
-    require('async').next(unmount)
-
+    setTimeout(unmount,50)
+


:art:

:art:

--- src/keyboard-layout.coffee
+++ src/keyboard-layout.coffee
@@ -1,5 +1,5 @@
 {Emitter} = require 'event-kit'
-{KeyboardLayoutObserver} = require('../build/Release/keyboard-layout-observer.node')
+{KeyboardLayoutObserver} = require '../build/Release/keyboard-layout-observer.node'

 emitter = new Emitter
 observer = new KeyboardLayoutObserver -> emitter.emit 'did-change-current-keyboard-layout', getCurrentKeyboardLayout()


better wording

better wording

--- src/steroids.coffee
+++ src/steroids.coffee
@@ -75,7 +75,7 @@

     errorCb = (err)=>
       if err.message.match /EADDRINUSE/
-        util.log "ERROR: Port #{selectedPort} is already in use. You probably have another `steroids connect` command running already."
+        util.log "ERROR: Port #{selectedPort} is already in use. You probably have an another `steroids` command running already in that port?"
         process.exit 1
       else
         throw err


Fix CSV/SSV/etc. parsing (was crashing)

Fix CSV/SSV/etc. parsing (was crashing)

Bug fix from code cleanup in 826a1c46ef99aa0253078531477c9b28332676fb

--- src/svgtiler.coffee
+++ src/svgtiler.coffee
@@ -521,7 +521,7 @@
       data = data[...-1]
     ## CSV parser.
     @load require('csv-parse/lib/sync') data,
-      delimiter: @delimiter
+      delimiter: @constructor.delimiter
       relax_column_count: true

 class SSVDrawing extends DSVDrawing


Fixed loading issue of files

Fixed loading issue of files

--- src/lib/models/file.coffee
+++ src/lib/models/file.coffee
@@ -337,7 +337,7 @@
 			file.set({fullPath})

 		# Log
-		file.log('debug', "Loading the file: #{filePath}")
+		file.log('notice', "Loading the file: #{fullPath}")

 		# Async
 		tasks = new balUtil.Group (err) =>
@@ -351,6 +351,7 @@

 		# Read the data if it is set
 		tasks.push (complete) ->
+			file.log('notice', "Data check for: #{fullPath}")
 			data = file.getData()
 			if data
 				buffer = new Buffer(data)
@@ -361,7 +362,8 @@

 		# Stat the file and cache the result
 		tasks.push (complete) ->
-			return complete()  if file.getStat()
+			file.log('notice', "Stat check for: #{fullPath}")
+			#return complete()  if file.getStat()
 			balUtil.stat fullPath, (err,fileStat) ->
 				return complete(err)  if err
 				file.setStat(fileStat)
@@ -369,7 +371,9 @@

 		# Read the file and cache the result
 		tasks.push (complete) ->
-			return complete()  if file.getBuffer()
+			file.log('notice', "Read check for: #{fullPath}")
+			#return complete()  if file.getBuffer()
+			file.log('notice', "Read check blah: #{fullPath}")
 			balUtil.readFile fullPath, (err,buffer) ->
 				return complete(err)  if err
 				file.setBuffer(buffer)


Increment offset before running plugins.

--- src/telegram.coffee
+++ src/telegram.coffee
@@ -247,6 +247,8 @@
                         for msg in result
                             # Increment the current offset
                             @offset = msg.update_id
+
+                        for msg in result
                             self.handleUpdate msg

             , @interval


make @req extend request data with the editor context so that calling code doesn't have to bother with it when augmenting with more values

--- lib/omni-sharp-server/omni.coffee
+++ lib/omni-sharp-server/omni.coffee
@@ -2,13 +2,12 @@
 rp = require "request-promise"
 Url = require "url"
 _ = require "underscore"
-$ = require "jquery"

 module.exports =

   class Omni

-    @getEditorRequestContext: ->
+    @getEditorContext: ->
       editor = atom.workspace.getActiveEditor()
       marker = editor.getCursorBufferPosition()

@@ -29,29 +28,24 @@
         query: query

     @req: (path, event, d) =>
-      context = @getEditorRequestContext()
-      r =
-        column: context.column
-        filename: context.filename
-        line: context.line
-        buffer: context.buffer
-      form = if d then d else r
+      context = @getEditorContext()
       rp
         uri: @_uri path
         method: "POST"
-        form: form
+        form: _.extend({}, context, d)
       .then (data) ->
         json = JSON.parse(data)
         atom.emit "omni:#{event}", json
         json
-      .catch (data) -> console.error(data.statusCode?, data.options?.uri)
+      .catch (data) -> console.error data.statusCode?, data.options?.uri

     @syntaxErrors: => @req "syntaxErrors", "syntax-errors"

     @goToDefinition: => @req "gotoDefinition", "navigate-to"

     @autocomplete: (wordToComplete) =>
-      data = @getEditorRequestContext()
-      data.wordToComplete = wordToComplete
-      data.wantDocumentationForEveryCompletionResult = false
+      data =
+        wordToComplete: wordToComplete
+        wantDocumentationForEveryCompletionResult: false
+
       @req "autocomplete", "autocomplete", data


Rename .write() to writeSync()

Rename .write() to writeSync()

--- lib/package-generator-view.coffee
+++ lib/package-generator-view.coffee
@@ -72,7 +72,7 @@
       if fsUtils.isFileSync(templateChildPath)
         fsUtils.makeTree(path.dirname(sourcePath))
         content = @replacePackageNamePlaceholders(fsUtils.read(templateChildPath), packageName)
-        fsUtils.write(sourcePath, content)
+        fsUtils.writeSync(sourcePath, content)

   replacePackageNamePlaceholders: (string, packageName) ->
     placeholderRegex = /__(?:(package-name)|([pP]ackageName)|(package_name))__/g


tooltips: get rid of some debug code

tooltips: get rid of some debug code

--- src/tooltips.coffee
+++ src/tooltips.coffee
@@ -44,8 +44,6 @@
               posX = mouseX - tipbox_width/2.0
               posY = mouseY + pad

-          console.log("#{direction} (#{mouseX},#{mouseY}) (#{posX},#{posY})")
-
           tipdiv.style("left", "#{posX}px")
                 .style("top", "#{posY}px")
                 .transition()


Returned data isn't encoded, must be string

--- src/user/login.cjsx
+++ src/user/login.cjsx
@@ -38,7 +38,6 @@
     return unless @isMounted()
     try
       json = JSON.parse(msg.data)
-      return unless msg.source.name is 'OxAccountIframe'
       for method, payload of json.data
         if @[method]
           @[method](payload)


fix goal index parsing

fix goal index parsing

--- lib/stream/execute-command.coffee
+++ lib/stream/execute-command.coffee
@@ -37,14 +37,19 @@

       when 'info-action: all goals'

+        indices = []
+
         # no more goals, all good
         if command.content.length is 0
           @agda.panelView.setStatus 'No Goals', 'success'
         else
           @agda.panelView.setStatus 'Goals', 'info'
+          # refresh holes with given goals
+          indices = command.content
+            .map (goal) => /^\?(\d+)\s\:\s/.exec(goal)
+            .filter (result) => result isnt null
+            .map (result) => result[1]

-        # refresh holes with given goals
-        indices = command.content.map (goal) => parseInt /^\?(\d+)\s\:\s/.exec(goal)[1]
         @agda.panelView.setContent command.content
         @agda.holeManager.resetGoals indices


add include variant

add include variant

--- snippets/includes.cson
+++ snippets/includes.cson
@@ -1,7 +1,13 @@
 '.source.c.scumm':
+  'include scummVars6.s':
+    'prefix': 'include scummVars6'
+    'body': '#include <scummVars6.s>'
+  'include scummVars7.s':
+      'prefix': 'include scummVars7'
+      'body': '#include <scummVars7.s>'
   'scummVars6.s':
     'prefix': 'scummVars6'
     'body': '#include <scummVars6.s>'
   'scummVars7.s':
       'prefix': 'scummVars7'
-      'body': '#include <scummVars7.s>'+      'body': '#include <scummVars7.s>'


fixed function syntax back to pre es6 for consistency issues with existing project

--- snippets/snippets.cson
+++ snippets/snippets.cson
@@ -1,34 +1,34 @@
-".source.js":
-  "mocha describe":
-    "prefix": "describe"
-    "body": "describe('$1', () => {\n\t$2\n});\n$3"
-  "mocha context":
-    "prefix": "context"
-    "body": "context('$1', () => {\n\t$2\n});\n$3"
-  "mocha it":
-    "prefix": "it"
-    "body": "it('$1', () => {\n\t$2\n});\n$3"
-  "mocha specify":
-    "prefix": "specify"
-    "body": "specify('$1', () => {\n\t$2\n});\n$3"
-  "mocha before":
-    "prefix": "before"
-    "body": "before(() => {\n\t$2\n});\n$3"
-  "mocha after":
-    "prefix": "after"
-    "body": "after(() => {\n\t$2\n});\n$3"
-  "mocha beforeEach":
-    "prefix": "beforeEach"
-    "body": "beforeEach(() => {\n\t$2\n});\n$3"
-  "mocha afterEach":
-    "prefix": "afterEach"
-    "body": "afterEach(() => {\n\t$2\n});\n$3"
-  "mocha pending":
-    "prefix": "pending"
-    "body": "it('$1');"
-  "mocha retries":
-    "prefix": "retries"
-    "body": "this.retries(${1:integer});"
-  "mocha timeout":
-    "prefix": "timeout"
-    "body": "this.timeout(${1:milliseconds});"
+'.source.js':
+  'mocha describe':
+    'prefix': 'describe'
+    'body': 'describe("$1", function(){\n\t$2\n});\n$3'
+  'mocha context':
+    'prefix': 'context'
+    'body': 'context("$1", function(){\n\t$2\n});\n$3'
+  'mocha it':
+    'prefix': 'it'
+    'body': 'it("$1", function(){\n\t$2\n});\n$3'
+  'mocha specify':
+    'prefix': 'specify'
+    'body': 'specify("$1", function(){\n\t$2\n});\n$3'
+  'mocha before':
+    'prefix': 'before'
+    'body': 'before(function(){\n\t$2\n});\n$3'
+  'mocha after':
+    'prefix': 'after'
+    'body': 'after(function(){\n\t$2\n});\n$3'
+  'mocha beforeEach':
+    'prefix': 'beforeEach'
+    'body': 'beforeEach(function(){\n\t$2\n});\n$3'
+  'mocha afterEach':
+    'prefix': 'afterEach'
+    'body': 'afterEach(function(){\n\t$2\n});\n$3'
+  'mocha pending':
+    'prefix': 'pending'
+    'body': 'it("$1");'
+  'mocha retries':
+    'prefix': 'retries'
+    'body': 'this.retries(${1:integer});'
+  'mocha timeout':
+    'prefix': 'timeout'
+    'body': 'this.timeout(${1:milliseconds});'


implement ambivalent (s/c and s with same code) code usage for translation toolkit

--- library/exposure/localized.coffee
+++ library/exposure/localized.coffee
@@ -87,23 +87,49 @@
             send setup, (f) -> @setupTranslationTools = f
             (inline -> @setupTranslationTools()); next()

+    # A routine intended for server side execution inside of the
+    # services that need to use the translation toolkit during the
+    # server side operations, such as context rendering and alike.
+    # This routine internally uses the same code that is used when
+    # the translation toolkit is loaded on the client side. Method
+    # implements some of the necessary scaffolding to invoke that
+    # same code in the standalone, server side environment itself.
+    this::i18n = this::withTranslation = (implement) ->
+        noImplement = "have no implementation function"
+        noIsolation = "the source scope is not isolated"
+        assert _.isFunction(implement or 0), noImplement
+        assert _.isObject(@request or null), noIsolation
+        assert silence = (message) -> # empty logging fn
+        assert ident = @constructor.identify().underline
+        assert notify = "Translation scope in %s for %s"
+        counts = "Offload %s translations in %s into %s"
+        assert this.session = @request.session or Object()
+        this.setupTranslationTools silence, (lng, msg) =>
+            assert not _.isEmpty(lng), "got no language"
+            assert _.isObject(msg), "got no translation"
+            assert count = _.keys(msg).length.toString()
+            try logger.debug notify.grey, lng.bold, ident
+            try logger.debug counts.grey, count.bold, lng
+            return implement.apply this, arguments
+
     # An automatically called external routine that will take care
     # of setting up the client site part of the translation toolkit.
     # This implementation requests the necessary translation tables
     # off the server provider. Once is acknowledged, a client side
     # routines are setup and associated with the language and table.
-    setupTranslationTools: @awaiting "booted", (force) ->
+    setupTranslationTools: @awaiting "booted", (log, ack) ->
         unexpected = "received malformed translation"
         unrecognized = "unrecognized language received"
         noted = "loaded %s translation messages for %s"
         sel = "using %s as the language selector for %s"
-        return if _.isFunction(@t) and force isnt true
+        return if _.isFunction @t # do not double call
+        assert loggingRoutine = try log or logger.info
         assert _.isFunction sprintf = _.sprintf # format
         pt = (o, v, key) -> delete o[key]; o[lc key] = v
         lc = (src) => return src.toString().toLowerCase()
         rx = (src) => @translationMessages?[lc src] or src
         try _.transform this.translationMessages or 0, pt
-        logger.info "installing the translation tookit"
+        loggingRoutine "installing the translation tookit"
         this.t = (s, a...) => sprintf "#{rx(s)}", a...
         this.th = (s, a...) => _.humanize this.t s, a...
         this.tt = (s, a...) => _.titleize this.t s, a...
@@ -113,8 +139,9 @@
             assert @translationMessages = translation
             assert @translationLanguage = language
             length = _.keys(translation).length
-            logger.info noted, length, @service
-            logger.info sel, language, @service
+            loggingRoutine noted, length, @service
+            loggingRoutine sel, language, @service
+            ack language, translation if ack

     # An out-of-the-box isolated provider that exposes translation
     # messages, provided by the service in the language requested.


add a handy inline

add a handy inline

--- library/membrane/preflight.coffee
+++ library/membrane/preflight.coffee
@@ -97,6 +97,8 @@
         context.inline -> `assert = chai.assert`
         context.inline -> `assert(logger = log)`
         context.inline -> try logger.enableAll()
+        context.inline -> $(document).ready =>
+            this.emit "document", document, this
         assert remotes = @constructor.remotes or []
         assert uniques = _.unique remotes or Array()
         @inject context, blob for blob in uniques


Groups: setStorageData method is added to Login controller, and called in group creation phase

--- client/landing/Login/AppController.coffee
+++ client/landing/Login/AppController.coffee
@@ -133,3 +133,9 @@
     view = @getView()
     view.headBannerShowInvitation invite

+  setStorageData: (key, value) ->
+    @appStorage = KD.getSingleton('appStorageController').storage 'Login', '1.0'
+    @appStorage.fetchStorage (storage) =>
+      @appStorage.setValue key, value, (err) ->
+        warn "Failed to set #{key} information"  if err
+


Add names for faces

Add names for faces

--- app/assets/javascripts/game_faces.js.coffee
+++ app/assets/javascripts/game_faces.js.coffee
@@ -25,17 +25,19 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
-    },
-    1: {sex: face_values['male'], glasses: null, hair: null, teeth: face_values['teeth'], beard_or_mustaches: null},
-    2: {sex: face_values['male'], glasses: null, hair: null, teeth: face_values['teeth'], beard_or_mustaches: null},
+      beard_or_mustaches: null,
+      name: 'Margarita'
+    },
+    1: {sex: face_values['male'], glasses: null, hair: null, teeth: face_values['teeth'], beard_or_mustaches: null, name: 'Peter'},
+    2: {sex: face_values['male'], glasses: null, hair: null, teeth: face_values['teeth'], beard_or_mustaches: null, name: 'John'},
     3: {
       sex: face_values['male'],
       glasses: null,
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: face_values['beard_or_mustaches']
+      beard_or_mustaches: face_values['beard_or_mustaches'],
+      name: 'Alexander'
     },
     4: {
       sex: face_values['male'],
@@ -43,16 +45,18 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
-    },
-    5: {sex: face_values['male'], glasses: null, hair: null, teeth: face_values['teeth'], beard_or_mustaches: null},
+      beard_or_mustaches: null,
+      name: 'Arnold'
+    },
+    5: {sex: face_values['male'], glasses: null, hair: null, teeth: face_values['teeth'], beard_or_mustaches: null, name: 'Boris'},
     6: {
       sex: face_values['male'],
       glasses: null,
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['pink'],
       teeth: null,
-      beard_or_mustaches: face_values['beard_or_mustaches']
+      beard_or_mustaches: face_values['beard_or_mustaches'],
+      name: 'Jakob'
     },
     7: {
       sex: face_values['male'],
@@ -60,7 +64,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['yellow'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Bruce'
     },
     8: {
       sex: face_values['female'],
@@ -68,7 +73,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['orange'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Janet'
     },
     9: {
       sex: face_values['male'],
@@ -76,7 +82,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: face_values['teeth'],
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Bogdan'
     },
     10: {
       sex: face_values['female'],
@@ -84,7 +91,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['green'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Ivanna'
     },
     11: {
       sex: face_values['male'],
@@ -92,26 +100,29 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['yellow'],
       teeth: null,
-      beard_or_mustaches: null
-    },
-    12: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null},
+      beard_or_mustaches: null,
+      name: 'Serg'
+    },
+    12: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null, name: 'Den'},
     13: {
       sex: face_values['male'],
       glasses: null,
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
-    },
-    14: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null},
-    15: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null},
+      beard_or_mustaches: null,
+      name: 'Nick'
+    },
+    14: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null, name: 'Silvester'},
+    15: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null, name: 'Brian'},
     16: {
       sex: face_values['female'],
       glasses: null,
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Samantha'
     },
     17: {
       sex: face_values['male'],
@@ -119,7 +130,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Andrew'
     },
     18: {
       sex: face_values['male'],
@@ -127,7 +139,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Walther'
     },
     19: {
       sex: face_values['male'],
@@ -135,7 +148,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['yellow'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Paul'
     },
     20: {
       sex: face_values['male'],
@@ -143,7 +157,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Daniel'
     },
     21: {
       sex: face_values['male'],
@@ -151,7 +166,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: face_values['beard_or_mustaches']
+      beard_or_mustaches: face_values['beard_or_mustaches'],
+      name: 'Mike'
     },
     22: {
       sex: face_values['male'],
@@ -159,7 +175,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Max'
     },
     23: {
       sex: face_values['male'],
@@ -167,7 +184,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: face_values['teeth'],
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Tony'
     },
     24: {
       sex: face_values['male'],
@@ -175,7 +193,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Ryan'
     },
     25: {
       sex: face_values['female'],
@@ -183,7 +202,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Agata'
     },
     26: {
       sex: face_values['male'],
@@ -191,7 +211,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['blue'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'David'
     },
     27: {
       sex: face_values['male'],
@@ -199,7 +220,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Dave'
     },
     28: {
       sex: face_values['male'],
@@ -207,7 +229,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: face_values['beard_or_mustaches']
+      beard_or_mustaches: face_values['beard_or_mustaches'],
+      name: 'Scott'
     },
     29: {
       sex: face_values['male'],
@@ -215,7 +238,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Connor'
     },
     30: {
       sex: face_values['female'],
@@ -223,7 +247,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Vanda'
     },
     31: {
       sex: face_values['male'],
@@ -231,7 +256,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Valentin'
     },
     32: {
       sex: face_values['female'],
@@ -239,18 +265,20 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
-    },
-    33: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null},
-    34: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null},
-    35: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null},
+      beard_or_mustaches: null,
+      name: 'Marina'
+    },
+    33: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null, name: 'William'},
+    34: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null, name: 'Sergio'},
+    35: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null, name: 'Nikola'},
     36: {
       sex: face_values['female'],
       glasses: face_values['glasses'],
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Helen'
     },
     37: {
       sex: face_values['female'],
@@ -258,7 +286,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['pink'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Iren'
     },
     38: {
       sex: face_values['female'],
@@ -266,7 +295,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Natali'
     },
     39: {
       sex: face_values['male'],
@@ -274,7 +304,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Clay'
     },
     40: {
       sex: face_values['male'],
@@ -282,7 +313,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['green'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Stephen'
     },
     41: {
       sex: face_values['female'],
@@ -290,7 +322,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['yellow'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Ronald'
     },
     42: {
       sex: face_values['female'],
@@ -298,7 +331,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Clarissa'
     },
     43: {
       sex: face_values['male'],
@@ -306,26 +340,29 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
-    },
-    44: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null},
+      beard_or_mustaches: null,
+      name: 'Jack'
+    },
+    44: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null, name: 'Timothy'},
     45: {
       sex: face_values['female'],
       glasses: null,
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
-    },
-    46: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null},
-    47: {sex: face_values['male'], glasses: null, hair: null, teeth: face_values['teeth'], beard_or_mustaches: null},
+      beard_or_mustaches: null,
+      name: 'Patricia'
+    },
+    46: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null, name: 'Robert'},
+    47: {sex: face_values['male'], glasses: null, hair: null, teeth: face_values['teeth'], beard_or_mustaches: null, name: 'Gedeon'},
     48: {
       sex: face_values['male'],
       glasses: null,
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: face_values['beard_or_mustaches']
+      beard_or_mustaches: face_values['beard_or_mustaches'],
+      name: 'Floyd'
     },
     49: {
       sex: face_values['male'],
@@ -333,16 +370,18 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
-    },
-    50: {sex: face_values['male'], glasses: null, hair: null, teeth: face_values['teeth'], beard_or_mustaches: null},
+      beard_or_mustaches: null,
+      name: 'George'
+    },
+    50: {sex: face_values['male'], glasses: null, hair: null, teeth: face_values['teeth'], beard_or_mustaches: null, name: 'Tom'},
     51: {
       sex: face_values['male'],
       glasses: face_values['glasses'],
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Adam'
     },
     52: {
       sex: face_values['male'],
@@ -350,26 +389,29 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
-    },
-    53: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null},
-    54: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null},
+      beard_or_mustaches: null,
+      name: 'Alan'
+    },
+    53: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null, name: 'Zak'},
+    54: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null, name: 'Vincent'},
     55: {
       sex: face_values['male'],
       glasses: face_values['glasses'],
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
-    },
-    56: {sex: face_values['male'], glasses: null, hair: null, teeth: face_values['teeth'], beard_or_mustaches: null},
+      beard_or_mustaches: null,
+      name: 'Bob'
+    },
+    56: {sex: face_values['male'], glasses: null, hair: null, teeth: face_values['teeth'], beard_or_mustaches: null, name: 'Jimmy'},
     57: {
       sex: face_values['male'],
       glasses: null,
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: face_values['teeth'],
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Richard'
     },
     58: {
       sex: face_values['male'],
@@ -377,7 +419,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Gerhard'
     },
     59: {
       sex: face_values['male'],
@@ -385,7 +428,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Bernard'
     },
     60: {
       sex: face_values['male'],
@@ -393,16 +437,18 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
-    },
-    61: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null},
+      beard_or_mustaches: null,
+      name: 'Ken'
+    },
+    61: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null, name: 'Ben'},
     62: {
       sex: face_values['female'],
       glasses: null,
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Darina'
     },
     63: {
       sex: face_values['female'],
@@ -410,7 +456,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['yellow'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Rachel'
     },
     64: {
       sex: face_values['male'],
@@ -418,7 +465,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Adrian'
     },
     65: {
       sex: face_values['female'],
@@ -426,7 +474,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Sarah'
     },
     66: {
       sex: face_values['male'],
@@ -434,7 +483,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Ben'
     },
     67: {
       sex: face_values['male'],
@@ -442,7 +492,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Viktor'
     },
     68: {
       sex: face_values['female'],
@@ -450,16 +501,18 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['pink'],
       teeth: null,
-      beard_or_mustaches: null
-    },
-    69: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null},
+      beard_or_mustaches: null,
+      name: 'Mary'
+    },
+    69: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null, name: 'Bernard'},
     70: {
       sex: face_values['female'],
       glasses: null,
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Adelina'
     },
     71: {
       sex: face_values['male'],
@@ -467,7 +520,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['brown'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Henry'
     },
     72: {
       sex: face_values['male'],
@@ -475,7 +529,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Bill'
     },
     73: {
       sex: face_values['male'],
@@ -483,7 +538,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Constantin'
     },
     74: {
       sex: face_values['female'],
@@ -491,7 +547,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Laura'
     },
     75: {
       sex: face_values['male'],
@@ -499,7 +556,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Patrick'
     },
     76: {
       sex: face_values['male'],
@@ -507,16 +565,18 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
-    },
-    77: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null},
+      beard_or_mustaches: null,
+      name: 'Erik'
+    },
+    77: {sex: face_values['male'], glasses: null, hair: null, teeth: null, beard_or_mustaches: null, name: 'Elton'},
     78: {
       sex: face_values['male'],
       glasses: null,
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: face_values['teeth'],
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Hose'
     },
     79: {
       sex: face_values['female'],
@@ -524,7 +584,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['blonde'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Kristina'
     },
     80: {
       sex: face_values['male'],
@@ -532,7 +593,8 @@
       hair: face_values['hair'],
       hair_color: face_values['hair_color']['black'],
       teeth: null,
-      beard_or_mustaches: null
+      beard_or_mustaches: null,
+      name: 'Timothy'
     },
   }


On generic open lightbox focus the first input or textarea

--- app/coffee/modules/common/lightboxes.coffee
+++ app/coffee/modules/common/lightboxes.coffee
@@ -32,6 +32,7 @@
 class LightboxService extends taiga.Service
     open: ($el) ->
         $el.css('display', 'flex')
+        $el.find('input,textarea').first().focus()
         timeout(70, -> $el.addClass("open"))

         docEl = angular.element(document)


remove unused jasmine tests

remove unused jasmine tests

--- lms/static/coffee/spec/calculator_spec.coffee
+++ lms/static/coffee/spec/calculator_spec.coffee
@@ -91,16 +91,6 @@
       $('#calculator_input_help').trigger(e);
       expect($('.help')).toHaveClass 'shown'

-  describe 'handleKeyUp', ->
-    it 'on key up of tab button on hint popup it does not hide', ->
-      calc = @calculator
-      calc.showHint()
-      e = jQuery.Event('keyup',{ keyCode: KEY.TAB })
-      $(document).activeElement = $('#hint-moreinfo')
-      calc.handleKeyUpOnHint(e)
-      expect($('.help')).toHaveClass 'shown'
-      expect(calc.active_element).toBe($('#hint-moreinfo a:first'))
-
   describe 'selectHint', ->
     it 'select correct hint item', ->
       spyOn($.fn, 'focus')


Getting close to getting transitions working

--- src/progress_circle.coffee
+++ src/progress_circle.coffee
@@ -7,8 +7,12 @@
 outerPercent = .50
 innerThickness = 10
 outerThickness = 20
+defaultArcColor = 'chartreuse'

-app.directive "progressCircle", ($parse, $window) ->
+actualArc = {}
+expectedArc = {}
+
+app.directive "progressCircle",  ->
     restrict: "EA"
     replace: true
     template: "<svg width='#{svgWidth}' height='#{svgHeight}'></svg>"
@@ -31,9 +35,9 @@
             #     .text(percent)

         # take value from 0-1 and draw arc
-        drawArc = (percent, radius, thickness, colorIsRed) ->
+        drawArc = (percent, radius, thickness, colorIsRed, arcClass) ->
             console.log("drawArc: #{percent}, #{radius}")
-            color = 'chartreuse'
+            color = defaultArcColor
             arc = d3.svg.arc()
                 .innerRadius radius - thickness
                 .outerRadius radius
@@ -41,28 +45,49 @@
                 .endAngle 2*Math.PI*percent

             if colorIsRed
-                color = 'orange'
-
+                color = 'red'
+
             arcValue = svg.append 'path'
                 .style 'fill', color
                 .attr 'd', arc
+                .attr 'class', arcClass

         drawExpectedArc = ->
-            drawArc(scope.expected, innerRadius, innerThickness, 0)
+            console.log("drawExpectedArc")
+            #d3.selectAll("svg").remove();
+            expectedArc = drawArc(attrs.expected, innerRadius, innerThickness, 0, 'expected')

         drawActualArc = ->
-            colorIsRed = arcColorIsRed(scope.actual, scope.expected)
-            drawArc(scope.actual, outerRadius, outerThickness, colorIsRed)
+            console.log("drawActualArc")
+            colorIsRed = arcColorIsRed(attrs.actual, attrs.expected)
+            actualArc = drawArc(attrs.actual, outerRadius, outerThickness, colorIsRed, 'actual')
+            drawText(attrs.actual)
+
+        drawBothArcs = ->
+            console.log("drawBothArcs")
+            drawActualArc()
+            drawExpectedArc()
+
+        transitionBothArcs = ->
+            console.log("transitionBothArcs")
+            transitionActualArc()
+            transitionExpectedArc()
+
+        transitionExpectedArc = ->
+
+
+        transitionActualArc = ->
+

         # return color based on values of actual and expected percents
         arcColorIsRed = (actualPercent, expectedPercent) ->
             console.log("arcColor: #{actualPercent}, #{expectedPercent}")
             returnVal = 0
-            console.log("checking color. actual: #{actualPercent}, #{expectedPercent}")
-            if expectedPercent - actualPercent >= 50
+            console.log("checking color: actual: #{actualPercent}, #{expectedPercent}")
+            if expectedPercent - actualPercent >= .5
                 console.log("expected 50 > actual")
                 returnVal = 1
-            if actualPercent > 25
+            if actualPercent > .25
                 console.log("actual > 25")
                 returnVal = 1

@@ -72,17 +97,13 @@
         svg = d3.select('svg')
             .append('g')
                 .attr("transform", "translate(#{svgWidth/2}, #{svgHeight/2})")
-        console.log("SVG: "+svg)
-        console.log("attrs "+attrs)
-        console.log("scope #{scope.actual}")
-        console.log("Actual #{attrs.actual}")
-        console.log("Expected #{attrs.expected}")
+        # console.log("SVG: "+svg)
+        # console.log("attrs "+attrs)
+        # console.log("scope #{scope.actual}")
+        console.log("Actual: #{attrs.actual}")
+        console.log("Expected: #{attrs.expected}")
+        drawBothArcs()
+        drawCircle(innerPercent, circleRadius)
+        scope.$watch 'expected', transitionBothArcs
+        scope.$watch 'actual', transitionBothArcs

-        scope.$watch 'expected', drawExpectedArc
-        scope.$watch 'actual', drawActualArc
-
-        # drawArc(scope.expected, innerRadius, innerThickness, 0)
-        # drawArc(scope.actual, outerRadius, outerThickness,
-        #     arcColorIsRed(scope.actual, scope.expected))
-        drawCircle(innerPercent, circleRadius)
-        drawText(scope.actual)


Fixed a bug

Fixed a bug

--- server/d2mpclient/socket.coffee
+++ server/d2mpclient/socket.coffee
@@ -72,7 +72,14 @@
             console.log "client installed unknown mod: "+modname
             return
           modname += "="+mod.version
+          toRemove = []
+          for mod in clientObj.installedMods
+            if mod.split("=")[0] is modname
+              toRemove.push(mod)
+          toRemove.unshift clientObj.installedMods
+          clientObj.installedMods = _.without.apply(_, toRemove)
           console.log "client installed "+modname
+          console.log "  -> mods: "+toRemove
           clientObj.installedMods.push(modname)
           clients.update {_id: ourID}, clientObj
     ).run()


Server: changed /WFGH routes to /Hackathon

--- servers/lib/server/index.coffee
+++ servers/lib/server/index.coffee
@@ -552,7 +552,7 @@
   return false

-app.post '/WFGH/Apply', (req, res, next)->
+app.post '/Hackathon/Apply', (req, res, next)->

   {JWFGH} = koding.models

@@ -590,7 +590,7 @@
     res.status(400).send body

-app.get '/WFGH/:section?', (req, res, next)->
+app.get '/Hackathon/:section?', (req, res, next)->

   {JGroup} = koding.models


Removed no longer needed regions

Removed no longer needed regions

--- core/app/backbone/views/react_fact.coffee
+++ core/app/backbone/views/react_fact.coffee
@@ -34,7 +34,5 @@
 window.ReactFact = React.createBackboneClass
   render: ->
     _div ['fact-view'],
-      _div ["js-fact-base-region"],
-        ReactFactBase(model: @model())
-      _div ["js-fact-link-region"],
-         ReactProxyLink(model: @model())
+      ReactFactBase(model: @model())
+      ReactProxyLink(model: @model())


Only compile changed CoffeeScript files (#7)

--- grunt/contrib-watch.coffee
+++ grunt/contrib-watch.coffee
@@ -7,7 +7,6 @@
       tasks: [
         'coffeelint'
         'coffee:dev'
-        'docco'
       ]
       options:
         livereload: true
@@ -31,5 +30,25 @@
       ]
       options:
         livereload: true
+
+  changedFiles = []
+  onChange = grunt.util._.debounce ->
+    changedCoffeeFiles = []
+
+    for filePath in changedFiles
+      fileExtension = filePath.split('.').pop()
+      if fileExtension is 'coffee'
+        changedCoffeeFiles.push filePath
+
+    if changedCoffeeFiles.length
+      grunt.config 'coffee.dev.src', changedCoffeeFiles
+      grunt.config 'coffeelint.all', changedCoffeeFiles
+
+    changedFiles = []
+  , 200
+
+  grunt.event.on 'watch', (action, filepath) ->
+    changedFiles.push filepath
+    onChange()

   grunt.loadNpmTasks 'grunt-contrib-watch'


Improve documentation

Improve documentation

--- src/scripts/harvest.coffee
+++ src/scripts/harvest.coffee
@@ -11,29 +11,46 @@
 #     you should set this to "yourcompany" (without the quotes).
 #
 # Commands:
-#   hubot remember my harvest account <email> with password <password> - Saves your Harvest credentials
-#                                                                        to allow Hubot to track time for you
-#   hubot forget my harvest account - Deletes your account credentials from Hubot's memory
-#   hubot start harvest at <project>/<task>: <notes> - Start a timer for a task at a project
-#                                                      (both of which may be abbreviated, Hubot
-#                                                      will ask you if your input is ambigious).
-#                                                      An existing timer (if any) will be stopped.
-#   hubot stop harvest [at <project>/<task>] - Stop the timer the for a task, if any.
-#                                              If no project is given, stops the first
-#                                              active timer it can find.
-#   hubot daily harvest [of <user>] - Hubot responds with your/a specific user's entries for today
-#
-#   hubot list harvest tasks - Gives you a list of all project/task combinations available to you.
-#                              You can use these for the start command.
+#   hubot remember my harvest account <email> with password <password>
+#     Saves your Harvest credentials to allow Hubot to track
+#     time for you.
+#
+#   hubot forget my harvest account
+#     Deletes your account credentials from Hubt's memory.
+#
+#   hubot start harvest at <project>/<task>: <notes>
+#     Starts a timer for a task at a project (both of which may
+#     be abbreviated, Hubot will ask you if your input is
+#     ambigious). An existing timer (if any) will be stopped.
+#
+#   hubot stop harvest [at <project>/<task>]
+#     Stops the timer for a task, if any. If no project is given,
+#     stops the first active timer it can find. The project and
+#     task arguments may be abbreviated as with start.
+#
+#   hubot daily harvest [of <user>]
+#     Hubot responds with your/a specific user's entries
+#     for today.
+#
+#   hubot list harvest tasks
+#     Gives you a list of all project/task combinations available
+#     to you. You can use these for the start command.
 #
 # Notes:
-# All commands and command arguments are case-insenitive. If you work
-# on a project "FooBar", hubot will unterstand "foobar" as well. This
-# is also true for abbreviations, so if you don't have similary named
-# projects, "foob" will do as expected.
+#   All commands and command arguments are case-insenitive. If you work
+#   on a project "FooBar", hubot will unterstand "foobar" as well. This
+#   is also true for abbreviations, so if you don't have similary named
+#   projects, "foob" will do as expected.
+#
+#   Some examples:
+#   > hubot remember my harvest account joe@example.org with password doe
+#   > hubot list harvest tasks
+#   > hubot start harvest at myproject/important-task: Some notes go here.
+#   > hubot start harvest at myp/imp: Some notes go here.
+#   > hubot daily harvest of nickofotheruser
 #
 # Author:
-#   Quintus
+#   Quintus @ Asquera

 unless process.env.HUBOT_HARVEST_SUBDOMAIN
   console.log "Please set HUBOT_HARVEST_SUBDOMAIN in the environment to use the harvest plugin script."
@@ -169,6 +186,9 @@
 # via `JSON.parse`.
 class HarvestAccount

+  # Create a new harvest account. Pass in the account's email and the
+  # password used to access harvest. These credentials are the same you
+  # use for logging into Harvest's web service.
   constructor: (email, password) ->
     @base_url = "https://#{process.env.HUBOT_HARVEST_SUBDOMAIN}.harvestapp.com"
     @email    = email


Support for triggering job with authentication

--- src/scripts/jenkins.coffee
+++ src/scripts/jenkins.coffee
@@ -7,6 +7,7 @@
 # The following variables are optional
 #   HUBOT_JENKINS_JOB: if not set you will have to specify job name every time
 #   HUBOT_JENKINS_BRANCH_PARAMETER_NAME: if not set is assumed to be BRANCH_SPECIFIER
+#   HUBOT_JENKINS_AUTH: for authenticating the trigger request (user:apiToken)
 #
 # build branch master - starts a build for branch origin/master
 # build branch master on job Foo - starts a build for branch origin/master on job Foo
@@ -25,6 +26,10 @@

     req = msg.http("#{url}/job/#{job}/build/api/json")

+    if process.env.HUBOT_JENKINS_AUTH
+      auth = new Buffer(process.env.HUBOT_JENKINS_AUTH).toString('base64')
+      req.headers Authorization: "Basic #{auth}"
+
     req.headers 'Content-Type': 'application/x-www-form-urlencoded'
     req.post("json=#{json_val}") (err, res, body) ->
         if err


:memo: Doc selector parser

:memo: Doc selector parser

--- src/selector-parser.coffee
+++ src/selector-parser.coffee
@@ -1,13 +1,8 @@
 selectorCache = null
 testElement = null

-exports.validateSelector = (selector) ->
-  return if exports.isSelectorValid(selector)
-
-  error = new Error("'#{selector}' is not a valid selector")
-  error.code = 'EBADSELECTOR'
-  throw error
-
+# Parses CSS selectors and memoizes their validity so each selector will only
+# be parsed once.
 exports.isSelectorValid = (selector) ->
   selectorCache ?= {}
   cachedValue = selectorCache[selector]
@@ -21,3 +16,11 @@
   catch selectorError
     selectorCache[selector] = false
     false
+
+# Parse the given selector and throw an error if it is invalid
+exports.validateSelector = (selector) ->
+  return if exports.isSelectorValid(selector)
+
+  error = new Error("'#{selector}' is not a valid selector")
+  error.code = 'EBADSELECTOR'
+  throw error


Fixed double-load in remote browser mode.

--- src/server/location.coffee
+++ src/server/location.coffee
@@ -40,10 +40,18 @@

     # Main navigation function, loads the page for the current location.
     reload : () ->
+        oldURL = @window.document.URL
+        if /\/$/.test(oldURL)
+            oldURL = oldURL.slice(0, oldURL.length - 1)
+        newURL = @parsed.href
+        if /\/$/.test(newURL)
+            newURL = newURL.slice(0, newURL.length - 1)
+        console.log "In reload: old url = #{oldURL} new url=#{newURL}"
         # Only load if the requested page is different.
         # This way, we can set window.location on the initial page without
         # entering an infinite loop.
-        if @parsed.href != @window.document.URL
+        if oldURL != newURL
+            console.log "old != new, loading page"
             #TODO: this breaks with pages that are loaded with a # from the start.

             # Check for hashchange


room check

room check

--- scripts/room-check.coffee
+++ scripts/room-check.coffee
@@ -1,4 +1,4 @@
 module.exports = (robot) ->
-  robot.respond /what room is this/i, (msg) ->
+  robot.respond /room check/i, (msg) ->
     msg.send msg.user.room


Better csv2object

Better csv2object

--- lib/csv2object.coffee
+++ lib/csv2object.coffee
@@ -2,6 +2,7 @@

 split = require "split"
 csv = require "csv"
+_ = require "lodash"

 csv2object = (filename, callback) ->


Allow to force an update when calling requestUpdate

--- lib/table-view.coffee
+++ lib/table-view.coffee
@@ -27,12 +27,11 @@

   getRowHeight: -> @rowHeight

-  setRowHeight: (@rowHeight) ->
-    @component.setState rowHeight: @getRowHeight()
+  setRowHeight: (@rowHeight) -> @requestUpdate(true)

   getRowOverdraw: -> @rowOverdraw or 0

-  setRowOverdraw: (@rowOverdraw) -> @requestUpdate()
+  setRowOverdraw: (@rowOverdraw) -> @requestUpdate(true)

   getFirstVisibleRow: ->
     row = Math.floor(@scrollView.scrollTop() / @getRowHeight())
@@ -53,7 +52,9 @@

     @scrollView.scrollTop()

-  requestUpdate: =>
+  requestUpdate: (forceUpdate=false) =>
+    @hasChanged = forceUpdate
+
     return if @updateRequested

     @updateRequested = true
@@ -65,7 +66,7 @@
     firstVisibleRow = @getFirstVisibleRow()
     lastVisibleRow = @getLastVisibleRow()

-    return if firstVisibleRow >= @firstRenderedRow and lastVisibleRow <= @lastRenderedRow
+    return if firstVisibleRow >= @firstRenderedRow and lastVisibleRow <= @lastRenderedRow and not @hasChanged

     firstRow = Math.max 0, firstVisibleRow - @rowOverdraw
     lastRow = Math.min @table.getRowsCount(), lastVisibleRow + @rowOverdraw
@@ -80,5 +81,6 @@

     @firstRenderedRow = firstRow
     @lastRenderedRow = lastRow
+    @hasChanged = false

   asDisposable: (subscription) -> new Disposable -> subscription.off()


Use Meteor.Error for validation errors

Use Meteor.Error for validation errors

--- src/Collections.coffee
+++ src/Collections.coffee
@@ -377,7 +377,15 @@
     # TODO(aramk) The deferred won't run in time since hooks are not asynchronous yet, so it won't
     # prevent the collection methods from being called.
     # https://github.com/matb33/meteor-collection-hooks/issues/71
-    handle = (invalid) -> throw new Error(invalid) if invalid
+    handle = (err) ->
+      return unless err
+      if err instanceof Error
+        throw new Meteor.Error(500, err.message, err.stack)
+      else if err instanceof Meteor.Error
+        throw err
+      else
+        throw new Meteor.Error(500, err)
+
     if result && result.then
       result.then(handle, handle)
     else


Fixed a bug which can cause Collections.copy() to insert blank documents when using beforeInsert().

--- src/Collections.coffee
+++ src/Collections.coffee
@@ -174,8 +174,11 @@
     insert = (srcDoc) ->
       df = Q.defer()
       if beforeInsert
-        srcDoc = beforeInsert(srcDoc)
-        return if srcDoc == false
+        resultDoc = beforeInsert(srcDoc)
+        if resultDoc == false
+          return
+        else if Types.isObjectLiteral(resultDoc)
+          srcDoc = resultDoc
       dest.insert srcDoc, Promises.toCallback(df)
       df.promise
     # Collection2 may not allow inserting a doc into a collection with a predefined _id, so we


If user puts an invalid date in the URL, don't throw an exception--just ignore and use current date

--- source/javascripts/index/schedule.js.coffee
+++ source/javascripts/index/schedule.js.coffee
@@ -5,9 +5,15 @@
 #= require ./announcement

 initialDate = ->
-  initialDate = window.location.search.replace("?", "")
-  initialDate = if initialDate.length > 0 then moment(initialDate, "YYYYMMDD").toDate() else (new Date())
-  moment(initialDate).add(12, 'hours').format("YYYY-MM-DD")
+  try
+    initialDate = window.location.search.replace("?", "")
+    initialDate = if initialDate.length > 0 then moment(initialDate, "YYYYMMDD").toDate() else (new Date())
+    result = moment(initialDate).add(12, 'hours').format("YYYY-MM-DD")
+    if "Invalid date" == result
+      throw "Invalid date"
+    end
+  catch
+    moment().format("YYYY-MM-DD")

 weekDescription = (shabbat) ->
   sedra = "#{if shabbat.isRegel() || shabbat.isYomKippur() || shabbat.isYomTob() then "" else "שַׁבַּת פְּרָשָׁת"} #{shabbat.sedra().replace(/-/g, ' - ')}"


Fix prefix code for fragment shader.

Fix prefix code for fragment shader.

--- source/javascripts/shader_lab_app.js.coffee
+++ source/javascripts/shader_lab_app.js.coffee
@@ -83,7 +83,7 @@
       "uniform mat4 viewMatrix;",
       "uniform vec3 cameraPosition;",
     ]
-    source = @editor_fragment.getValue()
+    source = prefix.join('\n') + @editor_fragment.getValue()
     [success, errors] = @threejs_scene.validator.validate_fragment(source, -prefix.length)
     if success
       @editor_fragment.getSession().clearAnnotations()


Change to use importItem

Change to use importItem

--- lib/birch-markdown.coffee
+++ lib/birch-markdown.coffee
@@ -57,5 +57,5 @@
       if markdown
         markdownToBirch ?= require './markdown-to-birch'
         markdownOutline = markdownToBirch markdown, @birchOutlineEditorService
-        importedItems = outline.importItems markdownOutline.root.children
-        outline.root.appendChildren importedItems+        for each in markdownOutline.root.children
+          outline.root.appendChild outline.importItem each


Fix broken curly brace escaping. (Fixes #62)

--- src/util/referencer.coffee
+++ src/util/referencer.coffee
@@ -241,7 +241,7 @@
         match

     # Restore curly braces within code blocks
-    text = text.replace /<code>.+?<\/code>/, (match) -> match.replace(/\u0091/mg, '{').replace(/\u0092/mg, '}')
+    text = text.replace /<code>.+?<\/code>/mg, (match) -> match.replace(/\u0091/mg, '{').replace(/\u0092/mg, '}')

   # Resolves a @see link.
   #


This is screwing up HTML generation for uppercase constants

See https://github.com/atom/biscotto/issues/39 for more information.

--- src/util/referencer.coffee
+++ src/util/referencer.coffee
@@ -210,6 +210,7 @@
         data.doc.summary = @resolveTextReferences(data.doc.summary, entity, path)

       for name, options of data.doc.options
+        continue unless options?
         for option, index in options
           data.doc.options[name][index].desc = @resolveTextReferences(option.desc, entity, path)


Better sentences.

Better sentences.

--- client/app/MainApp/paymentcontroller.coffee
+++ client/app/MainApp/paymentcontroller.coffee
@@ -307,9 +307,11 @@
         content += "
You have $#{formatMoney balance} credited to your account.
"

       if chargeAmount > 0
-        content += "
You will be charged for $#{formatMoney chargeAmount}
"
-      else
-        content += "
You won't be charged for this
"
+        content += "
You will be charged for $#{formatMoney chargeAmount}.
"
+      else
+        content += "
You won't be charged for this VM.
"
+
+      content += "
Do you want to continue?
"

       content


Replace `Array.prototype.last` in favor of `_.last`

…of course, thanks @aenario!

--- client/app/components/message_header.coffee
+++ client/app/components/message_header.coffee
@@ -4,9 +4,6 @@
 ContactStore   = require '../stores/contact_store'

 {MessageFlags} = require '../constants/app_constants'
-
-
-(Array.prototype.last = -> this[this.length - 1]) unless Array.prototype.last

 module.exports = React.createClass
@@ -65,7 +62,7 @@
                     onClick: (event) -> event.stopPropagation()

                 items.push tag attrs, format(user)
-                items.push ", " if user isnt users.last()
+                items.push ", " if user isnt _.last(users)
             return items
         else
             return format(users)


terminal: comment fix

terminal: comment fix

--- client/ide/lib/views/tabview/ideview.coffee
+++ client/ide/lib/views/tabview/ideview.coffee
@@ -613,8 +613,9 @@
       @emitChange terminalPane, change

     ###
-    rename terminal tab to terminal session name only if terminal has not been
-    renamed yet, i.e. session name is auto generated string which lenght is 24 symbols
+    Rename terminal tab to terminal session name only if terminal has already been
+    renamed before, i.e. session name isn't auto generated string which lenght is 24 symbols.
+    If session name is auto generated string, leave terminal tab name with its default value 'Terminal'
     ###
     unless session.length is DEFAULT_SESSION_NAME_LENGTH
       terminalHandle.setTitle session


remove todo

remove todo

--- client/landing/app/MainApp/fs/fsfile.coffee
+++ client/landing/app/MainApp/fs/fsfile.coffee
@@ -100,7 +100,6 @@

     return queue

-  # TODO: This method has too many logic with chunks etc. should be retought later. -- fka
   saveBinary:(contents, callback)->

     @abortRequested     = no


client/test: remove team invitation from team creation

--- client/test/lib/helpers/teamshelpers.coffee
+++ client/test/lib/helpers/teamshelpers.coffee
@@ -163,30 +163,21 @@
     companyNameSelector = "#{modalSelector} input[name=companyName]"
     signUpButton        = "#{modalSelector} button[type=submit]"
     user                = utils.getUser()
-    adminUser           =
-      username          : 'devrim'
-      password          : 'devrim'
-
-    helpers.beginTest(browser, adminUser)
-    browser.pause 5000 # wait for welcome modal
-
-    @createInvitation browser, user, (invitationLink) =>
-      browser.click '.close-icon.closeModal'
-
-      helpers.doLogout(browser)
-
-      browser
-        .url                   invitationLink
-        .waitForElementVisible modalSelector, 20000
-        .waitForElementVisible emailSelector, 20000
-        .waitForElementVisible companyNameSelector, 20000
-        .assert.valueContains  emailSelector, user.email
-        .setValue              companyNameSelector, user.teamSlug
-        .click                 signUpButton
-        .pause                 2500
-
-      @enterTeamURL(browser)
-      @fillUsernamePasswordForm(browser, user)
+
+    invitationLink = "#{helpers.getUrl()}/Teams/Create?email=#{user.email}"
+
+    browser
+      .url                   invitationLink
+      .waitForElementVisible modalSelector, 20000
+      .waitForElementVisible emailSelector, 20000
+      .waitForElementVisible companyNameSelector, 20000
+      .assert.valueContains  emailSelector, user.email
+      .setValue              companyNameSelector, user.teamSlug
+      .click                 signUpButton
+      .pause                 2500
+
+    @enterTeamURL(browser)
+    @fillUsernamePasswordForm(browser, user)

   createInvitation: (browser, user, callback) ->


Inline model creation

Inline model creation

--- lib/directory-view.coffee
+++ lib/directory-view.coffee
@@ -76,8 +76,7 @@
       if entry instanceof Directory
         @entries.append(new DirectoryView(directory: entry, isExpanded: false, project: @project, parent: @directory))
       else
-        file = File.createAsRoot(file: entry)
-        @entries.append(new FileView(file))
+        @entries.append(new FileView(File.createAsRoot(file: entry)))
     @append(@entries)

   toggleExpansion: ->


Tasklist searching optimized

Tasklist searching optimized

--- salvus/page/tasks.coffee
+++ salvus/page/tasks.coffee
@@ -484,8 +484,7 @@
         if search.length > 0
             # Go through the DOM tree of tasks and highlight all the search terms for
             # tasks that aren't currently being edited.
-            for tags in search
-                @elt_task_list.find(".#{(tags).substring(1)}").addClass("highlight-tag")
+            @elt_task_list.find( ("."+tags.substring(1) for tags in search).join(',') ).addClass("highlight-tag")

         # show the "create a new task" link if no tasks.
         if count == 0


fix at least one subtle async issue with synchronized strings and the database

--- salvus/syncstring.coffee
+++ salvus/syncstring.coffee
@@ -323,10 +323,11 @@
         opts.cb(undefined, S); return

     if sync_string_cbs[opts.string_id]?
+        winston.debug("get_syncstring -- getting string_id=#{opts.string_id} -- already doing it")
         sync_string_cbs[opts.string_id].push(opts.cb)
         return
     else
-        cbs = sync_string_cbs[opts.string_id] = [opts.cb]
+        sync_string_cbs[opts.string_id] = [opts.cb]

     S = new SynchronizedString(opts.string_id, opts.max_len)
     async.series([
@@ -353,6 +354,7 @@
     ], (err) =>
         if not err
             sync_strings[opts.string_id] = S
+        cbs = sync_string_cbs[opts.string_id]
         delete sync_string_cbs[opts.string_id]
         for cb in cbs
             if err
@@ -471,6 +473,7 @@
             f = (args...) =>
                 for cb in @_get_string_queue[opts.string_id]
                     cb(args...)
+                delete @_get_string_queue[opts.string_id]

             @_get_string_queue[opts.string_id] = [opts.cb]

@@ -914,32 +917,33 @@
     winston.debug("syncdb -- getting string -- string_id=#{opts.string_id} and max_len=#{opts.max_len}")
     d = _syncdb_cache[opts.string_id]
     if d?
-        winston.debug("syncdb -- getting string -- using cache")
+        winston.debug("syncdb -- getting string_id=#{opts.string_id} -- using cache")
         opts.cb(undefined, d)
         return
     x = _syncdb_callbacks[opts.string_id]
     if x?
-        winston.debug("syncdb -- getting string -- already creating")
+        winston.debug("syncdb -- getting string_id=#{opts.string_id} -- already creating")
         x.push(opts.cb)
         return
     _syncdb_callbacks[opts.string_id] = [opts.cb]
-    winston.debug("syncdb -- getting string -- doing it")
+    winston.debug("syncdb -- getting string_id=#{opts.string_id} -- doing it")
     get_syncstring
         string_id : opts.string_id
         max_len   : opts.max_len
         cb        : (err, S) =>
+            callbacks = _syncdb_callbacks[opts.string_id]
+            delete _syncdb_callbacks[opts.string_id]
             if not err
                 doc = new diffsync.SynchronizedDB_DiffSyncWrapper(S.in_memory_client)
                 S.db_client.on 'changed', () =>
                     doc.emit("sync")
                 d = _syncdb_cache[opts.string_id] = new diffsync.SynchronizedDB(doc, undefined, undefined, opts.max_len)
                 d.string_id = opts.string_id
-            for cb in _syncdb_callbacks[opts.string_id]
+            for cb in callbacks
                 if err
                     cb(err)
                 else
                     cb(undefined, d)
-            delete _syncdb_callbacks[opts.string_id]

 ######################################################################
 # Microservice API
@@ -948,7 +952,7 @@
 DEFAULT_PORT = 6001    # also hard coded in admin.py

 ###
-x={};require('syncstring').client(debug:true, cb:(e,s)->console.log('done',e);x.s=s;x.s.syncdb(string_id:'c26db83a-7fa2-44a4-832b-579c18fac65f',cb:(e,t)->console.log(e);x.t=t));0
+id='c26db83a-7fa2-44a4-832b-579c18fac65f';x={};require('syncstring').client(debug:true, cb:(e,s)->console.log('done',e);x.s=s;x.s.syncdb(string_id:id,cb:(e,t)->console.log(e);x.t=t));0
 ###

 ###


meta logs system prefix

meta logs system prefix

--- src/application.coffee
+++ src/application.coffee
@@ -28,22 +28,22 @@

 	knex('config').select('value').where(key: 'uuid').then ([ uuid ]) ->
 		uuid = uuid.value
-		channel = "device-#{uuid}-"
+		channel = "device-#{uuid}-logs"

 		# Redefine original function
-		publish = (message, channelPrefix="logs") ->
-			pubnub.publish({ channel + channelPrefix, message })
+		publish = (message) ->
+			pubnub.publish({ channel, message })

 		# Replay queue now that we have initialised the publish function
 		publish(args...) for args in publishQueue

 	return -> publishQueue.push(arguments)

-exports.logSupervisorEvent = logSupervisorEvent = (message) ->
-	publish(message, "meta-logs")
-
-exports.kill = kill = (app) ->
-	logSupervisorEvent( 'Killing application ' + app.imageId )
+exports.logSystemEvent = logSystemEvent = (message) ->
+	publish("[system] " + message)
+
+exports.kill = kill = (app) ->
+	logSystemEvent('Killing application ' + app.imageId)
 	utils.mixpanelTrack('Application kill', app)
 	updateDeviceInfo(status: 'Stopping')
 	container = docker.getContainer(app.containerId)
@@ -101,7 +101,7 @@
 			docker.getImage(app.imageId).inspectAsync()
 			.catch (error) ->
 				utils.mixpanelTrack('Application install', app)
-				logSupervisorEvent('Installing application ' + app.imageId)
+				logSystemEvent('Installing application ' + app.imageId)
 				updateDeviceInfo(status: 'Downloading')
 				docker.createImageAsync(fromImage: app.imageId)
 				.then (stream) ->
@@ -168,7 +168,7 @@
 				)
 	.tap ->
 		utils.mixpanelTrack('Application start', app.imageId)
-		logSupervisorEvent('Starting application ' + app.imageId)
+		logSystemEvent('Starting application ' + app.imageId)
 	.finally ->
 		updateDeviceInfo(status: 'Idle')

@@ -258,7 +258,7 @@
 					localApp = apps[imageId]
 					app = remoteApps[imageId]
 					utils.mixpanelTrack('Application update', app)
-					logSupervisorEvent('Updating application')
+					logSystemEvent('Updating application')
 					kill(localApp)
 					.then ->
 						start(app)


Remove sync endpoint

Remove sync endpoint

--- src/application.coffee
+++ src/application.coffee
@@ -47,7 +47,6 @@

     app.get  '/api/v1/account', accounts_api_controller.show
     app.put  '/api/v1/account', accounts_api_controller.update
-    app.post '/api/v1/account/sync', accounts_api_controller.sync

     port = process.env.PORT ? 3004
     server.listen port, ->


How did that happen?

How did that happen?

--- src/application.coffee
+++ src/application.coffee
@@ -50,5 +50,5 @@
       res.sendfile path.join(__dirname, '../public/index.html')

     port = process.env.PORT ? 3004
-    server.listen process, ->
+    server.listen port, ->
       console.log "Express server listening on port #{server.address().port}"


refactor(macFocusOnEvent): Prevent digest cycle from invoking on focus

--- src/directives/focus_on_event.coffee
+++ src/directives/focus_on_event.coffee
@@ -17,5 +17,5 @@
           x = window.scrollX
           y = window.scrollY
           window.scrollTo x, y
-      , 0
+      , 0, false
 ]


Fall back to using event.key.

Fall back to using event.key.

If `event.code` is not defined, then fall back to using `event.key`
instead.

Fixes #3099.

--- lib/keyboard_utils.coffee
+++ lib/keyboard_utils.coffee
@@ -19,7 +19,7 @@
     unless Settings.get "ignoreKeyboardLayout"
       key = event.key
     else unless event.code
-      key = ""
+      key = event.key ? "" # Fall back to event.key (see #3099).
     else if event.code[...6] == "Numpad"
       # We cannot correctly emulate the numpad, so fall back to event.key; see #2626.
       key = event.key


Fix ability of local storage provider to list directory

Were supressing directory list if dialog not mounted, but this
check failed for localStorage because directory is loaded
synchronously.

--- src/code/views/file-dialog-tab-view.coffee
+++ src/code/views/file-dialog-tab-view.coffee
@@ -81,12 +81,13 @@
   mixins: [AuthorizeMixin]

   getInitialState: ->
+    @_isMounted = true
     initialState = @getStateForFolder(@props.client.state.metadata?.parent, true) or null
     initialState.filename = initialState.metadata?.name or ''
     initialState

-  componentDidMount: ->
-    @_isMounted = true
+#  componentDidMount: ->
+#    @_isMounted = true

   componentWillUnmount: ->
     @_isMounted = false


fix test for producer manager calling add and remove component without a key

--- test/spec/datacommunication/producers/ProducerManager.spec.coffee
+++ test/spec/datacommunication/producers/ProducerManager.spec.coffee
@@ -72,9 +72,8 @@
         assert addComponent.calledOnce
         assert.ok instance instanceof DummyProducer1

-        assert.equal args.length, 2
-        assert.equal args[0], SubscriptionKeys.EXAMPLE_KEY1
-        assert.equal args[1], options
+        assert.equal args.length, 1
+        assert.equal args[0], options

     describe 'to unsubscribe', ->
       it 'should call the producer\'s removeComponent method', ->
@@ -90,9 +89,8 @@
         assert removeComponent.calledOnce
         assert.ok instance instanceof DummyProducer1

-        assert.equal args.length, 2
-        assert.equal args[0], SubscriptionKeys.EXAMPLE_KEY1
-        assert.equal args[1], componentId
+        assert.equal args.length, 1
+        assert.equal args[0], componentId

   # This method doesn't seem to exist
   # describe 'given a invalid subscription key', ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera_fade.coffee
+++ src/camera_fade.coffee
@@ -40,7 +40,7 @@
   @param {Color} [color="black"] The color to fade from
   ###
   fadeIn: (options={}) ->
-    {alpha, colorduration} = Object.reverseMerge(options, defaultParams)
+    {alpha, color, duration} = Object.reverseMerge(options, defaultParams)

     configureFade(duration, color, 0)


Add missing language option on export.

Add missing language option on export.


fix specs

fix specs

--- test/spec/models/choropleth_map_spec.coffee
+++ test/spec/models/choropleth_map_spec.coffee
@@ -54,6 +54,7 @@
         diff = @choroplethMap.calculateDifference(@oldSnippetModel)
         expect(diff[0].properties[1]).to.eql(
           label: 'projection'
+          key: 'projection'
           difference: undefined
           info: "(mercator)"
         )
@@ -65,6 +66,7 @@
         diff = @choroplethMap.calculateDifference(@oldSnippetModel)
         expect(diff[0].properties[1]).to.eql(
           label: 'projection'
+          key: 'projection'
           difference:
             type: 'change'
             previous: 'mercator'
@@ -194,6 +196,7 @@
         diff = @choroplethMap.calculateDifference(@oldSnippetModel)
         expect(diff[3].properties[0]).to.eql
           label: 'value property'
+          key: 'valueProperty'
           difference: undefined
           info: '(value)'

@@ -205,6 +208,7 @@
         diff = @choroplethMap.calculateDifference(@oldSnippetModel)
         expect(diff[3].properties[0]).to.eql
           label: 'value property'
+          key: 'valueProperty'
           difference:
             type: 'change'
             previous: 'value'
@@ -215,6 +219,7 @@
         diff = @choroplethMap.calculateDifference(@oldSnippetModel)
         expect(diff[3].properties[1]).to.eql
           label: 'color scheme'
+          key: 'colorScheme'
           difference: undefined
           info: '(YlGn)'

@@ -225,6 +230,7 @@
         diff = @choroplethMap.calculateDifference(@oldSnippetModel)
         expect(diff[3].properties[1]).to.eql
           label: 'color scheme'
+          key: 'colorScheme'
           difference:
             type: 'change'
             previous: 'YlGn'
@@ -235,6 +241,7 @@
         diff = @choroplethMap.calculateDifference(@oldSnippetModel)
         expect(diff[3].properties[2]).to.eql
           label: 'quantize steps'
+          key: 'quantizeSteps'
           difference: undefined
           info: '(3)'

@@ -245,6 +252,7 @@
         diff = @choroplethMap.calculateDifference(@oldSnippetModel)
         expect(diff[3].properties[2]).to.eql
           label: 'quantize steps'
+          key: 'quantizeSteps'
           difference:
             type: 'change'
             previous: 3


forgot to store reference to currentUser

--- src/client/auth.coffee
+++ src/client/auth.coffee
@@ -108,6 +108,7 @@
 class Auth
   constructor: (api, currentUser, currentConfig)->
     @api             = api
+    @currentUser     = currentUser
     @currentConfig   = currentConfig
     @_popupInterval  = null
     @_authenticating = null


this adds State Of The States 2019 to pivotal-listener

--- scripts/pivotal-listener.coffee
+++ scripts/pivotal-listener.coffee
@@ -43,7 +43,8 @@
         "DAR - ENG": "DARENG-",
         "Salesforce": "SFDC-",
         "JAM": "JAM-",
-        "Business As Usual": "BAU-"
+        "Business As Usual": "BAU-",
+        "State Of The States 2019": "SOTS-"

       project =
         projectId: reqBody["project"]["id"]


:melon: adapt styles to mozilla

:melon: adapt styles to mozilla

--- src/renderer/components/doc-search-container-component.coffee
+++ src/renderer/components/doc-search-container-component.coffee
@@ -96,6 +96,7 @@
     paddingLeft: 12
     fontSize: 16
     fontFamily: '-webkit-body'
+    fontFamily: '-moz-body'
     fontWeight: 'normal'
     outline: 'none'
     borderColor: colors.general.r.moderate


fix output tests

fix output tests

--- test/context.coffee
+++ test/context.coffee
@@ -23,7 +23,7 @@
       it 'can output', ->
         run_context = context.create_run_context []
         html = 'hello, world'
-        run_context.output html
+        run_context.div html
         $el = context.render run_context
         expect($el.text()).to.be html

@@ -130,7 +130,7 @@
         context_a = context.create_run_context [ctx]
         context.eval_in_context context_a,->
           text 'a'
-          @nested 'nest', ->
+          @div ->
             text 'b'
         $el = context.render context_a
         expect($el.text()).to.be 'ab'


JSMenuView's bug fix

JSMenuView's bug fix

--- JSKit/04_JSMenuView.coffee
+++ JSKit/04_JSMenuView.coffee
@@ -32,8 +32,8 @@
         $(@_viewSelector).append(@_div)
         $(@_viewSelector+"_menu").css("left", "0px")
         $(@_viewSelector+"_menu").css("top", "0px")
-        $(@_viewSelector+"_menu").css("width", @_parent._frame.size.width+"px")
-        $(@_viewSelector+"_menu").css("height", @_parent._frame.size.height+"px")
+        $(@_viewSelector+"_menu").css("width", @_frame.size.width+"px")
+        $(@_viewSelector+"_menu").css("height", @_frame.size.height+"px")
         $(@_viewSelector+"_menu").css("position", "absolute")
         $(@_viewSelector+"_menu").css("overflow", "visible")
         $(@_viewSelector+"_menu").css("font-size", @_textSize+"pt")


fix multiple call reaload area (#1903)

fix multiple call reaload area (#1903)

--- BackofficeBundle/Resources/public/coffee/page/area/AreaView.coffee
+++ BackofficeBundle/Resources/public/coffee/page/area/AreaView.coffee
@@ -20,6 +20,7 @@
     'sortupdate .block-container': 'stopBlock'
     'sortreceive .block-container': 'receiveBlock'
     'sortremove .block-container': 'removeBlock'
+    'remove': 'remove'

   ###*
    * @param {Object} options
@@ -247,3 +248,11 @@
     else
       @$el.children('.area-action').hide()
       @$el.removeClass('active')
+
+  ###*
+    * Call when view is removed, unbind area channel event
+  ###
+  remove: () ->
+    OpenOrchestra.Page.Area.Channel.unbind 'activateEditArea', @activateEditArea
+    OpenOrchestra.Page.Area.Channel.unbind 'activateSortableArea', @activateSortableArea
+    OpenOrchestra.Page.Area.Channel.unbind 'updateArea', @reloadArea


remove auto upgrade script

remove auto upgrade script

--- server/startup/migrations/xrun.coffee
+++ server/startup/migrations/xrun.coffee
@@ -1,6 +1,6 @@
-if RocketChat.Migrations.getVersion() isnt 0
-	RocketChat.Migrations.migrateTo 'latest'
-else
-	control = RocketChat.Migrations._getControl()
-	control.version = _.last(RocketChat.Migrations._list).version
-	RocketChat.Migrations._setControl control
+# if RocketChat.Migrations.getVersion() isnt 0
+# 	RocketChat.Migrations.migrateTo 'latest'
+# else
+# 	control = RocketChat.Migrations._getControl()
+# 	control.version = _.last(RocketChat.Migrations._list).version
+# 	RocketChat.Migrations._setControl control