:lipstick: Cleanup.

:lipstick: Cleanup.

--- lib/jumpy-view.coffee
+++ lib/jumpy-view.coffee
@@ -130,8 +130,8 @@
                 pane = editorView.getPane()
                 pane.activate()
                 currentEditor.setCursorBufferPosition location.position
-                cursor = pane.find '.cursors .cursor'
-                cursor.addClass 'ripple'
+                pane.find '.cursors .cursor'
+                    .addClass 'ripple'
                 console.log "Jumpy jumped to: #{@firstChar}#{@secondChar} at " +
                     "(#{location.position.row},#{location.position.column})"


Track single subscription and call super destroy

--- lib/linter-lsc.coffee
+++ lib/linter-lsc.coffee
@@ -1,6 +1,5 @@
 linterPath = atom.packages.getLoadedPackage('linter').path
 Linter = require "#{linterPath}/lib/linter"
-{CompositeDisposable} = require 'atom'

 class LinterLsc extends Linter
   # The syntax that the linter handles. May be a string or
@@ -22,11 +21,11 @@

   constructor: (editor) ->
     super(editor)
-    @disposables = new CompositeDisposable
-    @disposables.add atom.config.observe 'linter-lsc.lscExecutablePath', (lscExecutablePath)=>
+    @configSubscription = atom.config.observe 'linter-lsc.lscExecutablePath', (lscExecutablePath)=>
       @executablePath = lscExecutablePath

   destroy: ->
-    @disposables.dispose()
+    super
+    @configSubscription.dispose()

 module.exports = LinterLsc


Use delegate for now

Use delegate for now

--- lib/rails/csrf.coffee
+++ lib/rails/csrf.coffee
@@ -22,7 +22,7 @@

 # Listen for form submissions and inject hidden `authenticity_token`
 # input into forms missing them.
-$(document).on 'submit', 'form', (event) ->
+$(document).delegate 'form', 'submit', (event) ->
   form = $(this)

   # Don't handle remote requests. They'll have a header set instead.


Added hr_department (company_short) to profile cookie

--- app/assets/javascripts/internal/analytics_additions.js.coffee
+++ app/assets/javascripts/internal/analytics_additions.js.coffee
@@ -2,6 +2,7 @@
 jQuery ($) ->
   # Track department/working field from cookie as Event logging
   profile = $.cookie(msettings.myprofileName) or {}
+  ga('send', 'event', 'HRDepartment', profile.hr_department or 'none')
   ga('send', 'event', 'Department', profile.department or 'none')
   ga('send', 'event', 'WorkingField', profile.workingfield or 'none')


[#62240086] removed unnecessary return statement

--- app/assets/javascripts/trade/routes/shipments_route.js.coffee
+++ app/assets/javascripts/trade/routes/shipments_route.js.coffee
@@ -12,7 +12,7 @@
     )).then(new Ember.RSVP.Promise((resolve) =>
       resolve(@controllerFor('purposes').set('content', Trade.Purpose.find()))
     )).then(new Ember.RSVP.Promise((resolve) =>
-      return resolve(Ember.run.sync())
+      resolve(Ember.run.sync())
     ))

   model: (params, queryParams, transition) ->


Make wesabe.canvas.geometry.Size CommonJS-compatible.

--- application/chrome/content/wesabe/canvas/geometry/Size.coffee
+++ application/chrome/content/wesabe/canvas/geometry/Size.coffee
@@ -1,16 +1,14 @@
-wesabe.provide('canvas.geometry.Size')
+Colorizer = require 'util/Colorizer'

-class wesabe.canvas.geometry.Size
-  constructor: (width, height) ->
-    @width = width
-    @height = height
+class Size
+  constructor: (@width, @height) ->

   inspect: (refs, color, tainted) ->
-    s = new wesabe.util.Colorizer()
+    s = new Colorizer()
     s.disabled = !color
     return s
       .yellow('#<')
-      .bold(@constructor?.__module__?.name || 'Object')
+      .bold(@constructor?.__module__?.name or 'Object')
       .print(' ')
       .yellow('{')
       .print(@width)
@@ -19,3 +17,6 @@
       .yellow('}')
       .yellow('>')
       .toString()
+
+
+module.exports = Size


Admin: Integrations: Removed temp code.

Admin: Integrations: Removed temp code.

--- client/admin/lib/views/integrations/adminconfiguredintegrationslistview.coffee
+++ client/admin/lib/views/integrations/adminconfiguredintegrationslistview.coffee
@@ -18,7 +18,4 @@

       return @handleNoItem err  if err

-      # temp code
-      data = data.integrations
-
       @listItems data


gently clip circles

gently clip circles

--- app/graphDrawing.cjsx
+++ app/graphDrawing.cjsx
@@ -199,6 +199,9 @@

 ScatterComponent = React.createClass
+  contextTypes:
+    yScale: React.PropTypes.func.isRequired
+
   propTypes:
     target: React.PropTypes.object.isRequired
     hover: React.PropTypes.bool
@@ -206,6 +209,8 @@

   render: ->
     d = @props.target
+    {yScale} = @context
+    [max, min] = yScale.range()

     if @props.hover
       extraRadius = 3
@@ -219,12 +224,15 @@
     radius = d.radius + extraRadius

     circles = _.map d.scatterValues, (v, i) ->
-      <circle key={i}
-              cx={v.x}
-              cy={v.y}
-              fill={circleColor}
-              r={radius}
-              style={'fill-opacity': d.pointAlpha}/>
+      if v.y < min or v.y > max
+        null
+      else
+        <circle key={i}
+                cx={v.x}
+                cy={v.y}
+                fill={circleColor}
+                r={radius}
+                style={'fill-opacity': d.pointAlpha}/>

     <g>{circles}</g>

@@ -269,16 +277,19 @@

 CrosshairValuePointComponent = React.createClass
+  mixins: [CursorPositionMixin]
+
   propTypes:
     target: React.PropTypes.object.isRequired

-  mixins: [CursorPositionMixin]
   contextTypes:
     params: React.PropTypes.object.isRequired
-
-  render: ->
-    {params} = @context
+    yScale: React.PropTypes.func.isRequired
+
+  render: ->
+    {params, yScale} = @context
     {target} = @props
+    [max, min] = yScale.range()

     if target.type == 'scatter'
       radius = target.radius + 3
@@ -287,15 +298,18 @@

     if @state.value
       d = @state.value.targetValues[target.index]
-      visibility = if d.value? then 'visible' else 'hidden'
-
-      <circle
-        fill={target.color}
-        stroke={params.bgcolor}
-        style={{'stroke-width': 2, visibility}}
-        cx={d.x}
-        cy={d.y}
-        r={radius}/>
+      if d.y < min or d.y > max
+        null
+      else
+        visibility = if d.value? then 'visible' else 'hidden'
+
+        <circle
+          fill={target.color}
+          stroke={params.bgcolor}
+          style={{'stroke-width': 2, visibility}}
+          cx={d.x}
+          cy={d.y}
+          r={radius}/>
     else
       null


Fix mapred config

Fix mapred config

--- hdp/mapred.coffee
+++ hdp/mapred.coffee
@@ -8,11 +8,11 @@
 module.exports.push 'histi/hdp/hdfs'

 module.exports.push module.exports.configure = (ctx) ->
+  return if ctx.mapred_configured
+  ctx.mapred_configured = true
   require('./hdfs').configure ctx
-  module.exports.configured = true
+  require('./mapred_').configure ctx
   jobhistoryserver = ctx.host_with_module 'histi/hdp/mapred_jhs'
-  # Define Users and Groups
-  ctx.config.hdp.mapred_user ?= 'mapred'
   # Options for mapred-site.xml
   ctx.config.hdp.mapred ?= {}
   ctx.config.hdp.mapred['mapreduce.job.counters.max'] ?= 120
@@ -94,7 +94,7 @@
   do_log()

 module.exports.push name: 'HDP MapRed # Configuration', callback: (ctx, next) ->
-  { mapred, hadoop_conf_dir, mapred_queue_acls } = ctx.config.hdp
+  { mapred, hadoop_conf_dir, mapred_user, mapred_group, mapred_queue_acls } = ctx.config.hdp
   modified = false
   do_mapred = ->
     ctx.log 'Configure mapred-site.xml'
@@ -104,6 +104,8 @@
       local_default: true
       properties: mapred
       merge: true
+      uid: mapred_user
+      gid: mapred_group
     , (err, configured) ->
       return next err if err
       modified = true if configured
@@ -119,6 +121,8 @@
       local_default: true
       properties: mapred_queue_acls
       merge: true
+      uid: mapred_user
+      gid: mapred_group
     , (err, configured) ->
       return next err if err
       modified = true if configured
@@ -127,25 +131,25 @@
     next null, if modified then ctx.OK else ctx.PASS
   do_mapred()

-module.exports.push name: 'HDP MapRed # Kerberos', callback: (ctx, next) ->
-  {hadoop_conf_dir} = ctx.config.hdp
-  {realm} = ctx.config.krb5_client
-  mapred = {}
-  mapred['mapreduce.jobhistory.keytab'] ?= "/etc/security/keytabs/jhs.service.keytab"
-  mapred['mapreduce.jobhistory.principal'] ?= "jhs/_HOST@#{realm}"
-  ctx.hconfigure
-    destination: "#{hadoop_conf_dir}/mapred-site.xml"
-    properties: mapred
-    merge: true
-  , (err, configured) ->
-    next err, if configured then ctx.OK else ctx.PASS
-
 ###
 Layout is inspired by [Hadoop recommandation](http://hadoop.apache.org/docs/r2.1.0-beta/hadoop-project-dist/hadoop-common/ClusterSetup.html)
 ###
 module.exports.push name: 'HDP MapRed # HDFS layout', callback: (ctx, next) ->
-  {hadoop_group, hdfs_user, yarn, yarn_user, mapred, mapred_user} = ctx.config.hdp
-  ok = false
+  {hadoop_group, mapred, mapred_user} = ctx.config.hdp
+  modified = false
+  # Carefull, this is a duplicate of "HDP MapRed JHS # HDFS layout"
+  do_mapreduce_history = ->
+    ctx.execute
+      cmd: mkcmd.hdfs ctx, """
+      if hdfs dfs -test -d /mr-history; then exit 1; fi
+      hdfs dfs -mkdir -p /mr-history
+      hdfs dfs -chown #{mapred_user}:#{hadoop_group} /mr-history
+      """
+      code_skipped: 1
+    , (err, executed, stdout) ->
+      return next err if err
+      modified = true if executed
+      do_mapreduce_jobhistory_intermediate_done_dir()
   do_mapreduce_jobtracker_system_dir = ->
     mapreduce_jobtracker_system_dir = mapred['mapreduce.jobtracker.system.dir']
     ctx.log "Create #{mapreduce_jobtracker_system_dir}"
@@ -159,7 +163,7 @@
       code_skipped: 1
     , (err, executed, stdout) ->
       return next err if err
-      ok = true if executed
+      modified = true if executed
       do_mapreduce_jobhistory_intermediate_done_dir()
   do_mapreduce_jobhistory_intermediate_done_dir = ->
     # Default value for "mapreduce.jobhistory.intermediate-done-dir"
@@ -178,7 +182,7 @@
       code_skipped: 1
     , (err, executed, stdout) ->
       return next err if err
-      ok = true if executed
+      modified = true if executed
       do_mapreduce_jobhistory_done_dir()
   do_mapreduce_jobhistory_done_dir = ->
     # Default value for "mapreduce.jobhistory.done-dir"
@@ -197,41 +201,12 @@
       code_skipped: 1
     , (err, executed, stdout) ->
       return next err if err
-      ok = true if executed
+      modified = true if executed
       do_end()
   do_end = ->
-    next null, if ok then ctx.OK else ctx.PASS
-  do_mapreduce_jobtracker_system_dir()
-
-# module.exports.push (ctx, next) ->
-#   @name 'HDP Check # Test ResourceManager UI'
-#   ctx.execute
-#     cmd: 'curl http://#{}:8088'
-#   , (err, executed, stdout) ->
-#     return next err if err
-#     console.log stdout
-#     next err, ctx.PASS
-
-###
-Test JobTracker
----------------
-Run the "teragen" and "terasort" hadoop examples. Will only
-be executed if the directory "/user/test/10gsort" generated
-by this action is not present on HDFS. Delete this directory
-to re-execute the check.
-###
-module.exports.push name: 'HDP MapRed # Check', timeout: -1, callback: (ctx, next) ->
-  ctx.execute
-    cmd: mkcmd.test ctx, """
-    if hdfs dfs -test -d 10gsort; then exit 1; fi
-    hdfs dfs -mkdir 10gsort
-    hadoop jar /usr/lib/hadoop-mapreduce/hadoop-mapreduce-examples-2*.jar teragen 100 10gsort/input
-    hadoop jar /usr/lib/hadoop-mapreduce/hadoop-mapreduce-examples-2*.jar terasort 10gsort/input 10gsort/output
-    """
-    code_skipped: 1
-  , (err, executed, stdout) ->
-    next err, if executed then ctx.OK else ctx.PASS
-
-
-
-
+    next null, if modified then ctx.OK else ctx.PASS
+  do_mapreduce_history()
+
+
+
+


util.test: bugfix copypasta'd elAttributes test

--- coffee/src/util/test.coffee
+++ coffee/src/util/test.coffee
@@ -132,9 +132,9 @@
       expect(typeof view.events()).toBe 'object'

     it 'should have an elAttributes function, that returns an object', ->
-      expect(typeof View.prototype.events).toBe 'function'
+      expect(typeof View.prototype.elAttributes).toBe 'function'
       view = new View options
-      expect(typeof view.events()).toBe 'object'
+      expect(typeof view.elAttributes()).toBe 'object'

     it 'should have render return @', ->
       view = new View(options)


isBooting should be a function

isBooting should be a function

--- lib/connection/client.coffee
+++ lib/connection/client.coffee
@@ -72,16 +72,16 @@
   onConnected: (cb) -> @emitter.on('connected', cb)
   onDisconnected: (cb) -> @emitter.on('disconnected', cb)

-  isBooting: false
+  isBooting: -> false

   isConnected: -> false

-  isActive: -> @isConnected() || @isBooting
+  isActive: -> @isConnected() || @isBooting()

   connected: ->
     @emitter.emit 'connected'
-    if @isBooting
-      @isBooting = false
+    if @isBooting()
+      @isBooting = -> false
       @loading.done()
     @output msg for msg in @queue
     @queue = []
@@ -91,12 +91,12 @@
     @reset()

   booting: ->
-    @isBooting = true
+    @isBooting = -> true
     @loading.working()

   cancelBoot: ->
-    if @isBooting
-      @isBooting = false
+    if @isBooting()
+      @isBooting = -> false
       @reset()

   reset: ->


Reject transactions on domain repository

--- lib/domain_repository.coffee
+++ lib/domain_repository.coffee
@@ -9,27 +9,48 @@
     throw new Error "Missing store" unless @store?
     throw new Error "Missing event bus emitter" unless @emitter?
     throw new Error "Missing logger" unless @logger?
-    @aggregates = []
-    @directListeners = {}
-    @nextDirectListenerKey = 0
-    @transactionQueue = async.queue (transaction, done) =>
-      @logger.log "transaction", "starting"
-      transaction (err) =>
-        if err?
-          @logger.alert "transaction", "failed, rolling back (#{err})"
-          @rollback =>
-            @logger.log "transaction", "rolled back (#{@transactionQueue.length()} more transaction(s) in queue)"
-            done()
-        else
-          @logger.log "transaction", "succeeded, comitting"
-          @commit =>
-            @logger.log "transaction", "committed (#{@transactionQueue.length()} more transaction(s) in queue)"
-            done()
+    @aggregates             = []
+    @directListeners        = {}
+    @nextDirectListenerKey  = 0
+    @transacting            = false
+    @rejectingTransactions  = false
+    @transactionQueue       = async.queue (transaction, done) =>
+      if @rejectingTransactions
+        @logger.warning "transaction", "rejected (#{@transactionQueue.length()} more transaction(s) in queue)"
+        done()
+      else
+        @transacting = true
+        @logger.log "transaction", "starting"
+        transaction (err) =>
+          if err?
+            @logger.alert "transaction", "failed, rolling back (#{err})"
+            @rollback =>
+              @logger.log "transaction", "rolled back (#{@transactionQueue.length()} more transaction(s) in queue)"
+              @transacting = false
+              done()
+          else
+            @logger.log "transaction", "succeeded, comitting"
+            @commit =>
+              @logger.log "transaction", "committed (#{@transactionQueue.length()} more transaction(s) in queue)"
+              @transacting = false
+              done()
     , 1

   transact: (transaction) ->
     @transactionQueue.push transaction
     @logger.log "transaction", "queued (queue size: #{@transactionQueue.length()})"
+
+  rejectTransactions: (callback) ->
+    @rejectingTransactions = true
+    if @transacting || @transactionQueue.length() > 0
+      @transactionQueue.drain = =>
+        @transactionQueue.drain = null
+        callback()
+
+  acceptTransactions: (callback) ->
+    @rejectingTransactions = false
+    @transactionQueue.drain = null
+    callback()

   createNewUid: (callback) ->
     @store.createNewUid callback


#35 fix

#35 fix

--- lib/editor-background.coffee
+++ lib/editor-background.coffee
@@ -852,7 +852,7 @@
     keys = Object.keys @elements
     loaded = (@elements[k] for k in keys when @elements[k]?)
     #console.log 'keys',keys,loaded
-    if true
+    if @elements.editor?

       @insertMain()
       @popup = new popup()
@@ -889,8 +889,8 @@
       @elements.main.appendChild @elements.plane

       @insertTextBackground()
-
-      @colors.workspaceBgColor=style(@elements.editor).backgroundColor
+      if @elements.editor?
+        @colors.workspaceBgColor=style(@elements.editor).backgroundColor
       if @elements.treeView?
         @colors.treeOriginalRGB=style(@elements.treeView).backgroundColor
       @packagesLoaded = true


Return instead of closing dialog, if remote form's response is javascript.

We have a event binded on ajax:success for remote forms in dialogs.
If the response type was javascript we closed the current dialog.

This is sometimes not wanted. Instead we just return from the function and let the javascript handle the closing of the dialog.

--- app/assets/javascripts/alchemy/alchemy.dialog.js.coffee
+++ app/assets/javascripts/alchemy/alchemy.dialog.js.coffee
@@ -101,7 +101,7 @@
       content_type = xhr.getResponseHeader('Content-Type')
       if status == 'success'
         if content_type.match(/javascript/)
-          @close()
+          return
         else
           @dialog_body.html(xhr.responseText)
           @init()


Remove some unnecessary console logs.

Remove some unnecessary console logs.

--- src/UI/report.coffee
+++ src/UI/report.coffee
@@ -340,10 +340,7 @@
     final_entries = []
     for e in entries
         real_day = get_day e.date
-        console.log "#{new Date(e.date)} #{new Date previous} #{new Date real_day} #{(e.date - Math.max(previous, real_day))/1000/3600}"
         if day==0 or e.date - Math.max(previous, real_day) > day_boundary_inactivity
-            if day != real_day
-                console.log day
             day = real_day
         previous = e.date
         e.day = day


Reset the timer that updates feeds every minute when the user manually refreshes a feed.

This is related to commit 64bb1e88b4882ef3c07caa777986ae5bf13c8e84.

--- app/assets/javascripts/ng-services/ng-ReadSvc.js.coffee
+++ app/assets/javascripts/ng-services/ng-ReadSvc.js.coffee
@@ -12,6 +12,8 @@
   # PRIVATE FUNCTION: Load entries via AJAX in the root scope.
   #--------------------------------------------
   load_entries = ->
+    # Reset the timer that updates feeds every minute
+    feedsFoldersSvc.reset_refresh_timer()
     # If busy, do nothing
     return if entriesPaginationSvc.is_busy()
     # If no feed or folder is selected, do nothing
@@ -63,7 +65,6 @@
     # Load a page of entries for the currently selected feed or folder
     #---------------------------------------------
     read_entries_page: ->
-      feedsFoldersSvc.reset_refresh_timer()
       load_entries()

     #--------------------------------------------


cleanup

cleanup

--- lib/watch-view.coffee
+++ lib/watch-view.coffee
@@ -56,7 +56,6 @@

         @counter = document.createElement('div')
         @counter.classList.add('counter')
-        @counter.innerText = "0 / 0"

         @nextButton = document.createElement('button')
         @nextButton.classList.add('btn', 'btn-xs', 'icon', 'icon-chevron-right', 'next-btn')


Send spec-compliant payload when requesting component list

--- src/WebSocket.coffee
+++ src/WebSocket.coffee
@@ -787,7 +787,7 @@

           connection.once 'message', listener

-          send 'component', 'list', collection
+          send 'component', 'list', {}

       # TODO:
       # getsource => source


Removed code for setting current items time as available in bbTimeRanges directive - this is now handled entirely by the TimeService [BOOK-680]

--- src/core/javascripts/controllers/time_range_list.js.coffee
+++ src/core/javascripts/controllers/time_range_list.js.coffee
@@ -299,18 +299,7 @@

       promise.then (dateTimeArr) ->
         $scope.days = []
-        # if it is a move booking, set the date it occurs on to be availble if not already marked as available
-        # doesn't handle multi day bookings as we don't handle multiday bookings
-        if $scope.bb.moving_booking?
-          move_date = $scope.bb.moving_booking.datetime
-          if date <= move_date && edate >= move_date
-            if dateTimeArr[move_date.toISODate()].length == 0
-              v = move_date.minutes() + move_date.hours() * 60
-              dateTimeArr[move_date.toISODate()].splice(0, 0, new BBModel.TimeSlot({time: v, avail: 1}, curItem))
-            else
-              for slot in dateTimeArr[move_date.toISODate()]
-                if (curItem.time and curItem.time.time is slot.time)
-                  slot.avail = 1
+
         for pair in _.sortBy(_.pairs(dateTimeArr), (pair) -> pair[0])
           d = pair[0]
           timeSlotsArr = pair[1]
@@ -322,14 +311,6 @@
               curItem.earliest_time = moment(d).add(timeSlotsArr[0].time, 'minutes')
             if !curItem.earliest_time_slot || curItem.earliest_time_slot.date.isAfter(d)
               curItem.earliest_time_slot = {date: moment(d).add(timeSlotsArr[0].time, 'minutes'), time: timeSlotsArr[0].time}
-
-          # restores data when using the back/forward buttons
-          # add the date and time to the cuurent item if was selected before.
-     #     if day.date.isSame($scope.selected_date) && $scope.selected_slot
-     #       for slot in timeSlotsArr
-     #         if slot.time is $scope.selected_slot.time
-     #           $scope.bb.current_item.date = day
-     #           $scope.bb.current_item.time = slot

           # padding is used to ensure that a list of time slots is always padded
           # out with a certain of values, if its a partial set of results


[Backport] Fixing js error when redirecting /login for anonymous users

--- app/modules/home/working-on/working-on.directive.coffee
+++ app/modules/home/working-on/working-on.directive.coffee
@@ -1,8 +1,10 @@
 WorkingOnDirective = (homeService, currentUserService) ->
     link = (scope, el, attrs, ctrl) ->
-        userId = currentUserService.getUser().get("id")
-
-        ctrl.getWorkInProgress(userId)
+        user = currentUserService.getUser()
+        # If we are not logged in the user will be null
+        if user
+          userId = user.get("id")
+          ctrl.getWorkInProgress(userId)

     return {
         controller: "WorkingOn",


Improved breakpoint handling on line changes

When grabbing a breakpoint's line, prefer getting a fresh line number
from the marker

--- lib/models/breakpoint.coffee
+++ lib/models/breakpoint.coffee
@@ -41,6 +41,8 @@
     @line = @marker.getStartBufferPosition().row + 1

   getLine: ->
+    if @marker
+      return @marker.getStartBufferPosition().row + 1
     return @line

   isLessThan: (other) ->
@@ -58,4 +60,3 @@
     return !@isLessThan(other) && !@isEqual(other)

   @fromMarker: (marker) ->
-


Tweak GitLab file matches (#551)

Tweak GitLab file matches (#551)

--- config.cson
+++ config.cson
@@ -1631,8 +1631,10 @@
 	GitLab:
 		icon: "gitlab"
 		priority: 2
-		colour: "medium-orange"
-		match: /^\.gitlab-ci\.ya?ml$/i
+		match: [
+			[/^\.gitlab$/]
+			[/^\.gitlab-ci\.yml$/, "medium-orange"]
+		]

 	Glade:
 		icon: "glade"


Track whether monster is dead

Track whether monster is dead

--- src/General/Monster.coffee
+++ src/General/Monster.coffee
@@ -4,5 +4,30 @@

     @name = Parse.text el.querySelector(".btm3 .fd2").querySelectorAll ":not(.c)"
     @debuffs = []
+    # Check if monster has the nbardead.png image
+    # this means it's dead
+    @isDead = !!@root.querySelector "img[src='http://ehgt.org/v/s/nbardead.png']"
+
+    # Only calculate stats if monster is not dead
+    if @isDead
+      @HP = 0
+      @MP = 0
+      @SP = 0
+    else
+      stats = [@root.querySelectorAll(".btm4 .btm5")...]
+      if healthRoot = stats[0]
+        @HP = @statPercent healthRoot
+
+      if manaRoot = stats[1]
+        @MP = @statPercent manaRoot
+
+      if spiritRoot = stats[2]
+        @SP = @statPercent spiritRoot
+
       for debuff in [@root.querySelectorAll(".btm6 img")...]
         @debuffs.push Parse.buff debuff
+
+  Monster::statPercent = (root) ->
+    current = root.querySelector(".chb2").width
+    max = root.querySelector(".chb3").width
+    (current / max) * 100


:art: harder

:art: harder

--- lib/snippet-expansion.coffee
+++ lib/snippet-expansion.coffee
@@ -10,22 +10,20 @@
     @selections = [@cursor.selection]

     startPosition = @cursor.selection.getBufferRange().start
-    # Get leading indentation level
-    indent = @editor.lineTextForBufferRow(startPosition.row).match(/^\s*/)[0]
-    # Add proper indentation to the snippet
-    body = @snippet.body.replace(/\n/g, '\n' + indent)
+    if @snippet.lineCount > 1 and indent = @editor.lineTextForBufferRow(startPosition.row).match(/^\s*/)[0]
+      # Add proper leading indentation to the snippet
+      body = @snippet.body.replace(/\n/g, '\n' + indent)

-    tabStopRanges = []
-    for tabStop in @snippet.tabStops
-      ranges = []
-      for range in tabStop
-        newRange = Range.fromObject(range, true) # Don't overwrite the existing range
-        if newRange.start.row # a non-zero start row means that we're not on the initial line
-          # Add on the indent offset so that the tab stops are placed at the correct position
-          newRange.start.column += indent.length
-          newRange.end.column += indent.length
-        ranges.push(newRange)
-      tabStopRanges.push(ranges)
+      tabStops = @snippet.tabStops.map (tabStop) ->
+        tabStop.map (range) ->
+          newRange = Range.fromObject(range, true) # Don't overwrite the existing range
+          if newRange.start.row # a non-zero start row means that we're not on the initial line
+            # Add on the indent offset so that the tab stops are placed at the correct position
+            newRange.start.column += indent.length
+            newRange.end.column += indent.length
+          newRange
+    else
+      {body, tabStops} = @snippet

     @editor.transact =>
       newRange = @editor.transact =>
@@ -33,7 +31,7 @@
       if @snippet.tabStops.length > 0
         @subscriptions.add @cursor.onDidChangePosition (event) => @cursorMoved(event)
         @subscriptions.add @cursor.onDidDestroy => @cursorDestroyed()
-        @placeTabStopMarkers(startPosition, tabStopRanges)
+        @placeTabStopMarkers(startPosition, tabStops)
         @snippets.addExpansion(@editor, this)
         @editor.normalizeTabsInBufferRange(newRange)

@@ -44,9 +42,9 @@

   cursorDestroyed: -> @destroy() unless @settingTabStop

-  placeTabStopMarkers: (startPosition, tabStopRanges) ->
-    for ranges in tabStopRanges
-      @tabStopMarkers.push ranges.map ({start, end}) =>
+  placeTabStopMarkers: (startPosition, tabStops) ->
+    for tabStop in tabStops
+      @tabStopMarkers.push tabStop.map ({start, end}) =>
         @editor.markBufferRange([startPosition.traverse(start), startPosition.traverse(end)])
     @setTabStopIndex(0)


Updated directive to read length of duration array to determine if there are multiple durations

--- src/core/javascripts/controllers/multi_service_select.js.coffee
+++ src/core/javascripts/controllers/multi_service_select.js.coffee
@@ -236,7 +236,7 @@

   $scope.selectDuration = (service) ->

-    if service.max_bookings is 1
+    if service.durations.length is 1
       $scope.addItem(service)
     else


set visuals on decimated glyph

set visuals on decimated glyph

--- bokehjs/src/coffee/renderer/glyph/glyph_renderer.coffee
+++ bokehjs/src/coffee/renderer/glyph/glyph_renderer.coffee
@@ -60,6 +60,7 @@
     @glyph.set_data(source, arg)

     @glyph.set_visuals(source)
+    @decimated_glyph.set_visuals(source)
     @selection_glyph.set_visuals(source)
     @nonselection_glyph.set_visuals(source)


Show range as [start,end> instead of [start,end]

--- lib/text-manipulation.coffee
+++ lib/text-manipulation.coffee
@@ -24,8 +24,8 @@

   # TODO: Override toString? Could be confusing.
   show: ->
-    'ListElement: <' + @start + ' - ' + @end + '> ' +
-      'stripped: <' + @eltStart + ' - ' + @eltEnd + '> : ' +
+    'ListElement: [' + @start + ' - ' + @end + '> ' +
+      'stripped: [' + @eltStart + ' - ' + @eltEnd + '> : ' +
       '"' + (if @strippedElement.length <= 8 then @strippedElement else
                 (@strippedElement.slice 0, 3) + '..' + (@strippedElement.slice -3)) + '"'


Activity: minor styling

Activity: minor styling

--- client/Social/Activity/views/activitycontentpane.coffee
+++ client/Social/Activity/views/activitycontentpane.coffee
@@ -39,11 +39,9 @@
   loadMore: ->
     @emit 'NeedsMoreContent'

-  getContentFrom: ->
-    @listController.getListView().items.last.getData().createdAt
+  getContentFrom: -> @listController.getListView().items.last.getData().createdAt

-  getLoadedCount: ->
-    @listController.getListView().items.length
+  getLoadedCount: -> @listController.getListView().items.length

   removeMessage: MessagePane::removeMessage


Activity: private message consequency fix

Signed-off-by: Sinan Yasar <16f10c154f64d7995217977de070ec760cf09f0e@koding.com>

--- client/Social/Activity/views/privatemessage/pane.coffee
+++ client/Social/Activity/views/privatemessage/pane.coffee
@@ -1,4 +1,6 @@
 class PrivateMessagePane extends MessagePane
+
+  CONSEQUENCY_DELAY = 3e5

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

@@ -184,9 +186,15 @@
   # i know, i invented a word - SY
   doesBreakConsequency: (item, index) ->

+    [prev, next] = @getSiblings index
+    otherItem    = prev or next
+    hasSame      = otherItem and helper.hasSameOwner item, otherItem
+
     [currentDate, otherDate] = @extractDates item, index

-    return Math.abs(currentDate - otherDate) > 3e5
+    return no  unless otherDate
+
+    return Math.abs(currentDate - otherDate) > CONSEQUENCY_DELAY and hasSame

   #


Client: Activity: Updated shouldScrollBottom method to check if messages loaded with scroll or not

--- client/app/lib/components/scroller/scrollermixin.coffee
+++ client/app/lib/components/scroller/scrollermixin.coffee
@@ -25,7 +25,9 @@

     element = React.findDOMNode @refs.scrollContainer

-    if @shouldScrollToBottom
+    if @loadedWithScroll
+      element.scrollTop = @scrollTop + (element.scrollHeight - @scrollHeight)
+    else if @shouldScrollToBottom
       element.scrollTop = element.scrollHeight


Set pending sign up request state earlier

--- client/landing/site.landing/coffee/login/AppView.coffee
+++ client/landing/site.landing/coffee/login/AppView.coffee
@@ -457,7 +457,9 @@

         error : ({responseJSON}) =>

-          usernameCheckTimer = null
+          usernameCheckTimer   = null
+          pendingSignupRequest = no
+
           return  unless @signupModal?

           {forbidden, kodingUser} = responseJSON
@@ -471,8 +473,6 @@
           else
             input.setValidationResult "usernameCheck", "Sorry, there is a problem with \"#{username}\"!"
             USERNAME_VALID = no
-
-          pendingSignupRequest = no

   changeButtonState: (button, state) ->


limit response to 400 characters

limit response to 400 characters

--- src/plugins/kamaln7/urbandictionary/urbandictionary.coffee
+++ src/plugins/kamaln7/urbandictionary/urbandictionary.coffee
@@ -26,7 +26,7 @@
         # Replace new lines with ·
         definition = result.result.definition.replace(/(\r\n|\r|\n)/gm, ' · ')

-        @bot.reply from, to, "#{term}:[#{page}/#{result.pages}]: #{definition}"
+        @bot.reply from, to, "#{term}:[#{page}/#{result.pages}]: #{definition.substring 0, 400}"

   lookUp: (term, page, cb) ->
     url = "http://api.urbandictionary.com/v0/define?term=#{encodeURIComponent(term)}"
@@ -58,4 +58,4 @@
         cb(err, response)

   module.exports =
-    Plugin: Plugin+    Plugin: Plugin


force reload when the username changed

force reload when the username changed

--- core/app/backbone/controllers/profile_controller.coffee
+++ core/app/backbone/controllers/profile_controller.coffee
@@ -60,7 +60,7 @@

   setChannelListing: (username) ->
     channelCollectionView = new ChannelsView(collection: window.Channels)
-    window.Channels.setUsername(username)
-    window.Channels.setupReloading()
+    changed = window.Channels.setUsername(username)
+    window.Channels.setupReloading(changed)
     window.Channels.unsetActiveChannel()
     app.leftMiddleRegion.show(channelCollectionView)


clearer comment

clearer comment

--- js/app.coffee
+++ js/app.coffee
@@ -32,7 +32,10 @@
     @build_has_been_loaded = ko.observable(false)
     @recent_builds_have_been_loaded = ko.observable(false)
     @project_builds_have_been_loaded = ko.observable(false)
-    @selected = ko.observable({}) # Tracks what the dashboard is showing
+
+    # Tracks what page we're on (for pages we care about)
+    @selected = ko.observable({})
+
     @navbar = ko.observable(new CI.inner.Navbar(@selected, @))
     @billing = ko.observable(new CI.inner.Billing)


MachineStateModal: Only show approve view if machine is permanent.

Otherwise prepare the IDE and destroy the modal.

--- client/app/lib/providers/environmentsmachinestatemodal.coffee
+++ client/app/lib/providers/environmentsmachinestatemodal.coffee
@@ -55,7 +55,11 @@
       if not verified
         @buildVerifyView()
       else if not @machine.isApproved()
-        @buildApproveView()
+        if @machine.isPermanent()
+          @buildApproveView()
+        else
+          @prepareIDE()
+          @destroy()
       else
         kd.singletons.paymentController.subscriptions (err, subscription)=>
           kd.warn err  if err?


MachineStateModal: add checks for managed vms

--- client/app/lib/providers/environmentsmachinestatemodal.coffee
+++ client/app/lib/providers/environmentsmachinestatemodal.coffee
@@ -46,6 +46,8 @@
     @machineName = jMachine.label
     @machineId   = jMachine._id
     {@state}     = @machine.status
+    @isManaged   = @machine.provider is 'managed'
+

     @showBusy()
     @show()
@@ -185,6 +187,9 @@

     computeController.on "resize-#{@machineId}", (event) =>
       @updateStatus event, 'resize'
+
+    if @isManaged
+      computeController.on "public-#{@machineId}", @bound 'updateStatus'

     computeController.eventListener.followUpcomingEvents @machine

@@ -427,7 +432,7 @@
   getStateLabel:->

     stateTexts       =
-      Stopped        : 'is turned off.'
+      Stopped        : if @isManaged then 'is not reachable.' else 'is turned off.'
       Starting       : 'is starting now.'
       Stopping       : 'is stopping now.'
       Pending        : 'is resizing now.'
@@ -460,10 +465,10 @@
   createStateButton: ->

     @button      = new KDButtonView
-      title      : 'Turn it on'
+      title      : if @isManaged then 'Search for Nodes' else 'Turn it on'
       cssClass   : 'turn-on state-button solid green medium'
-      icon       : yes
-      callback   : @bound 'turnOnMachine'
+      icon       : !@isManaged
+      callback   : @bound if @isManaged then 'findNodes' else 'turnOnMachine'

     @container.addSubView @button

@@ -574,6 +579,10 @@
     return @show()

+  findNodes: ->
+    new kd.NotificationView title: 'COMING SOON.'
+
+
   turnOnMachine: ->

     trackEvent 'Turn on machine, click',


Delete old en-US.coffee strings file

Delete old en-US.coffee strings file

--- src/code/utils/lang/en-US.coffee
+++ src/code/utils/lang/en-US.coffee
@@ -1,207 +0,0 @@
-module.exports =
-  "~MENU.SAVE": "Save …"
-  "~MENU.OPEN": "Open …"
-  "~MENU.NEW": "New …"
-  "~MENU.SAVE_AS": "Save as …"
-  "~MENU.REVERT_TO_ORIGINAL": "Revert To Original"
-  "~MENU.REVERT_TO_LAST_SAVE": "Revert To Last Save"
-  "~MENU.UNTITLED_MODEL": "Untitled model"
-
-  "~GOOGLE_SAVE.TITLE": "Save Document"
-  "~GOOGLE_SAVE.MAKE_PUBLIC": "make public (read-only)"
-
-  "~OPEN_IN_CODAP.TITLE": "Open in CODAP"
-  "~OPEN_IN_CODAP.DISABLED": "Please save your diagram before opening in CODAP."
-  "~PUBLIC_LINK.OPEN": "Open public link"
-
-  "~NODE.UNTITLED": "Untitled"
-  "~NODE.SIMULATION.VALUE": "Value"
-  "~NODE-EDIT.TITLE": "Name"
-  "~NODE-EDIT.COLOR": "Color"
-  "~NODE-EDIT.IMAGE": "Image"
-  "~NODE-EDIT.BUILT_IN": "Built-In"
-  "~NODE-EDIT.DROPPED": "Dropped"
-  "~NODE-EDIT.REMOTE": "Remote"
-  "~NODE-EDIT.ADD_REMOTE": "Add remote"
-  "~NODE-EDIT.DELETE": "Delete"
-
-  # views/node-value-inspector-view.coffee
-  "~NODE-VALUE-EDIT.INITIAL-VALUE": "Initial Value"
-  "~NODE-VALUE-EDIT.DEFINING_WITH_NUMBERS": "You are defining values with numbers."
-  "~NODE-VALUE-EDIT.DEFINING_WITH_WORDS": "You are defining values with words."
-  "~NODE-VALUE-EDIT.SWITCH_TO_DEFINING_WITH_WORDS": "Switch to define with words."
-  "~NODE-VALUE-EDIT.SWITCH_TO_DEFINING_WITH_NUMBERS": "Switch to define with numbers."
-  "~NODE-VALUE-EDIT.IS_ACCUMULATOR": "Collector"
-  "~NODE-VALUE-EDIT.RESTRICT_POSITIVE": "Can go below zero"
-  "~NODE-VALUE-EDIT.RESTRICT_POSITIVE_UNCHECKED_TOOLTIP": "Click to allow negative values"
-  "~NODE-VALUE-EDIT.RESTRICT_POSITIVE_CHECKED_TOOLTIP": "Click to prevent negative values"
-  "~NODE-VALUE-EDIT.RESTRICT_POSITIVE_DISABLED_TOOLTIP": "Disabled for all collectors by \"Limit values\" simulation setting"
-  "~NODE-VALUE-EDIT.LOW": "Low"
-  "~NODE-VALUE-EDIT.HIGH": "High"
-  "~NODE-VALUE-EDIT.DEPENDENT_VARIABLE": "This node is a dependent variable"
-
-  # views/relation-inspector-view.coffee
-  "~NODE-RELATION-EDIT.COMBINATION_METHOD": "Combine variables using:"
-  "~NODE-RELATION-EDIT.ARITHMETIC_MEAN": "average"
-  "~NODE-RELATION-EDIT.SCALED_PRODUCT": "limiting factor"
-  "~NODE-RELATION-EDIT.UNSELECTED": "Select an option..."
-  "~NODE-RELATION-EDIT.AN_INCREASE_IN": "An increase in"
-  "~NODE-RELATION-EDIT.CAUSES": "causes"
-  "~NODE-RELATION-EDIT.TO": "to"
-  "~NODE-RELATION-EDIT.INCREASES": "increase"
-  "~NODE-RELATION-EDIT.DECREASES": "decrease"
-  "~NODE-RELATION-EDIT.VARIES": "vary"
-  "~NODE-RELATION-EDIT.BY": "by"
-  "~NODE-RELATION-EDIT.ABOUT_THE_SAME": "about the same"
-  "~NODE-RELATION-EDIT.A_LOT": "a lot"
-  "~NODE-RELATION-EDIT.A_LITTLE": "a little"
-  "~NODE-RELATION-EDIT.MORE_AND_MORE": "more and more"
-  "~NODE-RELATION-EDIT.LESS_AND_LESS": "less and less"
-  "~NODE-RELATION-EDIT.CUSTOM": "as described below:"
-  "~NODE-RELATION-EDIT.CUSTOM_HINT": "Draw relationship here"
-  "~NODE-RELATION-EDIT.BECAUSE": "Why do you think so?"
-  "~NODE-RELATION-EDIT.BECAUSE_PLACEHOLDER": "Write your response here"
-  "~NODE-RELATION-EDIT.IS": "is"
-  "~NODE-RELATION-EDIT.ADDED_TO": "added to"
-  "~NODE-RELATION-EDIT.SUBTRACTED_FROM": "subtracted from"
-  "~NODE-RELATION-EDIT.TRANSFERRED_TO": "transferred to"
-  "~NODE-RELATION-EDIT.EACH": "each"
-  "~NODE-RELATION-EDIT.ALL": "All"
-  "~NODE-RELATION-EDIT.MOST": "Most"
-  "~NODE-RELATION-EDIT.HALF": "Half"
-  "~NODE-RELATION-EDIT.SOME": "Some"
-  "~NODE-RELATION-EDIT.A_LITTLE_BIT": "A little bit"
-  "~NODE-RELATION-EDIT.OF": "of"
-  "~NODE-RELATION-EDIT.WILL_FLOW_TO": "will flow to"
-
-  "~TRANSFER_NODE.TITLE": "flow from %{sourceTitle} to %{targetTitle}"
-
-  "~LINK-EDIT.DELETE": "✖ Delete Link"
-  "~LINK-EDIT.TITLE": "Title"
-  "~LINK-EDIT.COLOR": "Color"
-
-  "~ADD-NEW-IMAGE.TITLE": "Add new image"
-  "~ADD-NEW-IMAGE.IMAGE-SEARCH-TAB": "Image Search"
-  "~ADD-NEW-IMAGE.MY-COMPUTER-TAB": "My Computer"
-  "~ADD-NEW-IMAGE.LINK-TAB": "Link"
-
-  # views/palette-inspector-view.coffee
-  "~PALETTE-INSPECTOR.ADD_IMAGE": "New Image"
-  "~PALETTE-INSPECTOR.ADD_IMAGE_SHORT": "New"
-  "~PALETTE-INSPECTOR.ABOUT_IMAGE": "About This Image"
-  "~PALETTE-INSPECTOR.DELETE": "Delete Image"
-  "~PALETTE-INSPECTOR.REPLACE": "Replace Image"
-
-  # views/palette-delete-view.coffee
-  "~PALETTE-DIALOG.TITLE":  "Delete image?"
-  "~PALETTE-DIALOG.DELETE": "Delete"
-  "~PALETTE-DIALOG.REPLACE": "and replace with"
-  "~PALETTE-DIALOG.OK": "ok"
-  "~PALETTE-DIALOG.CANCEL": "✖ cancel"
-
-  # views/image-metadata-view.coffee
-  "~METADATA.TITLE": "Title"
-  "~METADATA.LINK": "Link"
-  "~METADATA.CREDIT": "Credit"
-
-  # views/image-browser-view.coffee
-  "~IMAGE-BROWSER.PREVIEW": "Preview Your Image"
-  "~IMAGE-BROWSER.ADD_IMAGE": "Add Image"
-  "~IMAGE-BROWSER.SEARCH_HEADER": "Search for images"
-  "~IMAGE-BROWSER.SEARCH_BUTTON_LABEL": "Search"
-  "~IMAGE-BROWSER.NO_IMAGES_FOUND": "Sorry, no images found."
-  "~IMAGE-BROWSER.TRY_ANOTHER_SEARCH": "Try another search, or browse images below."
-  "~IMAGE-BROWSER.SEARCHING": "Searching openclipart.org for %{page} of \"%{query}\""
-  "~IMAGE-BROWSER.SEARCHING_FIRST_PAGE": "first page"
-  "~IMAGE-BROWSER.SEARCHING_PAGE": "page %{page}"
-  "~IMAGE-BROWSER.NO_EXTERNAL_FOUND": "No openclipart.org results found for \"%{query}.\""
-  "~IMAGE-BROWSER.ALREADY-IN-PALETTE": "Already in palette"
-  "~IMAGE-BROWSER.PREVIOUS": "‹ Previous"
-  "~IMAGE-BROWSER.NEXT": "Next ›"
-
-  "~IMAGE-BROWSER.PLEASE_DROP_IMAGE": "Please drop an image or enter an image url"
-  "~IMAGE-BROWSER.DROP_IMAGE_FROM_BROWSER": "Drop image from browser here"
-  "~IMAGE-BROWSER.TYPE_OR_PASTE_LINK": "Or type or paste a link to the image you want to use:"
-  "~IMAGE-BROWSER.IMAGE_URL": "Image URL"
-  "~IMAGE-BROWSER.PREVIEW_IMAGE": "Preview Image"
-  "~IMAGE-BROWSER.PLEASE_DROP_FILE": "Please select or drop a file"
-  "~IMAGE-BROWSER.DROP_IMAGE_FROM_DESKTOP": "Drop image from desktop here"
-  "~IMAGE-BROWSER.CHOOSE_FILE": "Or choose a file from your desktop:"
-  "~IMAGE-BROWSER.PROVIDER_MESSAGE": "Image search courtesy of openclipart.org"
-
-  "~COLOR.YELLOW": "Yellow"
-  "~COLOR.DARK_BLUE": "Dark Blue"
-  "~COLOR.LIGHT_BLUE": "Light Blue"
-  "~COLOR.MED_BLUE": "Blue"
-  "~COLOR.DARK_GRAY": "Dark Gray"
-  "~COLOR.LIGHT_GRAY": "Light Gray"
-  "~COLOR.MEDIUM_GRAY": "Gray"
-  "~COLOR.DATA": "Codap Orange"
-
-  # google-file-interface
-  "~FILE.CHECKING_AUTH": "Checking authorization..."
-  "~FILE.CONFIRM": "Are you sure?"
-  "~FILE.DOWNLOADING": "Downloading..."
-  "~FILE.FILENAME": "Filename"
-  "~FILE.UPLOADING": "Uploading..."
-  "~FILE.CONFIRM_ORIGINAL_REVERT": "Are you sure you want to revert to the original version?"
-  "~FILE.CONFIRM_LAST_SAVE_REVERT": "Are you sure you want to revert to the last save?"
-
-
-  "~DOCUMENT.ACTIONS.SIMULATE": "Simulate"
-  "~DOCUMENT.ACTIONS.RUN": "Run"
-  "~DOCUMENT.ACTIONS.DATA.RECORD-1": "Record 1"
-  "~DOCUMENT.ACTIONS.DATA.POINT": "Data Point"
-  "~DOCUMENT.ACTIONS.DATA.RECORD": "Record"
-  "~DOCUMENT.ACTIONS.DATA.STREAM": "Data Stream"
-  "~DOCUMENT.ACTIONS.DATA.STOP": "Stop"
-  "~DOCUMENT.ACTIONS.DATA.RECORDING": "Recording"
-  "~DOCUMENT.ACTIONS.SAVE_TO_GRAPHS": "Save to graphs"
-  "~DOCUMENT.ACTIONS.SHOW_MINI_GRAPHS": "Show mini-graphs"
-  "~DOCUMENT.ACTIONS.QUICK_TEST": "Quick-test mode"
-  "~DOCUMENT.ACTIONS.UNDO": "Undo"
-  "~DOCUMENT.ACTIONS.REDO": "Redo"
-  "~DOCUMENT.ACTIONS.NO_DEFINED_LINKS": "There must be at least one link with a defined relationship."
-
-  "~SIMULATION.SIMULATION_SETTINGS": "Simulation Settings"
-  "~SIMULATION.DIAGRAM_SETTINGS": "Diagram settings"
-  "~SIMULATION.VIEW_SETTINGS": "View settings"
-  "~SIMULATION.STEP_UNIT": "Each calculation is 1"
-  "~SIMULATION.DURATION": "Calculations per run"
-  "~SIMULATION.CAP_VALUES": "Limit values to min/max range"
-  "~SIMULATION.COMPLEXITY.DIAGRAM_ONLY": "Diagram only tools"
-  "~SIMULATION.COMPLEXITY.BASIC": "Basic (increases/decreases) relationships"
-  "~SIMULATION.COMPLEXITY.EXPANDED": "Expanded set of relationships including custom graphs"
-  "~SIMULATION.COMPLEXITY.COLLECTORS": "Include collectors"
-  "~SIMULATION.RELATIONSHIP_SYMBOLS": "Show relationship symbols"
-
-  "~DROP.ONLY_IMAGES_ALLOWED": "Sorry, only images are allowed."
-
-  "~DROPZONE.DROP_IMAGES_HERE": "Drop image here"
-  "~DROPZONE.SQUARES_LOOK_BEST": "(Squares look best.)"
-
-  "~RELATIONSHIP.NO_RELATION": "No relation defined"
-
-  "~CODAP.INTERACTIVE_FRAME.TITLE": "SageModeler"
-  "~CODAP.SIMULATION.RUN": "run"
-  "~CODAP.SIMULATION.EXPERIMENT": "Exp.#"
-  "~CODAP.SIMULATION.STEPS": "steps"
-  "~CODAP.SIMULATION.STEPS.DESCRIPTION": "Number of steps in the simulation."
-
-  "~TIME.STEP":   "Step"
-  "~TIME.SECOND": "Second"
-  "~TIME.MINUTE": "Minute"
-  "~TIME.HOUR":   "Hour"
-  "~TIME.DAY":    "Day"
-  "~TIME.WEEK":   "Week"
-  "~TIME.MONTH":  "Month"
-  "~TIME.YEAR":   "Year"
-
-  "~TIME.STEP.PLURAL":   "Steps"
-  "~TIME.SECOND.PLURAL": "Seconds"
-  "~TIME.MINUTE.PLURAL": "Minutes"
-  "~TIME.HOUR.PLURAL":   "Hours"
-  "~TIME.DAY.PLURAL":    "Days"
-  "~TIME.WEEK.PLURAL":   "Weeks"
-  "~TIME.MONTH.PLURAL":  "Months"
-  "~TIME.YEAR.PLURAL":   "Years"


Add logging in summary for empty SKU elements.

--- src/coffee/product-import.coffee
+++ src/coffee/product-import.coffee
@@ -60,9 +60,13 @@
   _extractUniqueSkus: (products) ->
     skus = []
     for product in products
-      skus.push(product.masterVariant.sku) if product.masterVariant?.sku
+      if product.masterVariant?.sku
+        skus.push(product.masterVariant.sku)
+      else @_summary.emptySKU++
       for variant in product.variants
-        skus.push(variant.sku) if variant.sku
+        if variant.sku
+          skus.push(variant.sku)
+        else @_summary.emptySKU++
     return _.uniq(skus,false)


Added: unbind function to restore initial state

--- src/aria-tips.coffee
+++ src/aria-tips.coffee
@@ -11,6 +11,8 @@

     arrowDelta = 6

+    unbinders = []
+
     oppositePosition = (position) ->
         switch position
             when 'top'    then 'bottom'
@@ -20,12 +22,20 @@

     attachTooltips = ->
+        unbindAll()
         tips = document.querySelectorAll '[role=tooltip]'
         for tip in tips
             # Tips need to be appended to body for global positioning.
             document.body.appendChild tip
             controls = document.querySelectorAll "[aria-describedby=#{tip.id}]"
-            bindHoverEvents.call control for control in controls
+            for control in controls
+                unbinder = bindHoverEvents.call control
+                unbinders.push unbinder
+
+
+    unbindAll = ->
+        unbinder() for unbinder in unbinders
+        unbinders = []

     positionTooltip = (control)->
@@ -109,5 +119,17 @@
         @addEventListener 'mouseover', onMouseOver
         @addEventListener 'mouseout', onMouseOut

-    return bind: -> attachTooltips()
+        unbindEvents = =>
+            tip.removeEventListener 'mouseover', onMouseOver
+            tip.removeEventListener 'mouseout', onMouseOut
+            @removeEventListener 'mouseover', onMouseOver
+            @removeEventListener 'mouseout', onMouseOut
+
+        return unbindEvents
+
+    return {
+        bind: -> attachTooltips()
+        unbind: -> unbindAll()
+    }
+
 )


Always use dev unless in production

Always use dev unless in production

--- app/lib/config.coffee
+++ app/lib/config.coffee
@@ -119,12 +119,8 @@
       invitationId: '502bfa73516bcb3c600003e9'
       workflowId: '502a701e516bcb0001000002'

-env = if window.jasmine
-  'test'
-else if window.location.port is '9294'
+env = if window.location.port > 1024
   'developmentRemote'
-else if window.location.port > 1024
-  'developmentLocal'
 else
   'production'


Fix thread selection with `cmd` and `shift` keys in the thread list

Summary:
We recently added a `shouldComponentUpdate` method to ListTabular to
improve scrolling performance. However, this was preventing ListTabular
from updating the selected state of its items when we selected new
threads via cmd or shift keys.

This occurred because instead of passing data as props for each of ListTabular's
items, we are passing a function that calculates the props for each
item, so when we diffed old props and new props in shouldComponentUpdate,
given that the function reference never changes, we thought that the props
hadn't changed and prevented a re render, when in fact the props for each item
generated by that function might actually change.

Unfortunately, we can't use shouldComponentUpdate in this component
given how it is structured

Test Plan: manual

Reviewers: evan, spang, halla

Reviewed By: spang

Differential Revision: https://phab.nylas.com/D3837

--- src/components/list-tabular.cjsx
+++ src/components/list-tabular.cjsx
@@ -37,10 +37,6 @@
     window.addEventListener('resize', @onWindowResize, true)
     @setupDataSource(@props.dataSource)
     @updateRangeState()
-
-  shouldComponentUpdate: (nextProps, nextState) =>
-    not Utils.isEqualReact(nextProps, @props) or
-    not Utils.isEqualReact(nextState, @state)

   componentWillUnmount: =>
     window.removeEventListener('resize', @onWindowResize, true)
@@ -211,15 +207,17 @@

   _rowForItem: (item, idx) =>
     return false unless item
-    <ListTabularItem key={item.id ? idx}
-                     item={item}
-                     itemProps={@props.itemPropsProvider?(item, idx) ? {}}
-                     metrics={top: idx * @props.itemHeight, height: @props.itemHeight}
-                     columns={@props.columns}
-                     onSelect={@props.onSelect}
-                     onClick={@props.onClick}
-                     onReorder={@props.onReorder}
-                     onDoubleClick={@props.onDoubleClick} />
+    <ListTabularItem
+      key={item.id ? idx}
+      item={item}
+      itemProps={@props.itemPropsProvider?(item, idx) ? {}}
+      metrics={top: idx * @props.itemHeight, height: @props.itemHeight}
+      columns={@props.columns}
+      onSelect={@props.onSelect}
+      onClick={@props.onClick}
+      onReorder={@props.onReorder}
+      onDoubleClick={@props.onDoubleClick}
+    />

   # Public: Scroll to the DOM node provided.
   #


WindowController: minor optimization

WindowController: minor optimization

--- src/core/windowcontroller.coffee
+++ src/core/windowcontroller.coffee
@@ -267,10 +267,10 @@
   registerWindowResizeListener:(instance)->
     @windowResizeListeners[instance.id] = instance
     instance.on "KDObjectWillBeDestroyed", =>
-      delete @windowResizeListeners[instance.id]
+      @windowResizeListeners[instance.id] = null

   unregisterWindowResizeListener:(instance)->
-    delete @windowResizeListeners[instance.id]
+    @windowResizeListeners[instance.id] = null

   notifyWindowResizeListeners: (event)->
     event or= type : "resize"


[Group Notifications] Added group left notification type

--- workers/social/lib/social/models/activity/bucketactivity.coffee
+++ workers/social/lib/social/models/activity/bucketactivity.coffee
@@ -27,8 +27,10 @@
         'CInstalleeBucket'
         'CGroupJoinerBucket'
         'CGroupJoineeBucket'
+        'CGroupLefterBucket'
+        'CGroupLefteeBucket'
       ]
       as          : 'content'

   @create =({constructor:{name}})->
-    new (require('bongo').Base.constructors[name+'Activity'] or this)+    new (require('bongo').Base.constructors[name+'Activity'] or this)


pull out notification room to env variable

--- scripts/sns-notifications.coffee
+++ scripts/sns-notifications.coffee
@@ -1,7 +1,7 @@
 module.exports = (robot) ->
-  # Handle all notifications
+  room = process.env.HUBOT_NOTIFICATION_ROOM
   robot.on "sns:notification", (msg) ->
-    robot.messageRoom("46691_curbot_stage_notifications@conf.hipchat.com",
+    robot.messageRoom(room,
       """
       Received notification:
         Topic:      #{msg.topic}


Move sortBy variable to instance.

Move sortBy variable to instance.

--- spec/javascripts/application/seeds_store_spec.js.coffee
+++ spec/javascripts/application/seeds_store_spec.js.coffee
@@ -44,55 +44,57 @@
       expect(@subject.update(listByName()))
         .eventually.notify(done)
     describe 'name', ->
-      sortBy = 'name'
+      beforeEach () ->
+        @sortBy = 'name'
       describe 'asc', ->
         list = listByName()
         sortOrderAsc = true
         it 'from the beginning', (done) ->
-          expect(@subject.readFromAll(sortBy, sortOrderAsc, 0, 1)).eventually
+          expect(@subject.readFromAll(@sortBy, sortOrderAsc, 0, 1)).eventually
             .eql([list[0]]).notify(done)
         it 'in the middle', (done) ->
-          expect(@subject.readFromAll(sortBy, sortOrderAsc, 1, 2)).eventually
+          expect(@subject.readFromAll(@sortBy, sortOrderAsc, 1, 2)).eventually
             .eql([list[1], list[2]]).notify(done)
         it 'beyond scope', (done) ->
-          expect(@subject.readFromAll(sortBy, sortOrderAsc, 5, 2)).eventually
+          expect(@subject.readFromAll(@sortBy, sortOrderAsc, 5, 2)).eventually
             .eql([list[5]]).notify(done)
       describe 'desc', ->
         list = listByName().reverse()
         sortOrderAsc = false
         it 'from the beginning', (done) ->
-          expect(@subject.readFromAll(sortBy, sortOrderAsc, 0, 1)).eventually
+          expect(@subject.readFromAll(@sortBy, sortOrderAsc, 0, 1)).eventually
             .eql([list[0]]).notify(done)
         it 'in the middle', (done) ->
-          expect(@subject.readFromAll(sortBy, sortOrderAsc, 1, 2)).eventually
+          expect(@subject.readFromAll(@sortBy, sortOrderAsc, 1, 2)).eventually
             .eql([list[1], list[2]]).notify(done)
         it 'beyond scope', (done) ->
-          expect(@subject.readFromAll(sortBy, sortOrderAsc, 5, 2)).eventually
+          expect(@subject.readFromAll(@sortBy, sortOrderAsc, 5, 2)).eventually
             .eql([list[5]]).notify(done)
     describe 'stars', ->
-      sortBy = 'stars'
+      beforeEach () ->
+        @sortBy = 'stars'
       describe 'asc', ->
         list = listByStars()
         sortOrderAsc = true
         it 'from the beginning', (done) ->
-          expect(@subject.readFromAll(sortBy, sortOrderAsc, 0, 1)).eventually
+          expect(@subject.readFromAll(@sortBy, sortOrderAsc, 0, 1)).eventually
             .eql([list[0]]).notify(done)
         it 'in the middle', (done) ->
-          expect(@subject.readFromAll(sortBy, sortOrderAsc, 1, 2)).eventually
+          expect(@subject.readFromAll(@sortBy, sortOrderAsc, 1, 2)).eventually
             .eql([list[1], list[2]]).notify(done)
         it 'beyond scope', (done) ->
-          expect(@subject.readFromAll(sortBy, sortOrderAsc, 5, 2)).eventually
+          expect(@subject.readFromAll(@sortBy, sortOrderAsc, 5, 2)).eventually
             .eql([list[5]]).notify(done)
       describe 'desc', ->
         list = listByStars().reverse()
         sortOrderAsc = false
         it 'from the beginning', (done) ->
-          expect(@subject.readFromAll(sortBy, sortOrderAsc, 0, 1)).eventually
+          expect(@subject.readFromAll(@sortBy, sortOrderAsc, 0, 1)).eventually
             .eql([list[0]]).notify(done)
         it 'in the middle', (done) ->
-          expect(@subject.readFromAll(sortBy, sortOrderAsc, 1, 2)).eventually
+          expect(@subject.readFromAll(@sortBy, sortOrderAsc, 1, 2)).eventually
             .eql([list[1], list[2]]).notify(done)
         it 'beyond scope', (done) ->
-          expect(@subject.readFromAll(sortBy, sortOrderAsc, 5, 2)).eventually
+          expect(@subject.readFromAll(@sortBy, sortOrderAsc, 5, 2)).eventually
             .eql([list[5]]).notify(done)


Fix stats functions

Fix stats functions

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

--- src/champions.coffee
+++ src/champions.coffee
@@ -11,23 +11,41 @@
     @skills = params.skills

   ##
+  # Applies stats to the base stats of this champion.
+  #
+  applyStats: (stats) ->
+    stats = {}
+    for stat in lol.stats.names
+      unless stat is "as"
+        stats[stat] = (@baseStats[stat] || 0) + (stats[stat] || 0)
+      else
+        stats[stat] = (@baseStats[stat] || 0) * (stats[stat] || 0)
+    return stats
+
+  ##
   # Gets the stats of the champion at a given level
   # without items, masteries, runes, etc.
   #
   getVanillaStats: (level) ->
-    stats = {}
+    return applyStats getAdditionalStats level
+
+  ##
+  # Gets the additional stats to add to the champion for the given level.
+  #
+  getAdditionalStats: (level) ->
+    added = {}

     for stat in lol.stats.names
-      stats[stat] = ((@baseStats[stat] || 0) unless stat is "as") + (level - 1) * (@statsPerLevel[stat] || 0)
+      added[stat] = (level - 1) * (@statsPerLevel[stat] || 0)

-    return stats
+    return added

   ##
   # Gets the stats of the champion at a given level
   # with the given items, masteries, and runes.
   #
   getStats: (level, items, masteries, runes) ->
-    return lol.stats.combine [@getVanillaStats(level), lol.stats.combine(items), lol.stats.combine(masteries), lol.stats.combine(runes)]
+    return applyStats lol.stats.combine [@getAdditionalStats(level), lol.stats.combine(items), lol.stats.combine(masteries), lol.stats.combine(runes)]

 lol.champions.list = {}
 lol.champions._def = (name, params) ->


Remove extra whitespace

Remove extra whitespace

--- src/cli/index.coffee
+++ src/cli/index.coffee
@@ -79,7 +79,6 @@
     method = "pnet.#{method}"
   params.method = method

-
 if isEmpty(params.method)
   console.error "ERROR: must specify a phish.net API method param"
   process.exit 1


collision with regular bounds

collision with regular bounds

--- src/collision.coffee
+++ src/collision.coffee
@@ -226,7 +226,6 @@
             y: target.y + yw
             xw: xw
             yw: yw
-          )
         else
           error "Bounds object isn't a rectangle"


move marks along with slider

move marks along with slider

--- app/lib/canvas-graph.coffee
+++ app/lib/canvas-graph.coffee
@@ -192,6 +192,9 @@
     val = classifier.el.find('#ui-slider').val()
     zoomRanges = classifier.zoomRanges
     zoomLevel  = classifier.zoomLevel
+
+    if val > 0.0
+      console.log 'SLIDER MOVED!!!'

     # plot points
     for i in [0...@dataLength]
@@ -203,16 +206,17 @@
       @ctx.fillRect(x+@leftPadding,y,2,2)
     if @marks
       for mark in @marks.all
-        scaledMin = ((mark.dataXMinRel + @toDataXCoord(@leftPadding) - xMin) / (xMax - xMin)) * (@canvas.width-@leftPadding)
-        scaledMax = ((mark.dataXMaxRel + @toDataXCoord(@leftPadding) - xMin) / (xMax - xMin)) * (@canvas.width-@leftPadding)
+        scaledMin = ((mark.dataXMinRel + @toDataXCoord(@leftPadding) - xMin - val) / (xMax - xMin)) * (@canvas.width-@leftPadding)
+        scaledMax = ((mark.dataXMaxRel + @toDataXCoord(@leftPadding) - xMin - val) / (xMax - xMin)) * (@canvas.width-@leftPadding)
         mark.element.style.width = (scaledMax-scaledMin) + "px"
-        mark.element.style.left = (scaledMin) + "px"
+        mark.element.style.left = ( scaledMin ) + "px"
         console.log 'SCAALED [',scaledMin,',',scaledMax,']'
         mark.save(scaledMin, scaledMax)

         console.log """
                       -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
                       ----------------- DEBUG REPORT ----------------
+                                            val: #{val}  <--- slider value
                               canvasGraph.scale: #{@scale}
                                            xMin: #{xMin}  <------------- lightcurve display limits
                                            xMax: #{xMax}


group bundle: remove sharedMethods block

--- workers/social/lib/social/models/bundle/groupbundle.coffee
+++ workers/social/lib/social/models/bundle/groupbundle.coffee
@@ -17,9 +17,6 @@

   @set
     sharedEvents      :
-      static          : []
-      instance        : []
-    sharedMethods     :
       static          : []
       instance        : []
     permissions       :


group bundle: expose #fetchLimits method for the UI

--- workers/social/lib/social/models/bundle/groupbundle.coffee
+++ workers/social/lib/social/models/bundle/groupbundle.coffee
@@ -1,6 +1,8 @@
 JBundle = require '../bundle'

 module.exports = class JGroupBundle extends JBundle
+
+  {permit} = require '../group/permissionset'

   @share()

@@ -10,6 +12,9 @@
     sharedEvents      :
       static          : []
       instance        : []
+    sharedMethods     :
+      static          : []
+      instance        : ['fetchLimits']
     permissions       :
       'manage payment methods'  : []
       'change bundle'           : []
@@ -28,3 +33,5 @@
         ]
         default       : 'not allowed'

+  @fetchLimits$ = permit 'change bundle',
+    success: (client, callback)-> @fetchLimits callback


Kite: Added event emitters for kite errors.

--- client/landing/app/MainApp/kite/kitecontroller.coffee
+++ client/landing/app/MainApp/kite/kitecontroller.coffee
@@ -31,6 +31,7 @@
   createKite:(kiteName, correlationName, kiteKey)->
     kite = new Kite { kiteName, correlationName, kiteKey }
     kite.on 'destroy', => @destroyKite kite
+    kite.on "KiteError", (err) => @emit "KiteError", err
     return kite

   # notification = null


groups menu item commented out

groups menu item commented out

--- client/landing/app/MainApp/sidebar/sidebarview.coffee
+++ client/landing/app/MainApp/sidebar/sidebarview.coffee
@@ -318,7 +318,7 @@
       { title : "Activity" }
       { title : "Topics" }
       { title : "Members" }
-      { title : "Groups",  path : "GroupsFake" }
+      # { title : "Groups",  path : "GroupsFake" }
       { title : "Develop", loggedIn : yes,  path : "StartTab" }
       { title : "Apps" }
     ]


Need to escape keywords such as 'in' from MathJax

--- common/lib/xmodule/xmodule/js/src/capa/display.coffee
+++ common/lib/xmodule/xmodule/js/src/capa/display.coffee
@@ -299,24 +299,40 @@
     target = "display_#{element.id.replace(/^input_/, '')}"

     if jax = MathJax.Hub.getAllJax(target)[0]
-      eqn = @latexify($(element).val())
+      eqn = @mathjax_preprocessor($(element).val())
+      #eqn = $(element).val()
       MathJax.Hub.Queue ['Text', jax, eqn],
         [@updateMathML, jax, element]

-  latexify: (eqn) ->
+  mathjax_preprocessor: (eqn) ->
     ###
     Translate 6.002x conventions for subscripts to standard Latex, e.g.
       'R3'  --> 'R_{3}'
       'vGS' --> 'v_{GS}'
       'K/2*(vIN-VT)^2' --> 'K/2*(v_{IN}-V_{T})^2'
     ###
-    subscript_replace = (match) ->
-      # Default keywords are taken from capa/calc.py
-      default_keywords = ['sin', 'cos', 'tan', 'sqrt', 'log10', 'log2', 'ln', 'arccos', 'arcsin', 'arctan', 'abs', 'pi']
-      if match in default_keywords
+
+    # Default keywords are taken from capa/calc.py
+    default_keywords = ['sin', 'cos', 'tan', 'sqrt', 'log10', 'log2', 'ln', 'arccos', 'arcsin', 'arctan', 'abs', 'pi']
+
+    # Escape keywords are strings that have special meaning in 6.002x that should not be processed by Jax
+    escape_keywords = ['in']
+
+    # First, perform subscript insertion
+    replace_subscript = (match) ->
+      if match in default_keywords or match in escape_keywords
         return match
-      return match[0] + '_{' + match.substr(1) + '}'
-    return eqn.replace(/[A-Za-z]\w+/g, subscript_replace)
+      else
+        return match[0] + '_{' + match.substr(1) + '}'
+    eqn = eqn.replace(/[A-Za-z]\w+/g, replace_subscript)
+
+    # Second, escape 6.002x-specific keywords from MathJax
+    replace_escape_keyword = (match) ->
+      return '"' + match + '"' # Force MathJax plain text
+    for escape_keyword in escape_keywords
+      eqn = eqn.replace(escape_keyword, replace_escape_keyword)
+
+    return eqn

   updateMathML: (jax, element) =>
     try


Catching variable timeout

Catching variable timeout

--- lib/views/cloud-variables-and-functions-view.coffee
+++ lib/views/cloud-variables-and-functions-view.coffee
@@ -105,12 +105,17 @@
     cell.text ''
     promise = spark.getVariable SettingsHelper.get('current_core'), variableName
     promise.done (e) =>
+      cell.removeClass()
       if !!e.ok
+        cell.addClass 'icon icon-issue-opened text-error'
         dfd.reject()
       else
-        cell.removeClass 'loading'
         cell.text e.result
         dfd.resolve e.result
+    , (e) =>
+      cell.removeClass()
+      cell.addClass 'icon icon-issue-opened text-error'
+      dfd.reject()
     dfd.promise

   toggleWatchVariable: (variableName) ->


:fire: remove debug comment

:fire: remove debug comment

--- src/renderer/components/doc-detail-title-component.coffee
+++ src/renderer/components/doc-detail-title-component.coffee
@@ -16,7 +16,6 @@

   constructLink = (name) ->
     match = name.match(/^(.+)\.(.+)$/)
-    console.log match

       <Link style={styles.link} href={"/class/#{match[1]}"}>{match[1]}</Link>
       .


:sparkles: refactor toggle visibility button

--- src/renderer/components/doc-factor-title-component.coffee
+++ src/renderer/components/doc-factor-title-component.coffee
@@ -43,6 +43,7 @@
           marginTop: 10
           marginLeft: 0

+
     <DocTitleComponent title={@props.current.name} kindString={@props.current.kindString} dstyle={dstyle} style={Array.prototype.concat.apply([], [styles.base, @props.style])}>
       {
         unless @props.collapsed


Use pending course if available

Use pending course if available

And show a validation message afterwards

--- src/course/new-registration.cjsx
+++ src/course/new-registration.cjsx
@@ -17,7 +17,9 @@
     course: React.PropTypes.instanceOf(Course)

   componentWillMount: ->
-    course = @props.course or new Course({ecosystem_book_uuid: @props.collectionUUID})
+    course = @props.course or
+      User.getCourse(@props.collectionUUID) or
+      new Course({ecosystem_book_uuid: @props.collectionUUID})
     course.channel.on('change', @onCourseChange)
     @setState({course})

@@ -26,13 +28,21 @@

   onComplete: ->
     @state.course.persist(User)
-    Navigation.channel.emit('show.panel', view: 'task')
+    Navigation.channel.emit('show')

   onCourseChange: ->
-    if @state.course.isRegistered()
+    if @state.course.isValidated() or @state.course.isRegistered()
       # wait 1.5 secs so our success message is briefly displayed, then call onComplete
       _.delay(@onComplete, 1500)
     @forceUpdate()
+
+  renderValidated: ->
+

+

+        Course validation is complete.
+

+
You can now login or signup to start using Concept Coach

+

   renderComplete: (course) ->

@@ -44,13 +54,11 @@

   renderCurrentStep: ->
     {course} = @state
-    if course.isIncomplete()
+    if course.isValidated()
+      @renderValidated()
+    else if course.isIncomplete()
       title = if @isTeacher() then '' else 'Register for this Concept Coach course'
-      <InviteCodeInput validateOnly={@props.validateOnly}
-        course={course}
-        currentCourses={User.courses}
-        title={title}
-      />
+      <InviteCodeInput course={course} currentCourses={User.registeredCourses()} title={title} />
     else if course.isPending()
       <ConfirmJoin
         title={"Would you like to join #{@state.course.description()}?"}


Fix #1437. Unneeded ref in existential assignment.

--- nodes.coffee
+++ nodes.coffee
@@ -1641,8 +1641,9 @@
       (shared.compileToFragments o), @makeCode(" #{@operator} "), (@second.compileToFragments o, LEVEL_OP)
     @wrapInBraces fragments

+  # Keep reference to the left expression, unless this an existential assignment
   compileExistence: (o) ->
-    if @first.isComplex()
+    if !o.isExistentialEquals and @first.isComplex()
       ref = new Literal o.scope.freeVariable 'ref'
       fst = new Parens new Assign ref, @first
     else


tagging more nodes as keys.

tagging more nodes as keys.

--- nodes.coffee
+++ nodes.coffee
@@ -557,7 +557,7 @@
 # an access into the object's prototype.
 exports.Access = class Access extends Base
   constructor: (@name, tag) ->
-    @name.accessed = yes
+    @name.asKey = yes
     @proto = if tag is 'proto' then '.prototype' else ''
     @soak  = tag is 'soak'

@@ -707,6 +707,7 @@
         prop = new Assign prop.properties[0].name, prop, 'object'
       else if prop not instanceof Assign and prop not instanceof Comment
         prop = new Assign prop, prop, 'object'
+      prop.variable.base.asKey = yes if prop instanceof Value
       indent + prop.compile(o, LEVEL_TOP) + join
     props = props.join ''
     obj   = "{#{ props and '\n' + props + '\n' + @tab }}"
@@ -1673,9 +1674,9 @@
     if statement then Expressions.wrap [call] else call

   literalArgs: (node) ->
-    node instanceof Literal and node.value is 'arguments' and not node.accessed
+    node instanceof Literal and node.value is 'arguments' and not node.asKey
   literalThis: (node) ->
-    (node instanceof Literal and node.value is 'this' and not node.accessed) or
+    (node instanceof Literal and node.value is 'this' and not node.asKey) or
       (node instanceof Code and node.bound)

 # Unfold a node's child if soak, then tuck the node under created `If`


nodes: filled in missing LEVEL_* in In::compile*Test

--- nodes.coffee
+++ nodes.coffee
@@ -1140,13 +1140,13 @@
     [sub, ref] = @object.cache o, LEVEL_OP
     [cmp, cnj] = if @negated then [' !== ', ' && '] else [' === ', ' || ']
     tests = for item, i in @array.base.objects
-      (if i then ref else sub) + cmp + item.compile o
+      (if i then ref else sub) + cmp + item.compile o, LEVEL_OP
     tests = tests.join cnj
     if o.level < LEVEL_OP then tests else "(#{tests})"

   compileLoopTest: (o) ->
     [sub, ref] = @object.cache o, LEVEL_LIST
-    code = utility('indexOf') + ".call(#{ @array.compile o }, #{ref}) " +
+    code = utility('indexOf') + ".call(#{ @array.compile o, LEVEL_LIST }, #{ref}) " +
            if @negated then '< 0' else '>= 0'
     return code if sub is ref
     code = sub + ', ' + code


gave a space between two string

gave a space between two string

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -682,7 +682,7 @@
       # Permanent option is only valid for paid accounts
       # if its passed then we need to check payment
       #
-      if permanent and @provider in ['managed','koding'] and options.group is 'koding'
+      if permanent and @provider in ['managed', 'koding'] and options.group is 'koding'
                    # TODO: we can limit this for koding provider only ~ GG

         Payment = require '../payment'


Fix post reply when no conversation entities

fixes #90

--- lib/assets/javascripts/views/post/post_reply_form.js.coffee
+++ lib/assets/javascripts/views/post/post_reply_form.js.coffee
@@ -26,13 +26,15 @@
     textarea_view = @textareaMentionsView()
     return unless textarea_view

-    Marbles.DOM.setAttr(textarea_view.el, 'disabled', 'disabled')
-
     text = ""

     entities = @post().conversation_entities
     entities_display_text = {}
     num_pending_profiles = entities.length
+
+    return unless entities.length
+
+    Marbles.DOM.setAttr(textarea_view.el, 'disabled', 'disabled')

     entityCompleteFn = (entity, profile) =>
       inline_mention = new TentStatus.InlineMentionsManager.InlineMention(


Fix selected_ids on creditors

Fix selected_ids on creditors

--- app/assets/javascripts/app/controllers/admin/creditors.js.coffee
+++ app/assets/javascripts/app/controllers/admin/creditors.js.coffee
@@ -390,7 +390,7 @@

   update_selected_count: ->
     box = @el.find("#admin_creditors_select_count")
-    if @selected_ids.length > 0
+    if @selected_ids?.length > 0
       box.html(I18n.t("common.item_selected", {count: @selected_ids.length}))
     else
       box.html("")


Fix gid in oozie

Fix gid in oozie

--- actions/hdp_oozie_server.coffee
+++ actions/hdp_oozie_server.coffee
@@ -5,6 +5,7 @@

 module.exports = []

+module.exports.push 'histi/actions/mysql_client'
 module.exports.push 'histi/actions/hdp_core'

 ###
@@ -150,7 +151,7 @@
       local_default: true
       properties: oozie_site
       uid: oozie_user
-      guid: hadoop_group
+      gid: hadoop_group
       mode: 0o0755
       merge: true
     , (err, configured) ->
@@ -165,7 +166,7 @@
       local_default: true
       properties: oozie_hadoop_config
       uid: oozie_user
-      guid: hadoop_group
+      gid: hadoop_group
       mode: 0o0755
     , (err, configured) ->
       return next err if err
@@ -177,7 +178,7 @@
       source: "#{hadoop_conf_dir}"
       destination: "#{oozie_conf_dir}/hadoop-conf"
       uid: hadoop_user
-      guid: hadoop_group
+      gid: hadoop_group
     , (err, linked) ->
       return next err if err
       modified = true if linked


Remove javascript alert statement that was left from development.

--- app/assets/javascripts/ng-controllers/ng-FeedbunchCtrl.js.coffee
+++ app/assets/javascripts/ng-controllers/ng-FeedbunchCtrl.js.coffee
@@ -330,7 +330,6 @@
   # Accepts as argument the boolean value to which the flag will be set.
   #--------------------------------------------
   $scope.set_sidebar_visible = (visible)->
-    alert visible
     sidebarVisibleSvc.set visible
     menuCollapseSvc.close()
     return


In smartphone-sized screens, close the collapsible app menu when going to the start page.

--- app/assets/javascripts/ng-controllers/ng-FeedbunchCtrl.js.coffee
+++ app/assets/javascripts/ng-controllers/ng-FeedbunchCtrl.js.coffee
@@ -43,6 +43,7 @@
     currentFolderSvc.unset()
     entriesPaginationSvc.set_busy false
     sidebarVisibleSvc.toggle()
+    menuCollapseSvc.close()

   #--------------------------------------------
   # Unsubscribe from a feed


remove shiftRequest file

remove shiftRequest file

--- both/methods/shift/shiftRequest.coffee
+++ both/methods/shift/shiftRequest.coffee
@@ -1,209 +0,0 @@
-Meteor.methods
-
-	request: (shiftId, teamId) ->
-		user = Meteor.user()
-		userId = user._id
-		shift = Shifts.findOne shiftId, fields: teams: 1, scheduling: 1, tagId: 1
-
-		if Meteor.isServer
-			check { shiftId: shiftId, teamId: teamId }, isExistingShiftAndTeam
-			check { tagId: shift.tagId, userId: userId }, isTagParticipant
-
-		user =
-			_id: userId
-			name: user.profile.firstname + ' ' + user.profile.lastname
-			teamleader: Roles.userIsInRole userId, 'teamleader', shift.tagId
-			substituteTeamleader: Roles.userIsInRole userId, 'substituteTeamleader', shift.tagId
-			thisTeamleader: false
-			phone: user.profile.telefon
-			email: user.profile.email
-
-		if shift.scheduling == 'manual'
-			for team in shift.teams when team._id == teamId
-				if team.status == 'open'
-					Shifts.update _id: shiftId, 'teams._id': teamId,
-						$pull: 'teams.$.declined': _id: userId
-						$addToSet: 'teams.$.pending': user
-
-					# TODO: write mail to orga team if participants.length > 0
-				else
-					throw new Meteor.Error 500, TAPi18n.__('modal.shift.closedTeam')
-		else if shift.scheduling == 'direct'
-			for team in shift.teams when team._id == teamId
-				inPending = false
-
-				for participant in team.pending when participant._id == userId
-					inPending = true
-
-				if !inPending
-					if team.participants.length > 0
-						if team.participants.length < team.max
-							Shifts.update _id: shiftId, 'teams._id': teamId,
-								$pull: 'teams.$.declined': _id: userId
-								$addToSet: 'teams.$.participants': user
-
-							if team.participants.length == team.max - 1
-								Meteor.call 'closeTeam', shiftId, teamId
-
-							Meteor.call 'sendTeamUpdate', shiftId, teamId, 'participant'
-						else throw new Meteor.Error 500, TAPi18n.__('modal.shift.maximumReached')
-					else if team.pending.length >= team.min - 1
-						acceptedUsers = [ ]
-						declinedUsers = [ ]
-						hasTeamleader = false
-						chosenId = null
-						chosenIsTeamleader = false
-
-						if user.teamleader
-							hasTeamleader = true
-							chosenId = user._id
-							chosenIsTeamleader = true
-						else if user.substituteTeamleader
-							hasTeamleader = true
-							chosenId = user._id
-							chosenIsTeamleader = false
-
-						for pendingUser in team.pending when pendingUser.teamleader || pendingUser.substituteTeamleader
-							hasTeamleader = true
-
-							if !chosenId?
-								if pendingUser.teamleader
-									chosenId = pendingUser._id
-									chosenIsTeamleader = true
-								else if pendingUser.substituteTeamleader
-									chosenId = pendingUser._id
-									chosenIsTeamleader = false
-							else if !chosenIsTeamleader && pendingUser.substituteTeamleader
-								chosenId = pendingUser._id
-								chosenIsTeamleader = false
-
-						if hasTeamleader
-							acceptedUsers.push userId
-
-							Shifts.update _id: shiftId, 'teams._id': teamId,
-								$pull: 'teams.$.declined': _id: userId
-								$addToSet: 'teams.$.participants': user
-
-							for pendingUser in team.pending
-								if acceptedUsers.length < team.max
-									acceptedUsers.push pendingUser._id
-
-									Shifts.update _id: shiftId, 'teams._id': teamId,
-										$pull:
-											'teams.$.pending': _id: pendingUser._id
-											'teams.$.declined': _id: pendingUser._id
-										$addToSet: 'teams.$.participants': pendingUser
-								else
-									declinedUsers.push pendingUser._id
-
-									Shifts.update _id: shiftId, 'teams._id': teamId,
-										$pull:
-											'teams.$.pending': _id: pendingUser._id
-										$addToSet: 'teams.$.declined': pendingUser
-
-								if pendingUser.checked
-									pendingUser.checked = false
-
-							for otherTeam in shift.teams when otherTeam._id != teamId
-								for pendingUser in otherTeam.pending when pendingUser._id in acceptedUsers
-									if pendingUser.checked
-										pendingUser.checked = false
-
-									Shifts.update _id: shiftId, 'teams._id': otherTeam._id,
-										$pull: 'teams.$.pending': _id: pendingUser._id
-										$addToSet: 'teams.$.declined': pendingUser
-
-								for participant in otherTeam.participants when participant._id in acceptedUsers
-									Meteor.call 'declineParticipant', shiftId, otherTeam._id, participant._id
-
-							Meteor.call 'setLeader', shiftId, team._id, chosenId
-
-							for acceptedUser in acceptedUsers
-								Meteor.call 'sendConfirmation', shiftId, teamId, acceptedUser
-							for declinedUser in declinedUsers
-								Meteor.call 'sendDeclined', shiftId, teamId, declinedUser
-
-							if acceptedUsers.length == team.max
-								Meteor.call 'closeTeam', shiftId, teamId
-						else
-							Shifts.update _id: shiftId, 'teams._id': teamId,
-								$pull: 'teams.$.declined': _id: userId
-								$addToSet: 'teams.$.pending': user
-					else
-						Shifts.update _id: shiftId, 'teams._id': teamId,
-							$pull: 'teams.$.declined': _id: userId
-							$addToSet: 'teams.$.pending': user
-
-	cancelRequest: (shiftId, teamId) ->
-		user = Meteor.user()
-		shift = Shifts.findOne shiftId, fields: teams: 1
-
-		if Meteor.isServer
-			check { shiftId: shiftId, teamId: teamId }, isExistingShiftAndTeam
-
-		Shifts.update _id: shiftId, 'teams._id': teamId,
-			$pull: 'teams.$.pending': _id: user._id
-
-	cancelParticipation: (shiftId, teamId) ->
-		user = Meteor.user()
-		userId = user._id
-		shift = Shifts.findOne shiftId, fields: teams: 1, scheduling: 1, tagId: 1, date: 1, projectId: 1
-
-		if Meteor.isServer
-			check { shiftId: shiftId, teamId: teamId }, isExistingShiftAndTeam
-			check { tagId: shift.tagId, userId: userId }, isTagParticipant
-
-		for team in shift.teams when team._id == teamId
-			if team.participants.length == team.min
-				cancelledUser = {}
-				for participant in team.participants when participant._id == userId
-					cancelledUser = participant
-
-				Shifts.update _id: shiftId, 'teams._id': teamId,
-					$pull: 'teams.$.participants': _id: userId
-					$addToSet: 'teams.$.pending': cancelledUser
-
-				if shift.scheduling == 'manual' and Meteor.isThisWeek(shift.date)
-					Meteor.call 'sendUnderstaffed', shiftId, teamId
-				else if shift.scheduling == 'manual'
-					Meteor.call 'sendToOrga', shift.projectId, 'teamCancel', shiftId, teamId
-
-				Meteor.call 'cancelTeam', shiftId, teamId, 'missingParticipant'
-			else
-				wasTeamleader = false
-				hasTeamleader = false
-				participantData = {}
-				newTeamleaderData = {}
-
-				for participant in team.participants
-					if participant._id == userId
-						participantData = participant
-
-						if participant.thisTeamleader
-							wasTeamleader = true
-					else if participant.teamleader || participant.substituteTeamleader
-						hasTeamleader = true
-						newTeamleaderData = participant
-						newTeamleaderData.thisTeamleader = true
-
-				if wasTeamleader
-					if hasTeamleader
-						Shifts.update _id: shiftId, 'teams._id': teamId,
-							$pull:
-								'teams.$.participants': _id: userId
-								'teams.$.participants': _id: newTeamleaderData._id
-
-						Shifts.update _id: shiftId, 'teams._id': teamId,
-							$addToSet:
-								'teams.$.declined': participantData
-								'teams.$.participants': newTeamleaderData
-
-						Meteor.call 'sendTeamUpdate', shiftId, teamId, 'leader'
-					else
-						Meteor.call 'cancelTeam', shiftId, teamId
-				else
-					Shifts.update _id: shiftId, 'teams._id': teamId,
-						$pull: 'teams.$.participants': _id: userId
-						$addToSet: 'teams.$.declined': participantData
-
-					Meteor.call 'sendTeamUpdate', shiftId, teamId, 'participant'


log client id when disconnecting on otUpdateError

only log errors for connected clients

--- services/real-time/app/coffee/DocumentUpdaterController.coffee
+++ services/real-time/app/coffee/DocumentUpdaterController.coffee
@@ -35,8 +35,8 @@
 				client.emit "otUpdateApplied", update

 	_processErrorFromDocumentUpdater: (io, doc_id, error, message) ->
-		logger.error err: error, doc_id: doc_id, "error from document updater"
 		for client in io.sockets.clients(doc_id)
+			logger.error err: error, doc_id: doc_id, client_id: client.id, "error from document updater, disconnecting client"
 			client.emit "otUpdateError", error, message
 			client.disconnect()


Allow pass collection object instead collection name

--- model.coffee
+++ model.coffee
@@ -6,17 +6,17 @@

 @Model = class Model
 	constructor: (config={}) ->
-		config.accessTokensCollectionName ?= 'oauth-access-tokens'
-		config.refreshTokensCollectionName ?= 'oauth-refresh-tokens'
-		config.clientsCollectionName ?= 'oauth-clients'
-		config.authCodesCollectionName ?= 'oauth-auth-codes'
+		config.accessTokensCollectionName ?= 'oauth_access_tokens'
+		config.refreshTokensCollectionName ?= 'oauth_refresh_tokens'
+		config.clientsCollectionName ?= 'oauth_clients'
+		config.authCodesCollectionName ?= 'oauth_auth_codes'

 		@debug = debug = config.debug

-		@AccessTokens = AccessTokens = new Meteor.Collection config.accessTokensCollectionName
-		@RefreshTokens = RefreshTokens = new Meteor.Collection config.refreshTokensCollectionName
-		@Clients = Clients = new Meteor.Collection config.clientsCollectionName
-		@AuthCodes = AuthCodes = new Meteor.Collection config.authCodesCollectionName
+		@AccessTokens = AccessTokens = config.accessTokensCollection or new Meteor.Collection config.accessTokensCollectionName
+		@RefreshTokens = RefreshTokens = config.refreshTokensCollection or new Meteor.Collection config.refreshTokensCollectionName
+		@Clients = Clients = config.clientsCollection or new Meteor.Collection config.clientsCollectionName
+		@AuthCodes = AuthCodes = config.authCodesCollection or new Meteor.Collection config.authCodesCollectionName

 	getAccessToken: Meteor.bindEnvironment (bearerToken, callback) ->


removing failed test

removing failed test

--- test/Local-Site.test.coffee
+++ test/Local-Site.test.coffee
@@ -37,7 +37,7 @@
             assert_Is_Null data
             done()

-  it 'should host content files', (done)->
+  xit 'should host content files', (done)->
     using local_Site, ->
       @.express_Setup()
       @.start()


Changed 5-diget objects.

Changed 5-diget objects.

--- fetsy-hammertag/scripts/utils/validation.coffee
+++ fetsy-hammertag/scripts/utils/validation.coffee
@@ -1,10 +1,10 @@
 angular.module 'FeTSy-Hammertag.utils.validation', []

-.constant 'singleObjectRegex', /^(HKES_\d{7}|\d{5})$/
+.constant 'singleObjectRegex', /^(HKES_\d{7}|\d{5}|\d{6})$/

-.constant 'suppliesRegex', /^(\d{13}|\d{6})$/
+.constant 'suppliesRegex', /^\d{13}$/

 .constant 'personRegex', /^\d{8}$/


fix indentation

fix indentation

--- models/featured_link.coffee
+++ models/featured_link.coffee
@@ -6,7 +6,7 @@
 { SECURE_IMAGES_URL } = require('sharify').data

 module.exports = class FeaturedLink extends Backbone.Model
-    _.extend @prototype, Image(SECURE_IMAGES_URL)
+   _.extend @prototype, Image(SECURE_IMAGES_URL)

   fetchItems: (cache=false) ->
     items = new Items null, { id: @id }


[tests] remove no longer existing property

--- source/data/index.test.coffee
+++ source/data/index.test.coffee
@@ -77,8 +77,6 @@
     staging: t.maybe t.Boolean
     build: t.maybe t.Boolean
     hotModuleRloading: t.maybe t.Boolean
-  DATA: t.struct
-    currentYear: t.Number
 }, { name: 'Data' })

 if typeof describe == 'function'


minor add up

minor add up

--- library/nucleus/arche.coffee
+++ library/nucleus/arche.coffee
@@ -125,4 +125,5 @@
         inmerge = (x) -> _.unique previous.concat x
         execute = (fnc) => fnc.call this; implement
         execute -> return @interceptors = inmerge
-            implement: implement, event: event
+            implement: implement or null
+            event: try event.toString()


Some catch up fixes

Some catch up fixes

--- library/nucleus/watch.coffee
+++ library/nucleus/watch.coffee
@@ -116,13 +116,13 @@
         modules = @constructor.EXTENSIONS
         extension = paths.extname absolute
         return unless extension in modules
+        unlink = "Unlinking module found at %s".cyan
         relative = paths.relative process.cwd(), path
-        unlink = "Unlinking module found at %s".cyan
-        logger.info unlink, relative.underline
+        logger.info unlink, relative.toString().underline
         registry = (router = @kernel.router)?.registry or []
         originate = (s) -> s.constructor.origin?.filename
         predicate = (s) -> originate(s) is absolute
-        previous = _.filter registry, predicate
+        try previous = _.filter registry, predicate
         router.unregister prev for prev in previous

     # The responsibility of this method is to determine whether it is


Actually refresh the feeds

Actually refresh the feeds

--- app/states/data_feed.coffee
+++ app/states/data_feed.coffee
@@ -15,9 +15,10 @@

     # setup periodic collection update
     _updateWeather = ->
-      app.intervals.ticket_refresh = setTimeout =>
+      app.intervals.weather_refresh = setTimeout =>
         app.models.weather.once 'change', ->
           _updateWeather()
+        app.models.weather.fetch()
       , 600000

     _updateWeather()
@@ -33,6 +34,7 @@
         app.collections.news_feed.once 'sync', ->
           app.views.news.render()
           _updateNews()
+        app.collections.news_feed.changes()
       , 600000

     _updateNews()
@@ -48,6 +50,7 @@
         app.collections.twitter_feed.once 'sync', ->
           app.views.twitter.render()
           _updateTwitter()
+        app.collections.twitter_feed.changes()
       , 600000

     _updateTwitter()


Refresh, just to be clear.

Refresh, just to be clear.

--- spec/fuzzy-finder-spec.coffee
+++ spec/fuzzy-finder-spec.coffee
@@ -923,7 +923,7 @@

       gitDirectory = atom.project.getDirectories()[1]
       gitRepository = atom.project.getRepositories()[1].async
-      waitsForPromise -> gitRepository._refreshingPromise
+      waitsForPromise -> gitRepository.refreshStatus()

     describe "git-status-finder behavior", ->
       [originalText, originalPath, newPath] = []


Add HEAD /:collection unit test

Add HEAD /:collection unit test

--- test/collection-spec.coffee
+++ test/collection-spec.coffee
@@ -168,6 +168,18 @@
           assert.equal res.body.total, c
           done()

+describe 'HEAD', ->
+  url = '/turer?api_key=dnt'
+
+  it 'should only get http header for collection resource', (done) ->
+    req.head(url).expect(200)
+      .expect('Count-Return', /^[0-9]+$/)
+      .expect('Count-Total', /^[0-9]+$/)
+      .end (err, res) ->
+        assert.ifError(err)
+        assert.deepEqual(res.body, {})
+        done()
+
 describe 'POST', ->
   gen = new Generator 'turer', exclude: ['_id', 'tilbyder', 'endret']
   url = '/turer?api_key=dnt'


Environments: Add extras data provider

Environments: Add extras data provider

--- client/Environments/views/scene/environmentextracontainer.coffee
+++ client/Environments/views/scene/environmentextracontainer.coffee
@@ -1,4 +1,16 @@
 class EnvironmentExtraContainer extends EnvironmentContainer
+
+  EnvironmentDataProvider.addProvider "extras", ->
+
+    dummyAdditionals = [
+      {
+        title: "Shared Space",
+        description: "additional"
+      }
+    ]
+
+    new Promise (resolve, reject)->
+      resolve dummyAdditionals

   constructor:(options={}, data)->
     options.cssClass  = 'extras'
@@ -8,17 +20,3 @@

     @on 'PlusButtonClicked', ->
       new KDNotificationView title: "Adding more resource will be available soon."
-
-  loadItems:->
-    super
-
-    dummyAdditionals = [
-      {
-        title: "Shared Space",
-        description: "additional"
-      }
-    ]
-
-    new Promise (resolve, reject)=>
-      @addItem addition for addition in dummyAdditionals
-      resolve()


VariablesEditorView: it's now basically BaseStackEditorView but keeping it as is for future requirements

--- client/admin/lib/views/stacks/editors/variableseditorview.coffee
+++ client/admin/lib/views/stacks/editors/variableseditorview.coffee
@@ -1,18 +1,3 @@
 BaseStackEditorView = require './basestackeditorview'

-
 module.exports = class VariablesEditorView extends BaseStackEditorView
-
-
-  constructor: (options = {}, data) ->
-
-    unless options.content
-      options.content = """
-        {
-          "variables": {
-
-          }
-        }
-      """
-
-    super options, data


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -26,6 +26,6 @@
     y: 20

   equals engine.first('type=testObj').length, 1
-  equals engine.first('type=te')
+  equals engine.first('type=testObj')

 module()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -9,7 +9,7 @@
     y: 5

   obj2 = engine.add
-    cl: "Awesome"
+    rad: "Awesome"
     x: 5
     y: 10


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -32,5 +32,6 @@
     x: 9
     y: 10

+  equ

 module()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -1,7 +1,7 @@
 module "EngineSelector"

 test "engine#find", ->
-  engine = w
+  engine = Engine()

 module()


Fix linked-file-types check when opening modal

--- services/web/public/coffee/ide/file-tree/controllers/FileTreeController.coffee
+++ services/web/public/coffee/ide/file-tree/controllers/FileTreeController.coffee
@@ -44,7 +44,7 @@
 			)

 		$scope.openProjectLinkedFileModal = window.openProjectLinkedFileModal = () ->
-			unless 'url' in window.data.enabledLinkedFileTypes
+			unless 'project_file' in window.data.enabledLinkedFileTypes
 				console.warn("Project linked files are not enabled")
 				return
 			$modal.open(


Use `atom.activatePackage` directly in specs

--- spec/bracket-matcher-spec.coffee
+++ spec/bracket-matcher-spec.coffee
@@ -6,7 +6,7 @@
   beforeEach ->
     window.rootView = new RootView
     rootView.open('sample.js')
-    window.loadPackage('bracket-matcher')
+    atom.activatePackage('bracket-matcher')
     rootView.attachToDom()
     editor = rootView.getActiveView()
     editSession = editor.activeEditSession


refactoring

refactoring

--- features/step_definitions/selectmenu/events.coffee
+++ features/step_definitions/selectmenu/events.coffee
@@ -3,6 +3,11 @@

 Until = seleniumWebdriver.until
 {By, WebElementCondition, Condition} = seleniumWebdriver
+
+forChangeEvent = new Condition '', (driver) ->
+  driver.findElement css: '.change .label'
+  .then (element) -> element.getText()
+  .then (text) -> text is 'Medium'

 defineSupportCode ({When, Then}) ->
   When 'Select new speed', () ->
@@ -11,9 +16,4 @@
     .then () => @driver.findElement xpath: "//li[contains(., 'Medium')]"
     .then (element) -> element.click()

-  Then 'selectmenu change event is fired', () ->
-    condition = new Condition '', (driver) ->
-      driver.findElement css: '.change .label'
-      .then (element) -> element.getText()
-      .then (text) -> text is 'Medium'
-    @driver.wait(condition)
+  Then 'selectmenu change event is fired', () -> @driver.wait forChangeEvent


Fix a couple more typos

Fix a couple more typos

--- src/kissmetrics-anon.coffee
+++ src/kissmetrics-anon.coffee
@@ -100,7 +100,7 @@
 # --------------------------

 # Wrapper for interacting with the Kissmetrics API with logged out users. The
-# only difference from `KissmetricsClient` is that an identifier for thie user
+# only difference from `KissmetricsClient` is that an identifier for the user
 # will be automatically created and saved in their browser.
 #
 # ##### Arguments
@@ -114,7 +114,7 @@
 # If you provide your own storage engine, it **must** match the
 # API's provided by `Cookie` and `LocalStorage` with `get()`, `set()` and
 # `delete()` methods. All methods should use `this.storageKey` to reference
-# the key to retreive data by, and `set()` must accept a key and value. The
+# the key to retrieve data by, and `set()` must accept a key and value. The
 # methods will always be called in the correct context by the API, such
 # that `this.storageKey` will be available.
 #
@@ -170,7 +170,7 @@
   # `newIdentity` (String): A new identifier to map to the `@person` set on
   # the current instance.
   #
-  # `deleteStoredID` *Optional* (Boolea): Whether or not to delete the
+  # `deleteStoredID` *Optional* (Boolean): Whether or not to delete the
   #   logged-out identity that was stored. Default `true`.
   #
   # ```


#52 use colorJet colors for users in task overview; cleanup

--- app/assets/javascripts/admin/views/task/task_overview_view.coffee
+++ app/assets/javascripts/admin/views/task/task_overview_view.coffee
@@ -3,6 +3,7 @@
 backbone.marionette : marionette
 worker!libs/viz.js : VizWorker
 libs/pan_zoom_svg  : PanZoomSVG
+moment : moment
 ###

 class TaskOverviewView extends Backbone.Marionette.View
@@ -48,11 +49,7 @@

     $.get("http://localhost:9000/admin/tasks/overviewNew").then( (data) =>

-      {userInfos, taskTypes, projects} = data
-
-      getFillColor = ->
-        "#8fff6f"
-        # Color.jet(math.min(50, user.lastActivityDays) * (128 / 50) + 128).toHtml
+      { userInfos, taskTypes, projects } = data

       edge = (a, b) -> "\"" + a + "\"->\"" + b + "\";"
       quoted = (str) -> '"' + str + '"'
@@ -70,9 +67,12 @@
       svgTaskTypes = taskTypes.map( (taskType) -> quoted(taskType.summary) + ";").join("\n")
       svgProjects = projects.map( (project) -> quoted(project.name) + ";" ).join("\n")

-      svgUsers = _.pluck(userInfos, "user").map( (user) ->
+      svgUsers = _.pluck(userInfos, "user").map( (user) =>
         userName = user.firstName + " " + user.lastName
-        quoted(userName) + " [id="+ quoted(user._id["$oid"]) + ", shape=box, fillcolor=" + quoted(getFillColor()) + "];"
+        lastActivityDays = moment().diff(user.lastActivity, 'days')
+        color = @colorJet(Math.min(50, lastActivityDays) * (128 / 50) + 128)
+
+        quoted(userName) + " [id="+ quoted(user._id["$oid"]) + ", shape=box, fillcolor=" + quoted(color) + "];"
       ).join("\n")

@@ -80,7 +80,7 @@
         {user, taskTypes} = userInfo
         userName = user.firstName + " " + user.lastName

-        taskEdges = taskTypes.map( (taskType) -> edge(userName, taskType.summary)).join("\n")
+        taskTypes.map( (taskType) -> edge(userName, taskType.summary)).join("\n")
       ).join("\n")

@@ -88,14 +88,12 @@
         {user, projects} = userInfo
         userName = user.firstName + " " + user.lastName

-        projectEdges = projects.map( (project) -> edge(userName, project.name)).join("\n")
+        projects.map( (project) -> edge(userName, project.name)).join("\n")
       ).join("\n")
-
+
       tail = "edge [ color=blue ];  }"

-      mySVG = svgHead + svgTaskTypes + svgUsers + svgProjects + svgUserTaskEdges + svgUserProjectEdges + tail
-
-      return mySVG
+      return svgHead + svgTaskTypes + svgUsers + svgProjects + svgUserTaskEdges + svgUserProjectEdges + tail
     )

@@ -103,8 +101,10 @@

     # reset some attributes before invoking panZoom plugin
     $svg = @$(".graph.well").find("svg")
+
     # get rid of the troublemaker. messes up transformations
     $svg[0].removeAttribute("viewBox")
+
     $svg[0].setAttribute("width", "#{$(window).width() - 100}px")
     $svg[0].setAttribute("height", "#{$(window).height() - 50 - $svg.offset().top}px" )
     $svg.css("max-width", "100%")
@@ -123,3 +123,21 @@
       )
     )

+
+  colorJet : (value) ->
+
+    fourValue = value / 64
+
+    clamp = (value, min, max) -> return Math.min(Math.max(value, min), max)
+
+    componentToHex = (c) ->
+      hex = Math.floor(c * 255).toString(16)
+      if hex.length == 1 then "0" + hex else hex
+
+    rgbToHex = (r, g, b) -> "#" + [r, g, b].map(componentToHex).join("")
+
+    r = clamp(Math.min(fourValue - 1.5, -fourValue + 4.5), 0, 1)
+    g = clamp(Math.min(fourValue - 0.5, -fourValue + 3.5), 0, 1)
+    b = clamp(Math.min(fourValue + 0.5, -fourValue + 2.5), 0, 1)
+
+    rgbToHex(r, g, b)


Date parsing in newAchievement unput field

--- app/assets/javascripts/controllers/achievements_controller.coffee
+++ app/assets/javascripts/controllers/achievements_controller.coffee
@@ -4,8 +4,36 @@
   sortAscending: false

   addAchievement: ->
+    data = @parseInput @get('newAchievement')
     RailsEmberApp.Achievement.createRecord
-      title: @get('newAchievement')
-      achievedAt: new Date()
+      title: data['title']
+      achievedAt: data['achievedAt']
     @set('newAchievement', '')
-    @get('store').commit()+    @get('store').commit()
+
+  parseInput: (str) ->
+    day   = /\bd\d\d\b/.exec(str)
+    month = /\bm\d\d\b/.exec(str)
+    year  = /\by\d{4}\b/.exec(str)
+
+    achievedAt = new Date()
+    title = str
+
+    if day
+      title = title.replace(day[0], "")
+      achievedAt.setDate(day[0].split('d')[1])
+
+    if month
+      title = title.replace(month[0], "")
+      achievedAt.setMonth(parseInt(month[0].split('m')[1]) - 1)
+
+    if year
+      title = title.replace(year[0], "")
+      achievedAt.setYear(year[0].split('y')[1])
+
+    title.replace(/\s+/, " ") if title
+
+    {
+      title: title,
+      achievedAt: achievedAt
+    }


Move select field allowMultiple option to publicConfiguration.

--- app/assets/javascripts/luca/components/fields/select_field.coffee
+++ app/assets/javascripts/luca/components/fields/select_field.coffee
@@ -4,6 +4,9 @@

 selectField.triggers          "after:select",
                               "on:change"
+
+selectField.publicConfiguration
+  allowMultiple: false

 selectField.defines
   events:
@@ -12,8 +15,6 @@
   template: "fields/select_field"

   includeBlank: true
-
-  allowMultiple: false

   blankValue: ''