changed addToFilter function

changed addToFilter function

--- src/driver/driverCache.coffee
+++ src/driver/driverCache.coffee
@@ -18,7 +18,7 @@
 splitToHash = (split) ->
   hash = []
   for own k, v of split
-    continue if k is 'name'
+    continue if k in ['name', 'bucketFilter']
     hash.push(k + ":" + v)

   return hash.sort().join('|')
@@ -59,17 +59,19 @@
       timeFilter: filter
     }

-addToFilter = (filter, newFilterPiece) ->
+addToFilter = (filter, newFilterPieces...) ->
   if filter?
-    if newFilterPiece.type is 'within'
+    newTimeFilterPiece = newFilterPieces.filter(({type}) -> return type is 'within')[0]
+    if newTimeFilterPiece?.type is 'within'
       { filter, timeFilter } = separateTimeFilter(filter)
-
+    newFilterPieces.push filter
+  if newFilterPieces.length > 1
     return {
       type: 'and'
       operation: 'filter'
-      filters: [newFilterPiece, filter]
-    }
-  return newFilterPiece
+      filters: newFilterPieces
+    }
+  return newFilterPieces[0]

 createFilter = (value, splitOp) ->
   if splitOp.bucket in ['timePeriod', 'timeDuration']
@@ -106,16 +108,17 @@
     @_filterPutHelper(condensedQuery, root, condensedQuery[0].filter, 0)
     return

-  _filterPutHelper: (condensedQuery, root, filter, level) ->
+  _filterPutHelper: (condensedQuery, node, filter, level) ->
     hashValue = @hashmap[filterToHash(filter)] ?= {}
     applies = condensedQuery[level].applies
     for apply in applies
-      hashValue[apply.name] = root.prop[apply.name] or hashValue[apply.name]
-
-    if root.splits?
+      hashValue[apply.name] = node.prop[apply.name] or hashValue[apply.name]
+
+    if node.splits?
       splitOp = condensedQuery[level + 1].split
-      for split in root.splits
-        @_filterPutHelper(condensedQuery, split, addToFilter(filter, createFilter(split.prop[splitOp.name], splitOp)), level + 1)
+      for split in node.splits
+        newFilter = addToFilter(filter, createFilter(split.prop[splitOp.name], splitOp))
+        @_filterPutHelper(condensedQuery, split, newFilter, level + 1)
     return

@@ -152,7 +155,8 @@

     if condensedQuery[level + 2]?
       for split in node.splits
-        @_splitPutHelper(condensedQuery, split, addToFilter(filter, createFilter(split.prop[splitOpName], splitOp)), level + 1)
+        newFilter = addToFilter(filter, createFilter(split.prop[splitOpName], splitOp))
+        @_splitPutHelper(condensedQuery, split, newFilter, level + 1)
     return

   _timeCalculate: (filter, splitOp) ->
@@ -209,6 +213,7 @@

   getUnknownQuery = (query, root, condensedQuery) ->
     return query unless root?
+    # console.log JSON.stringify(root, null, 2)
     unknownQuery = []
     added = false

@@ -224,7 +229,7 @@

       if condensedCommand.applies?
         for apply in condensedCommand.applies
-          exists = checkDeep(root, 0, i, apply.name, condensedCommand.split.bucketFilter)
+          exists = checkDeep(root, 0, i, apply.name, condensedCommand.split?.bucketFilter)
           if not exists
             added = true

@@ -272,7 +277,8 @@
     splits = []

     for value in cachedValues
-      ret = getKnownTreeHelper(condensedQuery, addToFilter(filter, createFilter(value, splitOp)), level + 1, value)
+      newFilter = addToFilter(filter, createFilter(value, splitOp))
+      ret = getKnownTreeHelper(condensedQuery, newFilter, level + 1, value)
       # console.log '\n---------------------------------------------------------'
       # console.log ret
       # console.log level - 1


Add geoconfig to config example

Add geoconfig to config example

Add example of geo module config to config example file.

--- config/config.coffee-dist.coffee
+++ config/config.coffee-dist.coffee
@@ -10,7 +10,13 @@
 exports.eventbrite =
 	appKey: null

-exports.elasticsearch =
+exports.elasticsearch =
 	host: 'localhost:9200'
 	log: 'trace'
-	apiVersion: '1.5'+	apiVersion: '1.5'
+
+exports.geo =
+	center: # Insert lat and lon coordinates for your area of interest
+		lat: 0.0
+		lon: 0.0
+	maxDistKilometers: 100 # Use something you feel is sensible


try 50 sockets for downloading

try 50 sockets for downloading

--- lib/download_manifest.coffee
+++ lib/download_manifest.coffee
@@ -8,6 +8,8 @@
 program  = require("commander")
 url      = require("url")
 util     = require("util")
+
+http.globalAgent.maxSockets = 50

 program
   .version(require("#{__dirname}/../package.json").version)


refactor: get rid of result references

refactor: get rid of result references

--- scripts-src/memoizing_analyzer.coffee
+++ scripts-src/memoizing_analyzer.coffee
@@ -29,15 +29,7 @@
           if rule.is_transposable_with ((x) -> blockTfm[x])
             symmetries.push tfm
   return symmetries
-
-unwrapResult = (result) ->
-      #console.log "#### Result found:"+JSON.stringify(result)
-      #Result may be a real result object, or a reference to another. Dereference, if needed
-      if (referenced = result.refersTo)?
-        referenced
-      else
-        result
-
+
 exports.MemoAnalyser = class MemoAnalyser
   constructor: (@rule)->
     @ruleset = rule.stabilize_vacuum()
@@ -47,23 +39,34 @@
     @maxPopulation = 1024
     @maxSize = 100
     @symmetries = ruleSpatialSymmetries rule
-
-  registerResult: (pattern, result, mainKey) ->
-      #Register a pattern with given result, under all keys
-      pattern2result = @pattern2result
-      pattern2result[mainKey] = result
-      for tfm in @symmetries
-        transformedKey = patternKey Cells.transform pattern, tfm
-        if transformedKey isnt mainKey
-          #assert that key either not present, or refers the same result
-          #if pattern2result[transformedKey]?
-          #
-          pattern2result[transformedKey] = result
-
+    @frozen = false
+    @doubleHitCount = 0
+    @currentPatternKeys = []
+
+  freeze: ->
+    @frozen = true
+    @truncateTable
+
+  stashKeys: (pattern, mainKey) ->
+    keys = @currentPatternKeys
+    keys.push mainKey
+    for tfm in @symmetries
+      transformedKey = patternKey Cells.transform pattern, tfm
+      keys.push transformedKey
+    return
+
+  writeResult: (result) ->
+    pattern2result = @pattern2result
+    for key in @currentPatternKeys
+      pattern2result[key] = result
+    @currentPatternKeys = []
+    return

   analyse: (pattern) ->
     result = @_analyse pattern
     result.hits += 1
+    if result.hits is 2
+      @doubleHitCount += 1
     return result

   _analyse: (pattern) -> #result
@@ -98,10 +101,10 @@
     Cells.sortXY pattern
     key = patternKey pattern
     if (result = @pattern2result[key])?
-      return unwrapResult result
+      #console.log "#### FIrst hit!"
+      return result
     else
-      result = {resolution:null} #result would be calculated later - now only make an empty placeholder
-      @registerResult pattern, result, key
+      @stashKeys pattern, key

     bestPatternSearch = new Maximizer Cells.energy
     bestPatternSearch.put pattern
@@ -134,62 +137,75 @@
       key = patternKey curPattern
       #Maybe, we already had this value?
       if (knownResult = @pattern2result[key])?
-        #Make current result to point to the cached one.
-        if knownResult.resolution isnt null
-          #console.log "#### known result:"+JSON.stringify(knownResult)
-          return (result.refersTo = unwrapResult knownResult)
-      else
-        #previously unknown pattern. Register its result (not yet calculated)
-        @registerResult curPattern, result, key
+        #Write current result to the stashed keys
+        #console.log "#### known result:"+JSON.stringify(knownResult)
+        result = knownResult
+        break

       #maybe, analysis has finished?
       if Cells.areEqual pattern, curPattern
-        return @makePeriodFoundResult result, dx, dy, iter, bestPatternSearch.getArg()
+        result = @makePeriodFoundResult dx, dy, iter, bestPatternSearch.getArg()
+        break
+
+      #previously unknown pattern. Remember its keys
+      @stashKeys curPattern, key

       #no cycle. Fine.
       bestPatternSearch.put curPattern
       if curPattern.length > maxPopulation
-        return @makePatternTooBigResult result
+        result = @makePatternTooBigResult()
+        break
       if Math.max( bounds[2]-bounds[0], bounds[3]-bounds[1]) > maxSize
-        return @makePatternToWideResult result
-
-    #After the given number of iterations, nothing was found.
-    #Give up.
-    @makeCycleNotFoundResult result
-
-  makePeriodFoundResult: (result, dx, dy, period, bestPattern)->
+        result = @makePatternToWideResult()
+        break
+
+    unless result?
+      #After the given number of iterations, nothing was found.
+      #Give up.
+      result = @makeCycleNotFoundResult()
+
+    @writeResult result
+    return result
+
+
+  makePeriodFoundResult: (dx, dy, period, bestPattern)->
     #console.log "#### period found"
-    [bestPattern, result.dx, result.dy] =
+    [bestPattern, dx0, dy0] =
          Cells.canonicalize_spaceship bestPattern, @rule, dx, dy
-    result.resolution = Resolution.HAS_PERIOD
-    result.period = period
-    result.cells = bestPattern
-    result.hits = 0
-    return result
-
-  makePatternToWideResult: (result)->
+    return {
+      resolution: Resolution.HAS_PERIOD
+      dx: dx0
+      dy: dy0
+      period: period
+      cells: bestPattern
+      hits: 0
+    }
+
+  makePatternToWideResult: ->
     #console.log "#### pattern too wide"
-    result.resolution = Resolution.TOO_WIDE
-    result
-
-  makePatternTooBigResult: (result)->
+    return {
+      resolution: Resolution.TOO_WIDE
+      hits: 0
+    }
+  makePatternTooBigResult: ->
     #console.log "#### pattern too big"
-    result.resolution = Resolution.OVERPOPUPATION
-    result.hits = 0
-    result
-  makeCycleNotFoundResult: (result)->
+    return {
+      resolution: Resolution.OVERPOPUPATION
+      hits: 0
+    }
+  makeCycleNotFoundResult: ->
     #console.log "#### no cycle found"
-    result.resolution = Resolution.NO_PERIOD
-    result.hits = 0
-    result
-
+    return {
+      resolution: Resolution.NO_PERIOD
+      hits: 0
+    }

   #Truncate memo table to the given number of records, removing items with the least hit count
   truncateTable: (maxRecords) ->
     if maxRecords < 0
       throw new Error "Number of records must be positive"
     pattern2result = @pattern2result
-    keysWithHits = ([unwrapResult(result).hits, key] for key, result of pattern2result)
+    keysWithHits = ([result.hits, key] for key, result of pattern2result)
     #sort keys by hit count, more hits go first
     keysWithHits.sort (kh1, kh2) -> kh2[0]-kh1[0]
     #remove the rest keys


Remove comment in branch test

Remove comment in branch test

--- cosmo.coffee
+++ cosmo.coffee
@@ -1,7 +1,6 @@
 window.Cosmo =
   version: '0.1.0'

-# more
 # All apps should be an extended instance of this class
 class Cosmo.Router
   # app regions, assumes main content goes in a div#container


Tabs: Implemented destroy method so every tab is destroyed.

--- src/elements/Tabs/Tabs.coffee
+++ src/elements/Tabs/Tabs.coffee
@@ -271,3 +271,9 @@
 		tab = @getTab(tab_or_idx_or_name)
 		tab.activate()
 		@
+
+	destroy: ->
+		while @__tabs.length > 0
+			# Tab destroy triggers 'tab_destroy' event which makes the tab to be removed from the array.
+			@__tabs[0].destroy()
+		super()


jump around finished

jump around finished

--- lib/editor-util.coffee
+++ lib/editor-util.coffee
@@ -8,9 +8,16 @@

   onDone = (editor) ->
     if editor.getText().length is 0
-      editor.setText(script.source)
-      editor.setCursorBufferPosition([line, 0], autoscroll: true)
+      if not script.source?
+        debuggerContext.scripts.getById(script.id)
+          .then (script) ->
+            editor.setText(script.source)
+            editor.setCursorBufferPosition([line, 0], autoscroll: true)
+          .done()
+      else
+        editor.setText(script.source)

+    editor.setCursorBufferPosition([line, 0], autoscroll: true)
     return editor

   onError = (e)->


fixes #2

fixes #2

--- lib/geekywalletlib.coffee
+++ lib/geekywalletlib.coffee
@@ -1,6 +1,11 @@
 define ->
+
   Array::sum = (fn = (x) -> x) ->
     @reduce ((a, b) -> a + fn b), 0
+
+  Array::hasElementMatching = (fn = (x) -> x) ->
+    filtered = @filter ((item, i) -> fn item)
+    filtered.length > 0

   class Brain

@@ -15,7 +20,7 @@
       group.lines.map (line) ->
         if line.context? # line is actually a group...
           console.log "TODO manage nested context"
-        else
+        else
           line.context = {}
           line.context.people = group.context.people
         line
@@ -29,16 +34,24 @@
       computing.totalSpentAmount = line.payers.sum (x) -> x.amount
       computing.totalFixedAmount = line.beneficiaries.sum (x) -> x.fixedAmount
       computing.totalOffset = line.beneficiaries.sum (x) -> x.offset
-      computing.totalMultiply =line.beneficiaries.sum (x) -> x.multiply
+      computing.totalMultiply =line.beneficiaries.sum (x) -> x.multiply
       # save intermediate computation in line
       line.computing = computing
       # return line object
       line

-    preprocessLine: (line) =>
+    preprocessLine: (line) =>
+      console.log "line", line
       # add beneficiaries from context if none is defined
       unless line.beneficiaries?
         line.beneficiaries = line.context.people.map (name) -> {name: name}
+      # add remaining beneficiaries if option "group" is present
+      if @getOption(line, "group")
+        missingBeneficiaries = line.context.people.filter (personName) =>
+          console.log "personName", personName
+          not line.beneficiaries.hasElementMatching (ben) -> ben.name == personName
+        console.log "missing", missingBeneficiaries
+        line.beneficiaries.push {name: name} for name in missingBeneficiaries
       # compute fixed amount, offset and multiply
       line.beneficiaries = line.beneficiaries.map (ben) ->
         ben.fixedAmount = 0
@@ -53,3 +66,7 @@
             ben.fixedAmount = ben.amount
         ben

+    getOption: (line, optionName) =>
+      line.options.filter((x) -> x.name == optionName)[0]
+
+


Revert "Pass the environment in for spawnOptions"

This reverts commit f615b4d7ff6cab6e3fd4963728edbaa81bea1027.

It is now handled by spawnteract itself.

--- lib/kernel-manager.coffee
+++ lib/kernel-manager.coffee
@@ -113,7 +113,6 @@
         )
         spawnOptions =
             cwd: projectPath
-            env: process.env
         launchSpec(kernelSpec, spawnOptions).
             then ({config, connectionFile, spawn}) =>
                 kernel = new ZMQKernel(


Fixed #3068

Fixed #3068

Fixed frustrating IME leftover issue when press ESC in input

--- lib/keyboard_utils.coffee
+++ lib/keyboard_utils.coffee
@@ -66,7 +66,10 @@

     (event) ->
       # <c-[> is mapped to Escape in Vim by default.
-      event.key == "Escape" or (useVimLikeEscape and @getKeyCharString(event) == "<c-[>")
+      # Escape with a keyCode 229 means that this event comes from IME, and should not be treat as a directly/normal ESC press.
+      # In this case, IME will take care of the ESC press event, not vimium.
+      # See https://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html
+      (event.key == "Escape" and event.keyCode != 229) or (useVimLikeEscape and @getKeyCharString(event) == "<c-[>")

   isBackspace: (event) ->
     event.key in ["Backspace", "Delete"]


Handle new addhoc Tasks to existing Phase

--- app/assets/javascripts/controllers/application_controller.js.coffee
+++ app/assets/javascripts/controllers/application_controller.js.coffee
@@ -20,6 +20,11 @@
               delete esData.type
               store.pushPayload(type, esData)

+              if esData.task
+                store.find('task', esData.task.id).then (task)->
+                  # ember.js bug:  need to tell phase about any new tasks
+                  task.get('phase').get('tasks').pushObject(task)
+
     Ember.$.ajax(params)
   ).on('init')


highlight active controller

highlight active controller

--- app/assets/javascripts/jax/dev/views/controller_list_item.js.coffee
+++ app/assets/javascripts/jax/dev/views/controller_list_item.js.coffee
@@ -7,3 +7,7 @@

   render: =>
     @$el.html @template @model.toJSON()
+    if document.location.hash.toString().indexOf("controllers/#{@model.get 'name'}") isnt -1
+      @$el.addClass 'active'
+    else
+      @$el.removeClass 'active'


teams: stacks: removed redis and fixed postgresql

--- client/admin/lib/views/stacks/onboarding/serverconfigoptions.coffee
+++ client/admin/lib/views/stacks/onboarding/serverconfigoptions.coffee
@@ -1,15 +1,15 @@
 module.exports =
   Database     :
-    mysql      : title: 'MySQL',    package: 'mysql',       command: 'service mysql start'
-    redis      : title: 'Redis',    package: 'redis',       command: ''
-    mongodb    : title: 'Mongo DB', package: 'mongodb',     command: ''
-    postgre    : title: 'Postgre',  package: 'postgre-sql', command: ''
-    sqlite     : title: 'SQLite',   package: 'sqlite',      command: ''
+    mysql      : title: 'MySQL',      package: 'mysql',             command: 'service mysql start'
+    # redis      : title: 'Redis',      package: 'redis-server',      command: 'apt-get install -y python-software-properties && add-apt-repository -y ppa:rwky/redis && sudo apt-get update && sudo apt-get install -y redis-server'
+    mongodb    : title: 'Mongo DB',   package: 'mongodb',           command: ''
+    postgresql : title: 'PostgreSQL', package: 'postgresql-9.4',    command: ''
+    sqlite     : title: 'SQLite',     package: 'sqlite',            command: ''
   Language     :
-    node       : title: 'Node.js',  package: 'node',        command: ''
-    ruby       : title: 'Ruby',     package: 'ruby',        command: ''
-    python     : title: 'Python',   package: 'python',      command: ''
-    php        : title: 'PHP',      package: 'php',         command: ''
+    node       : title: 'Node.js',    package: 'node',              command: ''
+    ruby       : title: 'Ruby',       package: 'ruby',              command: ''
+    python     : title: 'Python',     package: 'python',            command: ''
+    php        : title: 'PHP',        package: 'php',               command: ''
   'Web Server' :
-    apache     : title: 'Apache',   package: 'apache',      command: ''
-    nginx      : title: 'Nginx',    package: 'nginx',       command: 'nginx start'
+    apache     : title: 'Apache',     package: 'apache',            command: ''
+    nginx      : title: 'Nginx',      package: 'nginx',             command: 'nginx start'


Teamwork: Updated firebase url.

Teamwork: Updated firebase url.

--- client/landing/CollaborativeWorkspace/collaborativeworkspace.coffee
+++ client/landing/CollaborativeWorkspace/collaborativeworkspace.coffee
@@ -21,7 +21,7 @@
     unless instanceName
       return warn "CollaborativeWorkspace requires a Firebase instance."

-    @firepadRef   = new Firebase "https://#{instanceName}.firebaseIO.com/"
+    @firepadRef   = new Firebase "https://#{instanceName}.firebaseio.com/"
     @sessionKey   = @getOptions().sessionKey or @createSessionKey()
     @workspaceRef = @firepadRef.child @sessionKey
     @broadcastRef = @workspaceRef.child "broadcast"


animation example: dataset limitation

animation example: dataset limitation

--- src/examples/animation.coffee
+++ src/examples/animation.coffee
@@ -11,6 +11,7 @@
 					->
 						result = []
 						for i in [index..index + count-1]
+							continue if i <= 0 or i > 14
 							item = {}
 							item.id = i
 							item.content = "item #" + i


Center the main view

Center the main view

--- app/scripts/app.coffee
+++ app/scripts/app.coffee
@@ -26,14 +26,21 @@

   initialize: ->
     super
+
+    @$style = @$ "#animation"
+    @$result = @$ "#result"
+    @$box = @$result.find ".box"
+    @$main = @$ ".main-view"
+
+    @centerView()
+    $(window).on "resize", @centerView
+
+    @playIntro()
+
     @preferences = new PreferencesView
     @boxView = new BoxView
     @exportView = new ExportView

-    @$style = @$ "#animation"
-    @$result = @$ "#result"
-    @$box = @$result.find ".box"
-    @playIntro()

     @$loop = @$(".actions .loop-input").toggleButton()
     @$slow = @$(".actions .slow-input").toggleButton()
@@ -53,6 +60,10 @@
       localStorage["seenIntro"] = true
       $body.removeClass "play-intro"
     , 5000
+
+  centerView: =>
+    padding = Math.floor(($(window).outerHeight() - @$main.outerHeight()) / 2)
+    @$main.css "padding-top", Math.max(padding, 60)

   onClickPlay: ->
     if @preferences.getBounceObject().components.length


Move depoy info fetch into conditional and simplify adding alerts

--- SingularityUI/app/controllers/TaskDetail.coffee
+++ SingularityUI/app/controllers/TaskDetail.coffee
@@ -134,20 +134,26 @@
                 app.caughtError()
                 delete @models.resourceUsage

-    getAlerts: (deployInfo) =>
+    getAlerts: =>
+        @collections.alerts.reset()
         task = @models.task
-        alerts = []
+        requestId = @models.task.attributes.task.taskRequest.request.id
+        deployId = @models.task.attributes.task.taskRequest.deploy.id
         # Is this a scheduled task that has been running much longer than previous ones?
         if task.attributes.task.taskRequest.request.requestType == 'SCHEDULED' and task.get('isStillRunning')
-            avg = deployInfo.get('deployStatistics')?.averageRuntimeMillis
-            current =  new Date().getTime() - task.get('task').taskId.startedAt
-            threshold = window.config.warnIfScheduledJobIsRunningPastNextRunPct / 100
-            # Alert if current uptime is longer than the average * the configurable percentage
-            if current > (avg * threshold)
-                alerts.push
-                  title: 'Warning:',
-                  message: "This scheduled task has been running longer than #{threshold} times average for the request and may be stuck.",
-                  level: 'warning'
+            deployInfo = new DeployDetails
+              deployId: deployId
+              requestId: requestId
+            deployInfo.fetch().success =>
+                avg = deployInfo.get('deployStatistics')?.averageRuntimeMillis
+                current =  new Date().getTime() - task.get('task').taskId.startedAt
+                threshold = window.config.warnIfScheduledJobIsRunningPastNextRunPct / 100
+                # Alert if current uptime is longer than the average * the configurable percentage
+                if current > (avg * threshold)
+                    @collections.alerts.add
+                      title: 'Warning:',
+                      message: "This scheduled task has been running longer than #{threshold} times the average for the request and may be stuck.",
+                      level: 'warning'
         # Was this task killed by a decommissioning slave?
         if !task.get('isStillRunning')
             updates = task.get('taskUpdates')
@@ -156,11 +162,10 @@
             killedMessage = updates.filter (u) =>
                 return u.taskState == 'TASK_KILLED'
             if decomMessage.length > 0 and killedMessage.length > 0
-                alerts.push
+                @collections.alerts.add
                   title: 'Alert:',
                   message: 'This task was killed due to a slave decommissioning.',
                   level: 'danger'
-        return alerts

     refresh: ->
         @resourcesFetched = false
@@ -173,21 +178,11 @@
             .done =>
                 @fetchResourceUsage() if @models.task.get('isStillRunning')
             .success =>
-                requestId = @models.task.attributes.task.taskRequest.request.id
-                deployId = @models.task.attributes.task.taskRequest.deploy.id
-                deployInfo = new DeployDetails
-                  deployId: deployId
-                  requestId: requestId
-                deployInfo.fetch().success =>
-                    alerts = @getAlerts deployInfo
-                    @collections.alerts.reset()
-                    for alert in alerts
-                        @collections.alerts.add alert
+                @getAlerts()
             .error =>
                 # If this 404s the task doesn't exist
                 app.caughtError()
                 app.router.notFound()
-

         if @collections.s3Logs?.currentPage is 1
             @collections.s3Logs.fetch().error =>


Show the indexing message when it's reindexing

Closes #2

--- lib/fuzzy-finder-view.coffee
+++ lib/fuzzy-finder-view.coffee
@@ -207,11 +207,11 @@
           @projectPaths
       @setArray(listedItems)
       options.done(listedItems) if options.done?
-    else
+
+    if @reloadProjectPaths
       @setLoading("Indexing project...")
-      @loadingBadge.text("")
-
-    if @reloadProjectPaths
+      @loadingBadge.text("0")
+
       @loadPathsTask?.terminate()
       @loadPathsTask = PathLoader.startTask (paths) =>
         @projectPaths = paths


Make ImageEditorView::getPane work with .flexbox-repaint-hack

--- lib/image-editor-view.coffee
+++ lib/image-editor-view.coffee
@@ -62,7 +62,7 @@
   #
   # Returns a {Pane}.
   getPane: ->
-    @parent('.item-views').parent('.pane').view()
+    @parents('.pane').view()

   # Zooms the image out.
   #


- Added plots for accuracy vs. task time for SUI.

--- analyzer/src/analyzer.coffee
+++ analyzer/src/analyzer.coffee
@@ -296,6 +296,7 @@

 analyzeSUIExperiment = (files, options) ->
   suiEvents = []
+  times = []

   fn = (file, done) ->
     async.waterfall [
@@ -305,6 +306,7 @@
         parseLogFile file, parseCb, options
       (data, filename, options, cb) ->
         suiEvents.push extractSUIEvents(data)
+        times.push collectExperimentTimes data, filename, options
         cb(null)
     ], done

@@ -319,7 +321,17 @@
     accuracy = {}
     sum = {}

-    for result in suiEvents
+    userMeanEyeAccuracy = []
+    userKeypressEyeAccuracy = []
+    userBlinkAccuracy = []
+    userMouseAccuracy = []
+
+    for result, i in suiEvents
+      userEyeAcc = {correct: 0, incorrect: 0}
+      userKAcc   = {correct: 0, incorrect: 0}
+      userBAcc   = {correct: 0, incorrect: 0}
+      userMAcc   = {correct: 0, incorrect: 0}
+
       for input of result
         for btnSize of result[input]
           if btnSize is 'event' or btnSize is 'timestamp' then continue
@@ -330,17 +342,46 @@
               correct: []
               incorrect: []

+            # This is correcting for an error in the recorded data. Many-more
+            # incorrect results were recorded than allowed.
             if data.incorrect > data.correct + 2
               data.incorrect = data.correct + 2

             acc[input][btnSize][margin].correct.push data.correct
             acc[input][btnSize][margin].incorrect.push data.incorrect

-            if input is 'k' and btnSize is '31.25' and margin is '20'
-              console.log data.correct, data.incorrect
+            # Added correct/incorrect counts for only eye-input modes.
+            if input isnt 'k'
+              userEyeAcc.correct += data.correct
+              userEyeAcc.incorrect += data.incorrect
+
+            switch input
+              when 'k'
+                userKAcc.correct += data.correct
+                userKAcc.incorrect += data.incorrect
+              when 'b'
+                userBAcc.correct += data.correct
+                userBAcc.incorrect += data.incorrect
+              when 'm'
+                userMAcc.correct += data.correct
+                userMAcc.incorrect += data.incorrect
+
+      # Calculate the mean eye-input mode accuracy.
+      userMeanEyeAccuracy.push(
+        userEyeAcc.correct / (userEyeAcc.incorrect + userEyeAcc.correct))
+
+      userKeypressEyeAccuracy.push(
+        userKAcc.correct / (userKAcc.incorrect + userKAcc.correct))
+
+      userBlinkAccuracy.push(
+        userBAcc.correct / (userBAcc.incorrect + userBAcc.correct))
+
+      userMouseAccuracy.push(
+        userMAcc.correct / (userMAcc.incorrect + userMAcc.correct))

     for input of acc
       for btnSize of acc[input]
+        if +btnSize < 10 then continue
         for margin, data of acc[input][btnSize]
           mean[input] ?= {}
           mean[input][btnSize] ?= {}
@@ -469,6 +510,62 @@
       layout: layout
     plotly.plot data, graphOptions, (err, msg) ->
       if err then console.error error
+
+    # Plot the accuracy with respect to time. (i.e. we are interesting in
+    # determining if accuracy increases with the amount of time the user takes
+    # to complete the experiment.) This will be a scatter-plot, with eye-input
+    # task duration (sum of button and blink) as the x axis and accuracy as the
+    # y-axis.
+    for inputMode, m in [
+      userMeanEyeAccuracy,
+      userKeypressEyeAccuracy,
+      userBlinkAccuracy
+      userMouseAccuracy]
+      data =
+        x: []
+        y: []
+        type: 'scatter'
+        mode: 'markers'
+      for meanAccuracy, i in userMeanEyeAccuracy
+        time = times[i]
+        switch m
+          when 0
+            title = 'SUI Accuracy vs. Mean Eye Task Duration'
+            filename = 'SUI-Accuracy-vs-Time-Mean-Eye'
+            taskDuration = time.s.b.duration + time.s.k.duration
+          when 1
+            title = 'SUI Accuracy vs. Eye Keypress Task Duration'
+            filename = 'SUI-Accuracy-vs-Time-Keypress'
+            taskDuration = time.s.k.duration
+          when 2
+            title = 'SUI Accuracy vs. Eye Blink Task Duration'
+            filename = 'SUI-Accuracy-vs-Time-Blink'
+            taskDuration = time.s.b.duration
+          when 3
+            title = 'SUI Accuracy vs. Mouse Task Duration'
+            filename = 'SUI-Accuracy-vs-Time-Mouse'
+            taskDuration = time.s.m.duration
+
+        data.x.push moment.duration(taskDuration).asSeconds()
+        data.y.push meanAccuracy
+
+      layout =
+        title: title
+        xaxis:
+          title: 'Task Duration (seconds)'
+          showgird: false
+          zeroline: false
+        yaxis:
+          title: 'Accuracy'
+          rangemode: 'tozero'
+      graphOptions =
+        filename: filename
+        fileopt: "overwrite"
+        layout: layout
+      plotly.plot data, graphOptions, (err, msg) ->
+        if err then console.error error
+
+


clearLogItems

clearLogItems

--- lib/notifications-log.coffee
+++ lib/notifications-log.coffee
@@ -22,7 +22,7 @@
     @typesHidden = typesHidden if typesHidden?
     @emitter = new Emitter
     @subscriptions = new CompositeDisposable
-    @subscriptions.add atom.notifications.onDidClearNotifications => @clear()
+    @subscriptions.add atom.notifications.onDidClearNotifications => @clearLogItems()
     @render()
     @subscriptions.add new Disposable => @clearLogItems()


oauth: lots of bug fixes & code cleanup

oauth: lots of bug fixes & code cleanup

--- client/landing/app/MainApp/oauthcontroller.coffee
+++ client/landing/app/MainApp/oauthcontroller.coffee
@@ -3,8 +3,8 @@
 #   KD.singletons.oauthController.authCompleted null, "github"
 class OAuthController extends KDController
   openPopup: (provider)->
-    KD.remote.api.OAuth.getUrl provider, (err, url)=>
-      if err then @notify err
+    KD.remote.api.OAuth.getUrl provider, (err, url)->
+      if err then notify err
       else
         name       = "Login"
         size       = "height=643,width=1143"
@@ -14,12 +14,11 @@
   # This is called from the popup to indicate the process is complete.
   authCompleted: (err, provider)->
     mainController = KD.getSingleton "mainController"
-
-    if err then @notify err
+    if err then notify err
     else
       console.log "authCompleted", provider
       mainController.emit "ForeignAuthCompleted", provider

-  notify: (err)->
-    message = if err then err else "Something went wrong"
-    new KDNotificationView message
+  notify = (err)->
+    message = if err then "Error: #{err}" else "Something went wrong"
+    new KDNotificationView title : message


Get integration name from body

Get integration name from body

--- packages/rocketchat-integrations/server/api/api.coffee
+++ packages/rocketchat-integrations/server/api/api.coffee
@@ -130,7 +130,7 @@
 					Meteor.call 'addOutgoingIntegration',
 						username: 'rocket.cat'
 						urls: [@bodyParams.target_url]
-						name: @bodyParams.data.name
+						name: @bodyParams.name
 						channel: @bodyParams.data.channel_name
 						triggerWords: @bodyParams.data.trigger_words

@@ -141,7 +141,7 @@
 					Meteor.call 'addOutgoingIntegration',
 						username: 'rocket.cat'
 						urls: [@bodyParams.target_url]
-						name: @bodyParams.data.name
+						name: @bodyParams.name
 						channel: @bodyParams.data.username
 						triggerWords: @bodyParams.data.trigger_words


Quick fix for physics timestep issues

Quick fix for physics timestep issues

--- assets/script/Physics.coffee
+++ assets/script/Physics.coffee
@@ -17,6 +17,9 @@
 		@world.allowSleep =
 			yes

+		@secondsPerUpdate =
+			1.0 / 60.0
+
 		@_materials = {}

 	material: (name) ->
@@ -33,20 +36,24 @@
 		physicsSecondsPerRealSecond =
 			1

-		@world.step (dt * physicsSecondsPerRealSecond)
+		# TODO: This is bad! It can over and under count time.
+		while dt > 0
+			dt -= @secondsPerUpdate

-		for body in @world.bodies
-			body.threeObject.position.copy body.position
+			@world.step (@secondsPerUpdate * physicsSecondsPerRealSecond)

-			# For some reason, plain copy doesn't work.
-			# body.threeObject.quaternion.copy body.quaternion
-			tq = body.threeObject.quaternion
-			bq = body.quaternion
+			for body in @world.bodies
+				body.threeObject.position.copy body.position

-			tq.x = bq.x
-			tq.y = bq.y
-			tq.z = bq.z
-			tq.w = bq.w
+				# For some reason, plain copy doesn't work.
+				# body.threeObject.quaternion.copy body.quaternion
+				tq = body.threeObject.quaternion
+				bq = body.quaternion
+
+				tq.x = bq.x
+				tq.y = bq.y
+				tq.z = bq.z
+				tq.w = bq.w

 	setGravity: (v) ->
 		@world.gravity.set v.x, v.y, v.z


mangle during uglify

mangle during uglify

--- Gulpfile.coffee
+++ Gulpfile.coffee
@@ -90,7 +90,7 @@
         .pipe(source('index.js'))
         .pipe(buffer())
         .pipe(sourcemaps.init(loadMaps: true))
-        .pipe(if nodeEnv == 'production' then require('gulp-uglify')(mangle: false) else util.noop())
+        .pipe(if nodeEnv == 'production' then require('gulp-uglify')() else util.noop())
         .pipe(sourcemaps.write('../maps'))
         .pipe(gulp.dest('build/scripts'))
         .pipe(if lr then require('gulp-livereload')(lr) else util.noop())


Compile coffee-script without spawning new processes.:x

--- lib/tintan/compile.coffee
+++ lib/tintan/compile.coffee
@@ -1,7 +1,8 @@
 require 'colors'
-fs    = require 'fs'
-path  = require 'path'
-spawn = require('child_process').spawn
+fs     = require 'fs'
+path   = require 'path'
+coffee = require 'coffee-script'
+spawn  = require('child_process').spawn

 Tintan = null

@@ -19,7 +20,6 @@
   DEFAULT_OPTIONS =
     src: 'src/coffee'        # directory to take .coffee files from
     target: 'Resources'      # directory to put .js files into
-    atomic: false            # should create a file task for each .js target?
     name: 'compile:coffee'   # name of the compiler task to generate

@@ -38,24 +38,15 @@
     return false if sources.length == 0
     compiled = (c for s, c of map)

-    if options.atomic
-      for s, c of map
-        file c, [s], (->
-          compile @prereqs, path.dirname(@name), -> complete()
-        ), async: true
+    for s, c of map
+      file c, [s], (->
+        compile @prereqs[0], @name, -> complete()
+      ), async: true

     Tintan.$.onTaskNamespace options.name, (name)->
       desc "Compile coffee-script sources into #{options.target}"
-      if options.atomic
-        task name, compiled, (->
-          console.log 'compiled'.green + ' coffee-script sources into ' + options.target
-        ), async: true
-      else
-        task name, (->
-          console.log 'compile'.bold + ' coffee-script sources into ' + options.target
-          jake.mkdirP(path.dirname c) for c in compiled
-          compile [from], target, -> complete()
-        ), async: true
+      task name, compiled, ->
+        console.log 'compiled'.green + ' coffee-script sources into ' + options.target

     Tintan.$.onTaskNamespace options.name + ':clean', ->
       desc "Clean coffee-script produced files from #{options.target}"
@@ -63,16 +54,12 @@
         fs.unlink c for c in compiled
     true

-   compile: (files, target, cb)->
-     coffee = path.join(require.resolve('coffee-script'), '../../../bin/coffee')
-     argv = ['--compile', '--output', target].concat files
-     jake.mkdirP target
-     p = spawn coffee, argv
-     p.stdout.on 'data', (data)-> process.stdout.write data
-     p.stderr.on 'data', (data)-> process.stderr.write data
-     p.on 'exit', (status)->
-       fail "Compilation failed with status #{status}" unless status == 0
-       cb()
+   compile: (source, target, cb)->
+     jake.mkdirP path.dirname(target)
+     c = fs.readFileSync source, 'utf-8'
+     j = coffee.compile c
+     fs.writeFileSync target, j, 'utf-8'
+     cb()

    invokeTask: ->
      jake.Task[@options.name].invoke()


Updated to use Workspace::getActivePaneItem

Fixes #6

--- lib/vertical-align.coffee
+++ lib/vertical-align.coffee
@@ -63,5 +63,5 @@
   align:    align
   activate: ->
     atom.workspaceView.command 'vertical-align:align', '.editor', ->
-      editor = atom.workspaceView.getActivePaneItem()
+      editor = atom.workspace.getActivePaneItem()
       align(editor)


reserving __bind and __indexOf

reserving __bind and __indexOf

--- lexer.coffee
+++ lexer.coffee
@@ -523,7 +523,7 @@
 RESERVED = [
   'case', 'default', 'function', 'var', 'void', 'with', 'do'
   'const', 'let', 'enum', 'export', 'import', 'native'
-  '__hasProp', '__extends', '__slice'
+  '__hasProp', '__extends', '__slice', '__bind', '__indexOf'
 ]

 # The superset of both JavaScript keywords and reserved words, none of which may


Forbidding #interp-style interpolation ... Issue #581

--- lexer.coffee
+++ lexer.coffee
@@ -395,20 +395,13 @@
     if str.length < 3 or not starts str, '"'
       @token 'STRING', str
     else
-      lexer =    new Lexer
-      tokens =   []
-      quote =    str.substring 0, 1
-      [i, pi] =  [1, 1]
+      lexer   = new Lexer
+      tokens  = []
+      quote   = str.substring 0, 1
+      [i, pi] = [1, 1]
       while i < str.length - 1
         if starts str, '\\', i
           i += 1
-        else if match = str.substring(i).match INTERPOLATION
-          [group, interp] = match
-          interp = "this.#{ interp.substring(1) }" if starts interp, '@'
-          tokens.push ['STRING', quote + str.substring(pi, i) + quote] if pi < i
-          tokens.push ['IDENTIFIER', interp]
-          i += group.length - 1
-          pi = i + 1
         else if (expr = @balancedString str.substring(i), [['#{', '}']])
           tokens.push ['STRING', quote + str.substring(pi, i) + quote] if pi < i
           inner = expr.substring(2, expr.length - 1)
@@ -518,7 +511,6 @@
 IDENTIFIER    = /^([a-zA-Z\$_](\w|\$)*)/
 NUMBER        = /^(((\b0(x|X)[0-9a-fA-F]+)|((\b[0-9]+(\.[0-9]+)?|\.[0-9]+)(e[+\-]?[0-9]+)?)))\b/i
 HEREDOC       = /^("{6}|'{6}|"{3}\n?([\s\S]*?)\n?([ \t]*)"{3}|'{3}\n?([\s\S]*?)\n?([ \t]*)'{3})/
-INTERPOLATION = /^#([a-zA-Z_@]\w*(\.\w+)*)/
 OPERATOR      = /^(-[\-=>]?|\+[+=]?|[*&|\/%=<>:!?]+)([ \t]*)/
 WHITESPACE    = /^([ \t]+)/
 COMMENT       = /^(\s*\#{3}(?!#)[ \t]*\n+([\s\S]*?)[ \t]*\n+[ \t]*\#{3}|(\s*#(?!##[^#])[^\n]*)+)/
@@ -528,10 +520,10 @@
 LAST_DENT     = /\n([ \t]*)/

 # Regex-matching-regexes.
-REGEX_START        = /^\/[^\/ ]/
-REGEX_INTERPOLATION= /([^\\]#[a-zA-Z_@]|[^\\]#\{.*[^\\]\})/
-REGEX_END          = /^(([imgy]{1,4})\b|\W|$)/
-REGEX_ESCAPE       = /\\[^\$]/g
+REGEX_START         = /^\/[^\/ ]/
+REGEX_INTERPOLATION = /([^\\]#\{.*[^\\]\})/
+REGEX_END           = /^(([imgy]{1,4})\b|\W|$)/
+REGEX_ESCAPE        = /\\[^\$]/g

 # Token cleaning regexes.
 JS_CLEANER      = /(^`|`$)/g


FLEX CODE CLEANUP

FLEX CODE CLEANUP

--- source/Art/Engine/Core/EpochLayout/FlexLayout.coffee
+++ source/Art/Engine/Core/EpochLayout/FlexLayout.coffee
@@ -176,9 +176,8 @@
     hasCrossAlignment = !floatEq 0, crossAlignment

     # main alignment
-    mainPos = if !elementMainAxisIsChildRelative && hasMainAlignment = !floatEq 0, mainAlignment
-      mainAlignment = childrenAlignment[mainCoordinate]
-      (elementMainSizeForChildren - totalMainSize) * mainAlignment
+    mainPos = if !elementMainAxisIsChildRelative
+      (elementMainSizeForChildren - totalMainSize) * childrenAlignment[mainCoordinate]
     else
       0


fixing firefox bug on AudioNode

fixing firefox bug on AudioNode

--- source/app/coffee/audio/components/Oscillator.coffee
+++ source/app/coffee/audio/components/Oscillator.coffee
@@ -35,7 +35,7 @@
         oscillator.originalFrequency = frequency
         oscillator.nofg = nofg
         oscillator.frequency.cancelScheduledValues now
-        oscillator.frequency.setTargetAtTime frequency * @parameters.octave * Audio.CUR_OCTAVE[Audio.OCTAVE_STEP], 0, @parameters.portamento / 1000.0
+        oscillator.frequency.setTargetAtTime frequency * @parameters.octave * Audio.CUR_OCTAVE[Audio.OCTAVE_STEP], 0, @parameters.portamento / 1000.0 || 0.001
         oscillator.detune.setValueAtTime @parameters.detune, 0
         oscillator.connect nofg
         oscillator.start now
@@ -77,7 +77,7 @@
         else
             # frequency
             @activeOscillators[0].frequency.cancelScheduledValues now
-            @activeOscillators[0].frequency.setTargetAtTime frequency * @parameters.octave * Audio.CUR_OCTAVE[Audio.OCTAVE_STEP], 0, @parameters.portamento / 1000.0
+            @activeOscillators[0].frequency.setTargetAtTime frequency * @parameters.octave * Audio.CUR_OCTAVE[Audio.OCTAVE_STEP], 0, @parameters.portamento / 1000.0 || 0.001
         null

     stop: (frequency) ->
@@ -103,7 +103,7 @@
                 null
             else
                 @activeOscillators[0].frequency.cancelScheduledValues now
-                @activeOscillators[0].frequency.setTargetAtTime @active[@active.length-1] * @parameters.octave, 0, @parameters.portamento / 1000
+                @activeOscillators[0].frequency.setTargetAtTime @active[@active.length-1] * @parameters.octave, 0, @parameters.portamento / 1000.0 || 0.001
         null

     @property 'type',


Ensure falsy value doesn't fail conditional

--- services/real-time/app/coffee/WebsocketController.coffee
+++ services/real-time/app/coffee/WebsocketController.coffee
@@ -108,8 +108,8 @@
 							for comment in ranges?.comments or []
 								comment.op.c = encodeForWebsockets(comment.op.c)
 							for change in ranges?.changes or []
-								change.op.i = encodeForWebsockets(change.op.i) if change.op.i
-								change.op.d = encodeForWebsockets(change.op.d) if change.op.d
+								change.op.i = encodeForWebsockets(change.op.i) if change.op.i?
+								change.op.d = encodeForWebsockets(change.op.d) if change.op.d?
 						catch err
 							logger.err {err, project_id, doc_id, fromVersion, ranges, client_id: client.id}, "error encoding range uri component"
 							return callback(err)


Tests no longer need to remove the (removed) headersCookie after each example

--- spec_app/spec/javascripts/helpers/reset_up.js.coffee
+++ spec_app/spec/javascripts/helpers/reset_up.js.coffee
@@ -10,7 +10,6 @@
   up.util.nextFrame =>
     up.reset()
     up.cookies.remove(up.protocol.config.methodCookie)
-    up.cookies.remove(up.protocol.config.headersCookie)

     # Give async reset behavior another frame to play out,
     # then start the next example.


Ignore Atom go-plus package.

Ignore Atom go-plus package.

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -37,6 +37,7 @@
       "nuclide-arcanist"
       "nuclide-blame"
       "linter-markdown"
+      "go-plus"
     ]
     excludeVcsIgnoredPaths: false
     packagesWithKeymapsDisabled: [


Not hiding files in the treeview

Not hiding files in the treeview

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -94,5 +94,4 @@
     honorStyleSettings: true
     checkStyleDevDependencies: true
   "merge-conflicts": {}
-  "tree-view":
-    hideVcsIgnoredFiles: true
+  "tree-view": {}


Fix indentation bug

Fix indentation bug

--- admin/static/coffee/namespaces/index.coffee
+++ admin/static/coffee/namespaces/index.coffee
@@ -109,7 +109,7 @@
                 need_to_increase = true
                 switch formdata.protocol
                     when "Memcached"
-                        formdata.port = 11213
+                        formdata.port = 11211
                     when "Redis"
                         formdata.port = 6379
                     when "Riak"
@@ -121,7 +121,7 @@
                     for namespace in namespaces.models
                         used_ports[namespace.get('port')] = true
                         while formdata.port of used_ports
-                            formdata.port += 123
+                            formdata.port++
             else if @isnt_integer(formdata.port)
                 input_error = true
                 template_error.port_isnt_integer = true


Fix for conversations in private spaces.

--- packages/landsofillusions/memory/flashback.coffee
+++ packages/landsofillusions/memory/flashback.coffee
@@ -134,14 +134,24 @@
       # Listen to location changes.
       @_locationAutorun = Tracker.autorun (computation) =>
         return unless timelineId = LOI.adventure.currentTimelineId()
-        return unless locationId = LOI.adventure.currentLocationId()
+        return unless location = LOI.adventure.currentLocation()

-        # See if we've already shown a flashback at this location.
-        fieldName = "#{timelineId}-#{locationId}"
-        flashbackState = @flashbacksState fieldName
+        locationId = location.id()
+        locationIsPrivate = location.isPrivate()
+
+        if locationIsPrivate
+          # Don't show flashbacks at private locations.
+          flashbackState = null
+
+        else
+          # See if we've already shown a flashback at this location.
+          fieldName = "#{timelineId}-#{locationId}"
+          flashbackState = @flashbacksState fieldName

         @memoryId flashbackState?.memoryId or null
         @memoryPlayed flashbackState?.playStart? or false
+
+        return if locationIsPrivate

         fetchNewMemory = _.some [
           # Fetch a memory if we haven't done it yet.
@@ -161,8 +171,8 @@
           @memoryId memoryId

           # Store the flashback state.
-          @flashbacksState fieldName,
-            memoryId: memoryId
+          flashbackState = if memoryId then memoryId: memoryId else null
+          @flashbacksState fieldName, flashbackState

     destroy: ->
       @_memorySubscriptionAutorun.stop()


missed removing one file.

missed removing one file.

--- app/assets/javascripts/habberdash.js.coffee
+++ app/assets/javascripts/habberdash.js.coffee
@@ -1,7 +1,6 @@
 # jQuery and jQuery UI -- and other plugins
 #= require habberdash/dependencies/jquery-1.7.2
 #= require habberdash/dependencies/jquery-ui-1.8.21.custom
-#= require habberdash/dependencies/jquery_ui_drag_collision
 #= require habberdash/dependencies/jquery_easing
 #= require habberdash/dependencies/jquery_serialize_object
 #


Update knowledges.js.coffee

Update knowledges.js.coffee

--- app/assets/javascripts/knowledges.js.coffee
+++ app/assets/javascripts/knowledges.js.coffee
@@ -17,6 +17,12 @@
 	$('#new_knowledge').submit (e) ->
 		$(this).find('#knowledge_content').val($('#notes').val())

+if(window.location.pathname == '/')
+    $('html, body').css('overflow', 'hidden')
+else
+    $('html, body').css('overflow', 'auto')
+
+
 # $('.knowledge').click ->
 # 	o = @
 # 	$('.knowledge').each ->


Add filter script for select_check_boxes in agreements#new

--- app/assets/javascripts/search-filter.coffee
+++ app/assets/javascripts/search-filter.coffee
@@ -9,3 +9,15 @@
         $(element).show()
       else
         $(element).hide()
+
+$(document).on 'keyup change', '.list-filter', ->
+  $target = $($(this).data('target'))
+  filter = $(this).val()
+  if filter == ""
+    $target.find('.row-list').show()
+  else
+    $target.find('.row-list').each (index, element) ->
+      if $(element).text().toLowerCase().indexOf( filter.toLowerCase() ) != -1
+        $(element).show()
+      else
+        $(element).hide()


increased EXPIRY_TIMEOUT from 1.5 days to 2.5 days

--- app/coffee/ProjectPersistenceManager.coffee
+++ app/coffee/ProjectPersistenceManager.coffee
@@ -3,9 +3,11 @@
 db = require "./db"
 async = require "async"
 logger = require "logger-sharelatex"
+oneDay = 24 * 60 * 60 * 1000

 module.exports = ProjectPersistenceManager =
-	EXPIRY_TIMEOUT: (oneDay = 24 * 60 * 60 * 1000) * 1.5 #ms
+
+	EXPIRY_TIMEOUT: oneDay * 2.5

 	markProjectAsJustAccessed: (project_id, callback = (error) ->) ->
 		db.Project.findOrCreate(where: {project_id: project_id})


fix(create-lightbox): Add translate module

--- app/coffee/modules/common/lightboxes.coffee
+++ app/coffee/modules/common/lightboxes.coffee
@@ -323,7 +323,7 @@
 ## Creare Bulk Userstories Lightbox Directive
 #############################################################################

-CreateBulkUserstoriesDirective = ($repo, $rs, $rootscope, lightboxService, $loading, $model, $timeout, $confirm) ->
+CreateBulkUserstoriesDirective = ($repo, $rs, $rootscope, lightboxService, $loading, $model, $timeout, $confirm, $translate) ->
     link = ($scope, $el, attrs) ->
         form = null
         $scope.displayStatusSelector = false
@@ -425,6 +425,7 @@
     "$tgModel",
     "$timeout",
     "$tgConfirm",
+    "$translate",
     CreateBulkUserstoriesDirective
 ])


updating section performance progress bars to never overflow

--- src/components/cc-dashboard/section-performance.cjsx
+++ src/components/cc-dashboard/section-performance.cjsx
@@ -22,7 +22,7 @@
       incorrectLabel = if percents.incorrect is 100 then "#{percents.incorrect}% incorrect"
       incorrectBar = <BS.ProgressBar
         className="reading-progress-bar progress-bar-incorrect"
-        now={percents.incorrect}
+        now={percents.incorrect-1}
         label={incorrectLabel}
         type="incorrect"
         key={2} />


use span since title is an h4

use span since title is an h4

--- tutor/src/components/course-settings/add-period.cjsx
+++ tutor/src/components/course-settings/add-period.cjsx
@@ -70,7 +70,7 @@
     if @state?.invalid and @state.submitted
       formClasses.push('is-invalid-form')
       disabled = true
-    title =
Add <CourseGroupingLabel courseId={@props.courseId} />

+    title = Add <CourseGroupingLabel courseId={@props.courseId} />
     label = <CourseGroupingLabel courseId={@props.courseId} /> Name

     <BS.Modal


colors by default

colors by default

--- lib/Default.coffee
+++ lib/Default.coffee
@@ -18,7 +18,7 @@
     message     = @colorize @types.line.color, message
     messageType + message

-  COLOR: false
+  COLOR: true
   UNMUTED: 'all'
   MUTED: 'silent'
   TYPES:


:shirt:

:shirt:

--- lib/keybinding-resolver-view.coffee
+++ lib/keybinding-resolver-view.coffee
@@ -50,10 +50,10 @@
       @span class: 'keystroke', keystrokes

     unusedKeyBindings = atom.keymaps.findKeyBindings({keystrokes, target: keyboardEventTarget}).filter (binding) ->
-      binding != keyBinding
+      binding isnt keyBinding

     unmatchedKeyBindings = atom.keymaps.findKeyBindings({keystrokes}).filter (binding) ->
-      binding != keyBinding and binding not in unusedKeyBindings
+      binding isnt keyBinding and binding not in unusedKeyBindings

     @commands.html $$ ->
       @table class: 'table-condensed', =>


fixed code style on servers.lib.server.staticpages.coffee

--- servers/lib/server/staticpages.coffee
+++ servers/lib/server/staticpages.coffee
@@ -1,4 +1,4 @@
-{projectRoot}   = KONFIG
+{ projectRoot } = KONFIG
 fs              = require 'fs'

 authRegisterPath     = "#{projectRoot}/website/authRegister.html"
@@ -10,4 +10,4 @@
 notFoundPath       = "#{projectRoot}/website/404.html"
 notFoundTemplate   = fs.readFileSync notFoundPath, 'utf-8'

-module.exports = {errorTemplate, notFoundTemplate, authRegisterTemplate}
+module.exports = { errorTemplate, notFoundTemplate, authRegisterTemplate }


NavigationMachineItem: Remove VM name from machine item.

--- client/Main/navigation/navigationmachineitem.coffee
+++ client/Main/navigation/navigationmachineitem.coffee
@@ -6,11 +6,11 @@
   stateClasses += "#{state.toLowerCase()} " for state in Object.keys Machine.State

-  constructor:(options = {}, data)->
+  constructor: (options = {}, data) ->

     machine            = data
     @alias             = machine.label
-    path               = KD.utils.groupifyLink "/IDE/VM/#{machine.uid}"
+    path               = KD.utils.groupifyLink "/IDE/my-workspace"

     options.tagName    = 'a'
     options.cssClass   = "vm #{machine.status.state.toLowerCase()} #{machine.provider}"


use snippet description if available

use snippet description if available

--- lib/atomizr.coffee
+++ lib/atomizr.coffee
@@ -174,6 +174,9 @@
       else
         scope = "." + obj.scope

+    if obj.description[0]
+      console.log obj.description[0]
+
     snippet = {}
     snippet[obj.tabTrigger[0]] = { prefix: obj.tabTrigger[0], body: obj.content[0].trim() }


Rename Entry class to MylistEntry class.

--- lib/mylist_atom.coffee
+++ lib/mylist_atom.coffee
@@ -9,9 +9,9 @@
   constructor : (@xml) ->
     @entry = []
     for entry in $(@xml).find('entry')
-      @entry.push new Entry(entry)
+      @entry.push new MylistEntry(entry)

-class Entry
+class MylistEntry
   constructor : (@body) ->
     b = $(@body)
     @title = b.find('title').text()


Add 'test' directory as a spec directory

The test directory is used by minitest which is default in ruby / ruby on rails

--- lib/path_finder.coffee
+++ lib/path_finder.coffee
@@ -13,7 +13,7 @@
     helper: ['app/helpers', 'submodules/app/helpers']
     mailer: ['app/mailers', 'submodules/app/mailers']
     db: ['db', 'submodules/db']
-    spec: ['spec']
+    spec: ['spec', 'test']
     lib: ['lib', 'submodules/lib']
     log: ['log']
     asset: ['app/assets']


fix stupid scoping issue

fix stupid scoping issue

--- lib/command.coffee
+++ lib/command.coffee
@@ -1,7 +1,7 @@
 program = require 'commander'
 log = require 'loggo'
 async = require 'async'
-shake = require '../index'
+shake = require 'shake'
 {join} = require 'path'

 log.setName 'shake'


More natural fix for crossfade region overlapping fade durations.

--- core/app/backbone/factlink/cross_fade_region.coffee
+++ core/app/backbone/factlink/cross_fade_region.coffee
@@ -4,26 +4,23 @@

   defaultFadeTime = 560

-  initialize: ->
-    @_stateToken = 0
-    @_fadeTime = @options?.fadeTime || defaultFadeTime
-
   crossFade: (newView) ->
     if @currentView
-      @$el.fadeOut @_fadeTime, => @show newView
+      @$el.stop()
+      @$el.fadeOut @_fadeTime(), => @show newView
     else
       @show(newView)

   open: (view) ->
+    @$el.stop()
     @$el.hide()
     @$el.html view.el
-    ++@_stateToken
-    @$el.fadeIn @_fadeTime
-
+    @$el.fadeIn @_fadeTime()

   resetFade: ->
-    return if !@$el #if there's no element, nothing's been shown.
-    initialState = ++@_stateToken
-    @$el.fadeOut @_fadeTime, => @reset() if initialState == @_stateToken
+    return unless @$el #if there's no element, nothing's been shown.
+    @$el.stop()
+    @$el.fadeOut @_fadeTime(), => @reset()

+  _fadeTime: -> @options?.fadeTime || defaultFadeTime


Preprocess math into special text for later replacement, to avoid complex escaping behavior of markdown-it

--- lib/formats.coffee
+++ lib/formats.coffee
@@ -137,8 +137,8 @@
     ## Escape all characters that can be (in particular, _s) that appear
     ## inside math mode, to prevent Marked from processing them.
     ## The Regex is exactly marked.js's inline.escape.
-    text = replaceMathBlocks text, (block) ->
-      block.replace /[\\`*{}\[\]()#+\-.!_]/g, '\\$&'
+    #text = replaceMathBlocks text, (block) ->
+    #  block.replace /[\\`*{}\[\]()#+\-.!_]/g, '\\$&'
     #marked.Lexer.rules = {text: /^[^\n]+/} if title
     if title  ## use "single-line" version of Markdown
       text = markdownInline text
@@ -179,16 +179,27 @@

 katex = require 'katex'

-postprocessKatex = (text) ->
-  replaceMathBlocks text, (block) ->
+preprocessKaTeX = (text) ->
+  math = []
+  i = 0
+  text = replaceMathBlocks text, (block) ->
+    i += 1
+    math[i] = block
+    "MATH#{i}ENDMATH"
+  [text, math]
+
+postprocessKaTeX = (text, math) ->
+  #replaceMathBlocks text, (block) ->
+  text.replace /MATH(\d+)ENDMATH/g, (match, p1) ->
+    block = math[p1]
     start$ = /^\$+/.exec block
     end$ = /\$+$/.exec block
     display = start$[0].length >= 2
     block = block[start$[0].length...end$.index]
-    .replace /</g, '<'
-    .replace />/g, '>'
-    .replace /’/g, "'"
-    .replace /‘/g, "`"  ## remove bad Marked automatic behavior
+    #.replace /</g, '<'
+    #.replace />/g, '>'
+    #.replace /’/g, "'"
+    #.replace /‘/g, "`"  ## remove bad Marked automatic behavior
     try
       katex.renderToString block,
         displayMode: display
@@ -207,10 +218,6 @@
       .replace /</g, '<'
       .replace />/g, '>'
       "#{latex}"
-
-postprocess = (text, keepTeX = false) ->
-  text = postprocessKatex text unless keepTeX
-  postprocessCoauthorLinks text

 jsdiff = require 'diff'

@@ -235,13 +242,16 @@
   sanitized

 @formatBody = (format, body, leaveTeX = false) ->
+  [body, math] = preprocessKaTeX body unless leaveTeX
   if format of formats
     body = formats[format] body, false
   else
     console.warn "Unrecognized format '#{format}'"
-  sanitize postprocess body, leaveTeX
+  body = postprocessKaTeX body, math unless leaveTeX
+  sanitize postprocessCoauthorLinks body

 @formatTitle = (format, title, leaveTeX = false) ->
+  [title, math] = preprocessKaTeX title unless leaveTeX
   if format of formats
     title = formats[format] title, true
   else
@@ -250,7 +260,8 @@
   title = title
   .replace /^\s*
\s*/i, ''
   .replace /\s*<\/P>\s*$/i, ''
-  sanitize postprocess title, leaveTeX
+  title = postprocessKaTeX title, math unless leaveTeX
+  sanitize postprocessCoauthorLinks title

 @stripHTMLTags = (html) ->
   html.replace /<[^>]*>/gm, ''


Bug fix on \textcolor and \colorbox

Bug fix on \textcolor and \colorbox


:bug: define some undefined variables

:bug: define some undefined variables

--- lib/helpers.coffee
+++ lib/helpers.coffee
@@ -1,3 +1,5 @@
+child_process = require 'child_process'
+path = require 'path'
 module.exports = Helpers =
   # Based on an API demoed out in:
   #   https://gist.github.com/steelbrain/43d9c38208bf9f2964ab


Removing SectionController from example controller

--- src/example_controller/example_controller.coffee
+++ src/example_controller/example_controller.coffee
@@ -6,7 +6,7 @@
       console.log modal.opened.options.data
 ]

-module.controller "ExampleController", ["$scope", "$timeout", "Table", "SectionController", ($scope, $timeout, Table, SectionController) ->
+module.controller "ExampleController", ["$scope", "$timeout", "Table", ($scope, $timeout, Table) ->

   # Table view section


Use a config schema

Use a config schema

--- lib/preview.coffee
+++ lib/preview.coffee
@@ -2,10 +2,16 @@
 PreviewView = require './preview-view'

 module.exports =
-  configDefaults:
-    updateOnTabChange: true
-    refreshDebouncePeriod: 100
-    liveUpdate: true
+  config:
+    updateOnTabChange:
+      type: 'boolean'
+      default: true
+    refreshDebouncePeriod:
+      type: 'integer'
+      default: 100
+    liveUpdate:
+      type: 'boolean'
+      default: true

   previewView: null
   uri: "atom://atom-preview"


lib: Use DeviceCommunication in edge subscribe handling

--- lib/runtime.coffee
+++ lib/runtime.coffee
@@ -274,28 +274,32 @@
         runtime.uploadInProgress = false

 handleNetworkEdges = (runtime, connection, edges) ->
+    graph = runtime.graph
+    maxCommands = graph.connections.length+edges.length
+    buffer = new commandstream.Buffer 8*maxCommands
+    offset = 0
+
     # Loop over all edges, unsubscribe
-    graph = runtime.graph
-    transport = runtime.transport
     graph.connections.forEach (edge) ->
         if edge.src
             srcId = graph.nodeMap[edge.src.process].id
             srcComp = graph.processes[edge.src.process].component
             srcPort = componentLib.outputPort(srcComp, edge.src.port).id
-            buffer = new commandstream.Buffer(16)
-            commandstream.writeCmd buffer, 8, cmdFormat.commands.SubscribeToPort.id, srcId, srcPort, 0
-            transport.write buffer
+            offset += commandstream.writeCmd buffer, offset,
+                        cmdFormat.commands.SubscribeToPort.id, srcId, srcPort, 0
         return
-
     # Subscribe to enabled edges
     edges.forEach (edge) ->
         srcId = graph.nodeMap[edge.src.process].id
         srcComp = graph.processes[edge.src.process].component
         srcPort = componentLib.outputPort(srcComp, edge.src.port).id
-        buffer = new commandstream.Buffer 16
-        commandstream.writeCmd buffer, 8, cmdFormat.commands.SubscribeToPort.id, srcId, srcPort, 1
-        transport.write buffer
+        offset += commandstream.writeCmd buffer, offset,
+                    cmdFormat.commands.SubscribeToPort.id, srcId, srcPort, 1
         return
+
+    # Send
+    runtime.device.sendCommands buffer, (err) ->
+        throw err if err

 handleNetworkCommand = (command, payload, connection, runtime, transport, debugLevel) ->
     if command is "start" or command is "stop"


When the comet session is lost, reload the current page.

--- src/main/webapp/coffeescripts-hidden/base.coffee
+++ src/main/webapp/coffeescripts-hidden/base.coffee
@@ -2,3 +2,7 @@
   event: (eventName, parameters) ->
     event = jQuery.Event(eventName, parameters)
     jQuery(document).trigger event
+
+$(document).ready ->
+  liftComet?.lift_sessionLost = ->
+    document.location.reload()


Send detached root element to specs

Send detached root element to specs

This way the components that return null from render can be tested for
their absence in the dom

--- test/components/helpers/component-testing.coffee
+++ test/components/helpers/component-testing.coffee
@@ -34,14 +34,15 @@

 Testing = {

-  renderComponent: (component, options) ->
+  renderComponent: (component, options = {}) ->
     options.props ||= {}
-    div = document.createElement('div')
+    root = document.createElement('div')
     promise = new Promise( (resolve, reject) ->
       props = _.clone(options.props)
       props._wrapped_component = component
-      wrapper = React.render( React.createElement(Wrapper, props), div )
+      wrapper = React.render( React.createElement(Wrapper, props), root )
       resolve({
+        root,
         wrapper,
         element: wrapper.refs.element,
         dom: React.findDOMNode(wrapper.refs.element)
@@ -49,7 +50,7 @@
     )
     # defer adding the then callback so it'll be called after whatever is attached after the return
     _.defer -> promise.then ->
-      React.unmountComponentAtNode(div)
+      React.unmountComponentAtNode(root)
       return arguments
     promise


feat(web): add missing methods to angular service;

--- apps/actor-web/app/services/actorService.coffee
+++ apps/actor-web/app/services/actorService.coffee
@@ -1,112 +1,125 @@
 class ActorService
+  isLoggedIn: false
   messenger: null
   currentPeer: null
-  isLoggedIn: false

-  constructor: (@$rootScope, @$sessionStorage) ->
+  constructor: (@$rootScope) ->
     console.log '[AW]ActorService constructor'
-    window.jsAppLoaded = =>
-      @initActor()
-      console.log '[AW]ActorService $broadcast: actorReady'
-      @$rootScope.$broadcast 'actorReady'
+    window.jsAppLoaded = => @initActor()

   initActor: ->
     console.log '[AW]ActorService initActor'
-    window.messenger = @messenger = new actor.ActorApp
-    @isLoggedIn = @messenger.isLoggedIn()
+    @messenger = new actor.ActorApp
+    window.messenger = @messenger
+    @setLoggedIn() if @messenger.isLoggedIn()
     console.log '[AW]ActorService initActor: @isLoggedIn:', @isLoggedIn
-    if @isLoggedIn then @setLoggedIn() else @setLoggedOut()
+    console.log '[AW]ActorService initActor: $broadcast: actorReady'
+    @$rootScope.$broadcast 'actorReady'

-  # isLoggedIn: ->
-  #   @messenger.isLoggedIn()
-
-  # checkAccess: (event, toState, toParams, fromState, fromParams) ->
-  #   console.log '[AW]ActorService checkAccess'
-  #   if toState.data != undefined
-  #     if toState.data.noLogin != undefined && toState.data.noLogin
-  #       console.log '[AW]ActorService checkAccess: before login'
-  #       return
-  #   else
-  #     if @isLoggedIn
-  #       console.log '[AW]ActorService checkAccess: authenticated'
-  #       @$rootScope.isLoggedIn = @$sessionStorage.isLoggedIn
-  #     else
-  #       console.log '[AW]ActorService checkAccess: redirect to login'
-  #       event.preventDefault()
-  #       @$rootScope.$state.go 'login'

   setLoggedIn: () =>
     console.log '[AW]ActorService setLoggedIn'
+    @isLoggedIn = true
     @$rootScope.$state.go 'home'
     @$rootScope.$broadcast 'actorLoggedIn'
-
   setLoggedOut: () =>
     console.log '[AW]ActorService setLoggedOut'
     localStorage.clear()
     @isLoggedIn = false
     @$rootScope.$state.go 'login'
     @$rootScope.$broadcast 'actorLoggedOut'
+  setCurrentPeer: (peer) ->
+    console.log '[AW]ActorService setCurrentPeer'
+    console.log '[AW]ActorService setCurrentPeer: peer:', peer
+    @currentPeer = peer
+
+  bindChat: (peer, callback) ->
+    console.log '[AW]ActorService bindChat'
+    console.log '[AW]ActorService bindChat: peer:', peer
+    @messenger.bindChat peer, callback
+  bindDialogs: (callback) ->
+    console.log '[AW]ActorService bindDialogs'
+    @messenger.bindDialogs (dialogs) ->
+      console.log '[AW]ActorService bindDialogs: dialogs:', dialogs
+      callback dialogs
+  bindGroup: (peer) ->
+    console.log '[AW]ActorService bindGroup'
+    console.log '[AW]ActorService bindGroup: peer:', peer
+  bindTyping: ->
+    console.log '[AW]ActorService bindTyping'
+  bindUser: (peer) ->
+    console.log '[AW]ActorService bindUser'
+    console.log '[AW]ActorService bindUser: peer:', peer
+
+  unbindChat: (peer, callback) ->
+    console.log '[AW]ActorService unbindChat'
+    console.log '[AW]ActorService unbindChat: peer:', peer
+    @messenger.unbindChat peer, callback
+  unbindDialogs: ->
+    console.log '[AW]ActorService unbindDialogs'
+  unbindGroup: ->
+    console.log '[AW]ActorService unbindGroup'
+  unbindTyping: ->
+    console.log '[AW]ActorService unbindTyping'
+  unbindUser: ->
+    console.log '[AW]ActorService unbindUser'
+
+  getAuthPhone: ->
+    console.log '[AW]ActorService getAuthPhone'
+  getAuthState: ->
+    console.log '[AW]ActorService getAuthState'
+  getGroup: ->
+    console.log '[AW]ActorService getGroup'
+  getTyping: ->
+    console.log '[AW]ActorService getTyping'
+  getUid: ->
+    console.log '[AW]ActorService getUid'
+    @messenger.getUid()
+  getUser: (uid) ->
+    console.log '[AW]ActorService getUser'
+    @messenger.getUser uid
+
+  clearChat: ->
+    console.log '[AW]ActorService clearChat'
+  deleteChat: ->
+    console.log '[AW]ActorService deleteChat'
+
+  # Draft
+  loadDraft: (peer) ->
+    console.log '[AW]ActorService loadDraft'
+    @messenger.loadDraft peer
+  saveDraft: (peer, draft) ->
+    console.log '[AW]ActorService saveDraft'
+    console.log '[AW]ActorService saveDraft: draft:', draft
+    if draft != null
+      @messenger.saveDraft peer, draft
+

   requestSms: (phone) ->
     console.log '[AW]ActorService requestSms'
     console.log '[AW]ActorService requestSms: phone:', phone
     @messenger.requestSms phone.toString(), (state) =>
       console.log '[AW]ActorService requestSms: state:', state
-      if state == 'code'
-        console.log '[AW]ActorService requestSms: state: code'
-        @$rootScope.$broadcast 'actorAuthCode'
+      switch state
+        when 'code'
+          console.log '[AW]ActorService requestSms: $broadcast actorAuthCode'
+          @$rootScope.$broadcast 'actorAuthCode'
     , (tag, message, canTryAgain, state) ->
-      console.log '[AW]ActorService requestSms: error'
+      console.log '[AW]ActorService requestSms: error: state:', state

   sendCode: (code) ->
     console.log '[AW]ActorService sendCode'
     @messenger.sendCode code, (state) =>
       console.log '[AW]ActorService sendCode: state:', state
-      if state == 'logged_in'
-        @setLoggedIn()
-      if state == 'signup'
-        @$rootScope.$broadcast 'actorSignUp'
-    , (tag, message, canTryAgain, state) =>
-      console.log '[AW]ActorService sendCode: error'
-      console.log '[AW]ActorService sendCode: tag, message, canTryAgain, state:', tag, message, canTryAgain, state
+      switch state
+        when 'logged_in'
+          @setLoggedIn()
+        when 'logged_in'
+          @$rootScope.$broadcast 'actorSignUp'
+    , (tag, message, canTryAgain, state) ->
+      console.log '[AW]ActorService sendCode: error: state:', state

-  bindDialogs: (callback) ->
-    console.log '[AW]ActorService bindDialogs'
-    @messenger.bindDialogs (items) ->
-      console.log '[AW]ActorService bindDialogs: items', items
-      callback items

-  onConversationClosed: (peer) ->
-    console.log '[AW]ActorService closeConversation'
-    console.log '[AW]ActorService closeConversation: peer:', peer
-    @messenger.onConversationClosed peer
-    @$rootScope.$broadcast 'onConversationClosed', peer
-
-  onConversationOpen: (peer) ->
-    console.log '[AW]ActorService openConversation'
-    console.log '[AW]ActorService openConversation: peer:', peer
-    @setCurrentPeer peer
-    @messenger.onConversationOpen peer
-    @$rootScope.$broadcast 'onConversationOpen', peer
-
-  bindChat: (peer, callback) ->
-    console.log '[AW]ActorService bindChat'
-    console.log '[AW]ActorService bindChat: peer:', peer
-    @messenger.bindChat peer, callback
-
-  unbindChat: (peer) ->
-    console.log '[AW]ActorService unbindChat'
-    console.log '[AW]ActorService unbindChat: peer:', peer
-    @messenger.unbindChat peer, ->
-
-  setCurrentPeer: (peer) ->
-    console.log '[AW]ActorService setCurrentPeer'
-    console.log '[AW]ActorService setCurrentPeer: peer:', peer
-    @currentPeer = peer
-
-  onTyping: ->
-    console.log '[AW]ActorService onTyping'
-    @messenger.onTyping @currentPeer

   sendMessage: (peer, message) ->
     console.log '[AW]ActorService sendMessage'
@@ -114,33 +127,35 @@
     # console.log '[AW]ActorService sendMessage: peer:', peer
     @messenger.sendMessage peer, message

-#  getAuthPhone: () ->
-#    console.log '[AW]ActorService getAuthPhone'
-#    @messenger.getAuthPhone()

-  loadDraft: (peer) ->
-    console.log '[AW]ActorService loadDraft'
-    @messenger.loadDraft peer
+  # Events
+  onAppHidden: ->
+    console.log '[AW]ActorService onAppHidden'
+  onAppVisible: ->
+    console.log '[AW]ActorService onAppVisible'
+  onConversationClosed: (peer) ->
+    console.log '[AW]ActorService onConversationClosed'
+    console.log '[AW]ActorService onConversationClosed: peer:', peer
+    @messenger.onConversationClosed peer
+    @$rootScope.$broadcast 'onConversationClosed', peer
+  onConversationOpen: (peer) ->
+    console.log '[AW]ActorService onConversationOpen'
+    console.log '[AW]ActorService onConversationOpen: peer:', peer
+    @messenger.onConversationOpen peer
+    @$rootScope.$broadcast 'onConversationOpen', peer
+  onDialogsClosed: ->
+    console.log '[AW]ActorService onDialogsClosed'
+  onDialogsOpen: ->
+    console.log '[AW]ActorService onDialogsOpen'
+  onProfileClosed: ->
+    console.log '[AW]ActorService onProfileClosed'
+  onProfileOpen: ->
+    console.log '[AW]ActorService onProfileOpen'
+  onTyping: ->
+    console.log '[AW]ActorService onTyping'
+    @messenger.onTyping @currentPeer

-  saveDraft: (peer, draft) ->
-    console.log '[AW]ActorService saveDraft'
-    console.log '[AW]ActorService saveDraft: draft:', draft
-    if draft != null
-      @messenger.saveDraft peer, draft
-
-  # onGroupOnline: () ->
-  #   console.log '[AW]ActorService onGroupOnline'
-  #   @$rootScope.$broadcast 'onGroupOnline'
-
-  getUid: ->
-    @messenger.getUid()
-
-  getUser: (uid) ->
-    console.log '[AW]ActorService getUser'
-    @messenger.getUser uid
-
-
-ActorService.$inject = ['$rootScope', '$sessionStorage']
+ActorService.$inject = ['$rootScope']

 angular
   .module 'actorWeb'


Filter credit card number and security code if it's not updated

--- node_modules_koding/koding-payment/lib/main.coffee
+++ node_modules_koding/koding-payment/lib/main.coffee
@@ -516,6 +516,11 @@
       callback no, res

 setAccount = (accountCode, data, callback) ->
+  # Remove credit card number if it's not updated
+  if data.cardNumber.indexOf('...') > -1 or data.cardCV == 'XXX'
+    delete data.cardNumber
+    delete data.cardCV
+
   # See https://docs.recurly.com/api/account for XML format
   xml = """<?xml version="1.0" encoding="UTF-8"?>
            <account>


Fix restart for kontrold enabled processes

--- node_modules_koding/processes/src/processes.coffee
+++ node_modules_koding/processes/src/processes.coffee
@@ -96,7 +96,7 @@
     return @child

   kontroldProcess: (options) ->
-    {name,restart,verbose} = options
+    {name,onExit,restart,verbose} = options

     console.log "[PROCESSES][#{@name}] force mode enabled. Trying to stop and kill all other #{name} workers" if verbose and options.kontrol.forceStart

@@ -111,7 +111,7 @@
     }

     # Disable restart for kontrold processes
-    options.restart = no
+    # options.restart = no

     workerProcess.connect()
     console.log "[PROCESSES][#{name}] connected to Kontrold. Waiting for instructions..." if verbose
@@ -124,6 +124,32 @@
       unless @list[name]?.name is name
           @child = @startProcess options
           @populateChildObject options, @child
+          #############
+          ### Child ###
+          #############
+
+          onExit ?= ->
+          @child.on 'exit', ()=>
+            console.log "[PROCESSES][#{name}] did exit." if verbose
+            @emit "exit",@child.pid,name
+            delete @list[name]
+            workerProcess.stopReporter()
+            workerProcess.worker.status = 4
+            workerProcess.fetchWorkerExchange (workerExchange) =>
+              workerProcess.worker.message.command = "ack"
+              workerExchange.publish "input.worker", {worker: workerProcess.worker},
+                appId: "#{workerProcess.worker.uuid}"
+
+          @child.on 'close', () =>
+            console.log "[PROCESSES][#{name}] did close." if verbose
+            @emit "close",@child.pid,name
+            onExit @child.pid,name
+            if restart is yes
+              restartInterval = 1 unless restartInterval
+              setTimeout =>
+                @run options
+              ,restartInterval
+              console.log "[PROCESSES][#{name}] restarting the process in #{restartInterval} msecs." if verbose

           workerProcess.startReporter()
           # Update kontrold worker information with our newly created pid.
@@ -181,6 +207,7 @@
           workerProcess.worker.message.command = "ack"
           workerExchange.publish "input.worker", {worker: workerProcess.worker},
             appId: "#{workerProcess.worker.uuid}"
+

     @on 'childData',(msg) =>
       onMessage msg if "function" is typeof onMessage
@@ -207,14 +234,6 @@
     ### HANDLE SIGNALS and KILLS ###
     ################################

-    # When child_process dies (aka kill -9 <child_pid>, killRequest,etc..)
-    @on 'exit', =>
-      workerProcess.worker.status = 4
-      workerProcess.fetchWorkerExchange (workerExchange) =>
-        workerProcess.worker.message.command = "ack"
-        workerExchange.publish "input.worker", {worker: workerProcess.worker},
-          appId: "#{workerProcess.worker.uuid}"
-
     # When doing ctrl+c, let kontrold now we are dead
     process.on 'SIGINT', =>
       workerProcess.worker.status = 5
@@ -264,26 +283,28 @@
         @kill name
       ,die.after

-    @child.on 'exit',=>
-      console.log "[PROCESSES][#{name}] did exit." if verbose
-      @emit "exit",@child.pid,name
-      delete @list[name]
-    @child.on 'close', () =>
-      console.log "[PROCESSES][#{name}] did close." if verbose
-      @emit "close",@child.pid,name
-      onExit @child.pid,name
-      if restart is yes
-        restartInterval = 1 unless restartInterval
-        setTimeout =>
-          @run options
-        ,restartInterval
-        console.log "[PROCESSES][#{name}] restarting the process in #{restartInterval} msecs." if verbose
-    @child.on 'message',(msg) =>
-      onMessage msg if "function" is typeof onMessage
-      if msg['process-monitor']
-        @emit "monitorData", msg
-      else if options.kontrol.enabled and options.kontrol.nodeProcess
-        @emit "childData", msg
+    # kontrold uses his own onExit and onClose
+    unless options.kontrol?.enabled
+      @child.on 'exit', ()=>
+        console.log "[PROCESSES][#{name}] did exit." if verbose
+        @emit "exit",@child.pid,name
+        delete @list[name]
+      @child.on 'close', () =>
+        console.log "[PROCESSES][#{name}] did close." if verbose
+        @emit "close",@child.pid,name
+        onExit @child.pid,name
+        if restart is yes
+          restartInterval = 1 unless restartInterval
+          setTimeout =>
+            @run options
+          ,restartInterval
+          console.log "[PROCESSES][#{name}] restarting the process in #{restartInterval} msecs." if verbose
+      @child.on 'message',(msg) =>
+        onMessage msg if "function" is typeof onMessage
+        if msg['process-monitor']
+          @emit "monitorData", msg
+        else if options.kontrol.enabled and options.kontrol.nodeProcess
+          @emit "childData", msg

     # console.log @list
     return childObj


add locale folders option

add locale folders option

--- tasks/i18n.coffee
+++ tasks/i18n.coffee
@@ -21,11 +21,12 @@

     options = @options()
     options.i18n = {} unless options.i18n
-    { locales, namespace, localeExtension, defaultExt } = options.i18n
+    { locales, namespace, localeExtension, defaultExt, localeFolders } = options.i18n

     # set default options
     namespace = '$i18n' unless namespace?
     localeExtension = no unless localeExtension?
+    localeFolders   = no unless localeFolders?
     defaultExt = '.html' unless defaultExt?

     if locales and locales.length
@@ -70,6 +71,8 @@
         config.files = _.cloneDeep(@files).map (file) ->
           if localeExtension
             addLocaleExtensionDest file, locale, defaultExt
+          if localeFolders
+            addLocaleFolderDest file, locale, defaultExt
           else
             addLocaleDirnameDest file, locale, defaultExt
           file
@@ -115,6 +118,22 @@

     file.dest = file.orig.dest = dest

+  addLocaleFolderDest = (file, locale, outputExt) ->
+    throw new TypeError 'Missing the tuna destination path' unless file.dest
+
+    if ext = getExtension file.dest
+      relative = file.dest.slice(file.orig.dest.length + 1)
+      dest = path.join file.orig.dest, locale, path.dirname(relative), path.basename(relative, ext) + setExtension ext
+    else
+      if /(\/|\*+)$/i.test file.dest
+        base = file.dest.split('/')
+        dest = path.join path.join.apply(null, base.slice(0, -1)), locale, base.slice(-1).shift()
+      else
+        dest = path.join file.dest, locale
+
+    dest = dest.replace /\.jade$/i, setExtension outputExt
+    file.dest = file.orig.dest = dest
+
   addLocaleDirnameDest = (file, locale, outputExt) ->
     throw new TypeError 'Missing the template destination path' unless file.dest


Use reopenClass syntax

Use reopenClass syntax

--- spec/javascripts/acceptance/admin_users_page.js.coffee
+++ spec/javascripts/acceptance/admin_users_page.js.coffee
@@ -4,47 +4,54 @@
     Review.reset()

     Ember.run ->
-      Review.User.FIXTURES = [
-        {
-          admin: true, id: 'me'
-        },
-        {
-          id: 5
-          image_url: "adas1.jpg"
-          name: "mariusz"
-          nickname: "mariuszDusielak"
-          admin: true
-          permissions: [1,2]
-        }
-      ]
-      Review.Project.FIXTURES = [
-        {
-          id: 1
-          name: 'firstP'
-          grade: "grade1"
-          permission: [1]
-        },
-        {
-          id: 2
-          name: 'SecondP'
-          grade: "grade2"
-          permission: [2]
-        }
-      ]
-      Review.Permission.FIXTURES = [
-        {
-        id: 1
-        user_id: 5
-        project_id: 1
-        allowed: true
-        },
-        {
-          id: 2
-          user_id: 5
-          project_id: 2
-          allowed: true
-        }
-      ]
+      Review.User.reopenClass({
+        FIXTURES: [
+          {
+            id: 5
+            image_url: "adas1.jpg"
+            name: "mariusz"
+            nickname: "mariuszDusielak"
+            admin: true
+            permission_ids: [1,2]
+          },
+          {
+            admin: true
+            id: "me"
+          }
+        ]
+      })
+      Review.Project.reopenClass({
+        FIXTURES: [
+          {
+            id: 1
+            name: "firstP"
+            grade: "grade1"
+            permission: [1]
+          },
+          {
+            id: 2
+            name: "SecondP"
+            grade: "grade2"
+            permission: [2]
+          }
+        ]
+      })
+      Review.Permission.reopenClass({
+        FIXTURES: [
+          {
+            id: 1
+            user_id: 5
+            project_id: 1
+            allowed: true
+          },
+          {
+            id: 2
+            user_id: 5
+            project_id: 2
+            allowed: true
+          }
+        ]
+      })

 test "displays a table with user", ->
   visit '/admin/users'


Add SlideShare

Add SlideShare

--- packages/rocketchat-oembed/server/providers.coffee
+++ packages/rocketchat-oembed/server/providers.coffee
@@ -34,6 +34,9 @@
 providers.registerProvider
 	urls: [new RegExp('https?://www.rdio.com/\\S+'), new RegExp('https?://rd.io/\\S+')]
 	endPoint: 'http://www.rdio.com/api/oembed/?format=json&maxheight=150'
+providers.registerProvider
+	urls: [new RegExp('https?://www.slideshare.net/[^/]+/[^/]+')]
+	endPoint: 'http://www.slideshare.net/api/oembed/2?format=json&maxheight=200'

 RocketChat.oembed = {}
 RocketChat.oembed.providers = providers


fix pagination issues when entering full screen assessment mode

--- src/app/units/partials/directives/unit-contexts.coffee
+++ src/app/units/partials/directives/unit-contexts.coffee
@@ -96,11 +96,14 @@
     # Initially not full screen
     $scope.fullscreen = false

+    oldCurrentPage = $scope.currentPage
     $scope.$watch 'fullscreen', (newValue) ->
-      if newValue is true
+      if newValue
         $scope.pageSize = 9999 # allow infinite scroll
+        $scope.currentPage = 1
       else
         $scope.pageSize = 15 # default size
+        $scope.currentPage = oldCurrentPage

     update_project_details = (student, project) ->
       projectService.updateTaskStats(student, project.stats)


Implement select all matches command (x) with Buffer.traverseRegexMatchesInRange

--- src/atom/command-interpreter/select-all-matches.coffee
+++ src/atom/command-interpreter/select-all-matches.coffee
@@ -3,34 +3,16 @@

 module.exports =
 class SelectAllMatches extends Command
-  @regex: null
+  regex: null

   constructor: (pattern) ->
-    @regex = @regexForPattern(pattern)
+    @regex = new RegExp(pattern, 'g')

   execute: (editor) ->
     rangesToSelect = []
     for selection in editor.getSelections()
-      selectedText = selection.getText()
-      selectionStartIndex = editor.buffer.characterIndexForPosition(selection.getBufferRange().start)
-      for range in @findMatchingRanges(editor, selectedText, selectionStartIndex)
+      editor.buffer.traverseRegexMatchesInRange @regex, selection.getBufferRange(), (match, range) ->
         rangesToSelect.push(range)

     editor.clearSelections()
     editor.addSelectionForBufferRange(range) for range in rangesToSelect
-
-  findMatchingRanges: (editor, text, startIndex) ->
-    return [] unless match = text.match(@regex)
-
-    matchStartIndex = startIndex + match.index
-    matchEndIndex = matchStartIndex + match[0].length
-
-    buffer = editor.buffer
-    startPosition = buffer.positionForCharacterIndex(matchStartIndex)
-    endPosition = buffer.positionForCharacterIndex(matchEndIndex)
-    range = new Range(startPosition, endPosition)
-
-    text = text[(match.index + match[0].length)..]
-    startIndex = matchEndIndex
-    [range].concat(@findMatchingRanges(editor, text, startIndex))
-


defend against nulls in full page navigate

--- lib/assets/javascripts/turbograft/turbolinks.coffee
+++ lib/assets/javascripts/turbograft/turbolinks.coffee
@@ -80,8 +80,11 @@
     fetchReplacement url, options

   @fullPageNavigate: (url) ->
-    triggerEvent('page:before-full-refresh', url: url)
-    document.location.href = url
+    if url?
+      url = (new ComponentUrl(url)).absolute
+      triggerEvent('page:before-full-refresh', url: url)
+      document.location.href = url
+    return

   @pushState: (state, title, url) ->
     window.history.pushState(state, title, url)
@@ -111,7 +114,7 @@

     xhr.onload = ->
       if xhr.status >= 500
-        Turbolinks.fullPageNavigate(url.absolute)
+        Turbolinks.fullPageNavigate(url)
       else
         Turbolinks.loadPage(url, xhr, options)
       xhr = null
@@ -121,7 +124,7 @@
       if xhr.statusText == "abort"
         xhr = null
         return
-      Turbolinks.fullPageNavigate(url.absolute)
+      Turbolinks.fullPageNavigate(url)

     xhr.send()

@@ -137,12 +140,12 @@
       else
         turbohead = new TurboHead(document, upstreamDocument)
         if turbohead.hasAssetConflicts()
-          return Turbolinks.fullPageNavigate(url.absolute)
+          return Turbolinks.fullPageNavigate(url)
         reflectNewUrl url if options.updatePushState
         turbohead.insertNewAssets(-> updateBody(upstreamDocument, xhr, options))
     else
       triggerEvent 'page:error', xhr
-      Turbolinks.fullPageNavigate(url.absolute) if url?
+      Turbolinks.fullPageNavigate(url)

   updateBody = (upstreamDocument, xhr, options) ->
     nodes = changePage(


only add meta data to events if necessary

--- source/server/domain/aggregate.coffee
+++ source/server/domain/aggregate.coffee
@@ -74,8 +74,9 @@
     (this[field] = snapshot[field]) for field of @fields when snapshot[field] != undefined

   record: (event) ->
-    event.meta ?= {}
-    _.extend(event.meta, this.meta ? {}, @_metaData ? {})
+    if this.meta? or @_metaData?
+      event.meta ?= {}
+      _.extend(event.meta, this.meta ? {}, @_metaData ? {})
     @_validateEvent event
     @_events.push event
     @handle(event) if @hasHandlerFor(event)


Make user to make member.

Make user to make member.

--- picoCTF-web/web/coffee/classroom-management.coffee
+++ picoCTF-web/web/coffee/classroom-management.coffee
@@ -44,7 +44,7 @@
       </Button>

     if @props.teacher
-      switchUser = <Button onClick={@switchUserRole.bind(null, user.uid, "user")}>Make User</Button>
+      switchUser = <Button onClick={@switchUserRole.bind(null, user.uid, "member")}>Make Member</Button>
     else
       switchUser = <Button onClick={@switchUserRole.bind(null, user.uid, "teacher")}>Make Teacher</Button>


Fixed FSWebglDirective (WebGL buffer overload)

scope.addPoints -> old BufferGeometry will now be disposed before
add new allocated BufferGeometry.

--- src/main/app/common/directives/FSWebglDirective.coffee
+++ src/main/app/common/directives/FSWebglDirective.coffee
@@ -445,9 +445,6 @@
           else
             currentPointcloudAngle = 90*(Math.PI/180)

-          geometry = new THREE.BufferGeometry()
-          geometry.dynamic = true
-
           new_positions = new Float32Array(points.length*3)
           new_colors = new Float32Array(points.length*3)

@@ -470,12 +467,17 @@
             positions = scope.Float32Concat(positions,new_positions)
             colors = scope.Float32Concat(colors,new_colors)

-
+          geometry = new THREE.BufferGeometry()
+          geometry.dynamic = true
           geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
           geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );

-          material = new THREE.PointsMaterial({size: 0.2, vertexColors: THREE.VertexColors })
-          pointcloud = new THREE.Points(geometry, material)
+          if !pointcloud
+            material = new THREE.PointsMaterial({size: 0.1, vertexColors: THREE.VertexColors })
+            pointcloud = new THREE.Points(geometry, material)
+          else
+            pointcloud.geometry.dispose()
+            pointcloud.geometry = geometry

           degree =  360/resolution
@@ -490,13 +492,13 @@
           #  $log.info currentPointcloudAngle - scope.rad

-        while i < points.length
+        #while i < points.length
           #point = new THREE.Vector3(parseFloat(points[i].x), parseFloat(points[i].z)+450, parseFloat(points[i].y))
           #pointcloud.geometry.vertices.push(point)
           #pointcloud.geometry.dispose()
-          _points[current_point] = points
-          i++
-          current_point++
+          #_points[current_point] = points
+          #i++
+          #current_point++

         #if progress == resolution
           #scope.createScreenShot()
@@ -561,4 +563,4 @@
       scope.init()
       scope.animate()
       return
-])+])


Removed unnessessary code duplication

Removed unnessessary code duplication

--- bokehjs/src/coffee/models/widgets/slider.coffee
+++ bokehjs/src/coffee/models/widgets/slider.coffee
@@ -24,26 +24,19 @@
     min = @mget('start')
     step = @mget('step') or ((max - min)/50)
     logger.debug("slider render: min, max, step = (#{min}, #{max}, #{step})")
+    opts = {
+      orientation: @mget('orientation')
+      animate: "fast",
+      value: @mget('value')
+      min: min,
+      max: max,
+      step: step,
+    }
     if @mget('delay_callback') == true
-      @$('.slider').slider({
-        orientation: @mget('orientation')
-        animate: "fast",
-        stop: @slide,
-        value: @mget('value')
-        min: min,
-        max: max,
-        step: step,
-      })
+      opts.stop = @slide
     else
-      @$('.slider').slider({
-        orientation: @mget('orientation')
-        animate: "fast",
-        slide: _.throttle(@slide, 200),
-        value: @mget('value')
-        min: min,
-        max: max,
-        step: step,
-      })
+      opts.slide = _.throttle(@slide, 200)
+    @$('.slider').slider(opts)
     @$( "##{ @mget('id') }" ).val( @$('.slider').slider('value') )
     return @


feat: Use the native color picker if supported

This presents a slight UX challenge in that the native color picker is uncontrollable from javascript. There is no way to close it or know that it has been closed. Therefore I've dealt with this by 'closing' the aha color picker when the native one opens and handing it control.

--- lib/assets/javascripts/aha/color_picker.js.coffee
+++ lib/assets/javascripts/aha/color_picker.js.coffee
@@ -29,7 +29,7 @@
       @picker.off "click.colorPickerColor"
       @picker.on "click.colorPickerColor", ".small-colorpicker-color", (event) =>
         hex = $(event.target).data('color')
-        @input.minicolors('value', hex)
+        @input.minicolors('value', hex) unless @native
         @setHexColor(hex)
         @closePicker()
         false
@@ -48,13 +48,15 @@
     enableScrolling() if window.enableScrolling
     $(window).off 'click', @clickClosePicker

+    @triggerChange()
+    @picker.hide() if @picker
+
+  triggerChange: () ->
     if @hexColor && @color
       @element.trigger(
         type: 'changeColor'
         color: {hex: @hexColor, converted: @color}
       )
-
-    @picker.hide() if @picker

   createColorPicker: () ->
     picker = $(@template).appendTo("body")
@@ -65,16 +67,21 @@
     initialColor = "##{initialColor}" unless initialColor[0] == '#'

     createColorDiv = (color) ->
-      el = $("

")
+      el = $("

")
       el.addClass('small-colorpicker-color-white') if color.toLowerCase() == 'ffffff'
       el

-    createCustom = () ->
+    createCustom = () =>
       container = $("
").addClass("small-colorpicker-custom-container")
       label = $("
").text("Custom:").addClass("small-colorpicker-custom-label")
       input = $("<input/>")
         .val(initialColor)
         .addClass("small-colorpicker-custom")
+        .attr("type", "color")
+        .css
+          backgroundColor: initialColor
+          color: @fontFromColor(initialColor)
+
       container.append(label)
       container.append(input)

@@ -90,21 +97,39 @@
     colorsContainer.append(createCustom())

     @input = picker.find('.small-colorpicker-custom')
+    @native = @input.prop("type") == "color"
+    @configureCustomPicker(picker)
+
+    colorsContainer.append("

").end()
+
+  configureCustomPicker: (picker) ->
+    if @native
+      @configureNativeCustomPicker(picker)
+    else
+      @configureNonNativeCustomPicker(picker)
+
+    @input.on 'keydown', (event) =>
+      @closePicker() if event.which == 13
+
+  configureNativeCustomPicker: (picker) ->
+    @input.on 'change', (event) =>
+      hex = $(event.target).val()
+      @setHexColor(hex)
+      @triggerChange()
+    @input.on 'click', (event) =>
+      @picker.css("opacity", 0)
+
+  configureNonNativeCustomPicker: (picker) ->
     @input.minicolors
       theme: 'colorpicker'
       change: (hex) =>
         @setHexColor(hex)
-    @input.css
-      backgroundColor: initialColor
-      color: @fontFromColor(initialColor)
-    @input.on 'keydown', (event) =>
-      @closePicker() if event.which == 13
+
     picker.find('.minicolors-panel > div').each (_, div) ->
       $(div).css
         top: parseInt($(div).css('top')) + 3
         left: parseInt($(div).css('left')) + 3
-    colorsContainer.append("

").end()
-
+
   setHexColor: (hex) ->
     return unless /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex)
     unless @options.dontSetElementColor
@@ -119,6 +144,7 @@

   placePicker: () ->
     @picker.show()
+    @picker.css('opacity', 1.0)
     preventScrolling() if window.preventScrolling
     elemRect = @element[0].getBoundingClientRect()
     css = {}


Remove sprocket directive for extensions

--- lib/written/app/assets/javascripts/written.coffee
+++ lib/written/app/assets/javascripts/written.coffee
@@ -1,4 +1,3 @@
 #= require_tree ./vendors
 #= require_tree ./written/core
-#= require_tree ./written/extensions
 #= require_tree ./written/parsers


Uncomment mistakenly code

Uncomment mistakenly code

--- src/components/navbar/book-links.cjsx
+++ src/components/navbar/book-links.cjsx
@@ -10,8 +10,7 @@

   render: ->
     course = CourseStore.get(@props.courseId)
-    return null #unless course?.is_concept_coach
-    links = []
+    return null unless course?.is_concept_coach
     if course.book_pdf_url
       links.push(
         <a key='pdf' target='_blank' href={course.book_pdf_url}>


DRY up the event row into a common component

--- src/components/student-dashboard.cjsx
+++ src/components/student-dashboard.cjsx
@@ -66,6 +66,20 @@
       {moment(event.due_at).format("ddd, MMMM Do")}

+EventRow = React.createClass
+  displayName: 'EventRow'
+  propTypes:
+    cssClass: React.PropTypes.string.isRequired
+    event:    React.PropTypes.object.isRequired
+    feedback: React.PropTypes.string.isRequired
+  render: ->
+

+     <BS.Col className="icon" xs={1}></BS.Col>
+     <BS.Col xs={7}>{@props.children}</BS.Col>
+     <BS.Col xs={2}>{@props.feedback}</BS.Col>
+     <BS.Col xs={2} className="due-at">{moment(@props.event.due_at).format("ddd, MMMM Do")}</BS.Col>
+

+
 ReadingEvent = React.createClass
   displayName: 'ReadingEvent'
   propTypes:
@@ -73,16 +87,9 @@

   render: ->
     event=@props.event
-

-     <BS.Col className="icon" xs={1}>
-     </BS.Col>
-     <BS.Col xs={9}>
-       {event.title} | reference view
-     </BS.Col>
-     <BS.Col xs={2} className="due-at">
-       {moment(event.due_at).format("ddd, MMMM Do")}
-     </BS.Col>
-

+    <EventRow feedback="In Progress" event=event cssClass="reading">
+        {event.title} | reference view
+    </EventRow>

 HomeworkEvent = React.createClass
   displayName: 'HomeworkEvent'
@@ -91,16 +98,9 @@

   render: ->
     event=@props.event
-

-     <BS.Col className="icon" xs={1}>
-     </BS.Col>
-     <BS.Col xs={9}>
-       {event.title} | view feedback | recover credit
-     </BS.Col>
-     <BS.Col xs={2} className="due-at">
-       {moment(event.due_at).format("ddd, MMMM Do")}
-     </BS.Col>
-

+    <EventRow feedback="In Progress" event=event cssClass="homework">
+        {event.title} | view feedback | recover credit
+    </EventRow>

 EventsViewPanel = React.createClass
   displayName: 'EventsViewPanel'


Use Ember.String.camelize in tags input

Use Ember.String.camelize in tags input

--- packages/emberella/lib/views/tags_input.js.coffee
+++ packages/emberella/lib/views/tags_input.js.coffee
@@ -424,7 +424,7 @@
   ###
   addTag: (value = '', idx = get(@, 'cursor')) ->
     type = typeOf(value)
-    method = '_' + ['prepare', type, 'tag'].join('-').camelize()
+    method = '_' + Ember.String.camelize(['prepare', type, 'tag'].join('-'))

     unless typeOf(@[method]) is 'function'
       throw new TypeError("Attempting to add tag of an unsupported type " + type)