fix jasmine tests

fix jasmine tests

--- js/tests/inner-tests.coffee
+++ js/tests/inner-tests.coffee
@@ -158,14 +158,13 @@
       parallel: 2
     project.billing.loadPlanData
       containers: 6
-      plan:
+      template_properties:
         max_parallelism: 6
         price: null
         type: "trial"

-    @expect(project.paid_speed()).toEqual 6
-    @expect(project.plan_max_speed()).toEqual 6
-    @expect(project.payor_login()).toBe(null)
+    @expect(project.paid_parallelism()).toEqual 6
+    @expect(project.plan().max_parallelism()).toEqual 6

     # Allow them to select 5x
     @expect(project.parallel_label_style(5).disabled()).not.toBe(true)
@@ -173,54 +172,50 @@
     # Don't allow them to select 8x
     @expect(project.parallel_label_style(8).disabled()).toEqual(true)

-    @expect(project.show_parallel_upgrade_plan_p()).not.toBe(true)
-    @expect(project.show_parallel_upgrade_speed_p()).not.toBe(true)
+    @expect(project.show_upgrade_plan()).not.toBe(true)
+    @expect(project.show_add_containers()).not.toBe(true)

   j.it "should handle container-type plans", ->
     project = new CI.inner.Project
       parallel: 2
     project.billing.loadPlanData
-      plan:
+      template_properties:
         max_parallelism: 3
         price: null
         type: "containers"
-      payor:
-        login: 'daniel'
-      concurrency: 5
-      parallelism: 2
       containers: 2

-    @expect(project.paid_speed()).toEqual 2
-    @expect(project.plan_max_speed()).toEqual 3
-    @expect(project.payor_login()).toBe('daniel')
+    @expect(project.paid_parallelism()).toEqual 2
+    @expect(project.plan().max_parallelism()).toEqual 3
+
     @expect(project.parallel_label_style(2).disabled()).not.toBe(true)
     @expect(project.parallel_label_style(3).disabled()).toBe(true)
     @expect(project.parallel_label_style(4).disabled()).toBe(true)

     # Don't tell them to upgrade for things they can click
     project.focused_parallel(2)
-    @expect(project.show_parallel_upgrade_plan_p()).not.toBe(true)
-    @expect(project.show_parallel_upgrade_speed_p()).not.toBe(true)
+    @expect(project.show_upgrade_plan()).not.toBe(true)
+    @expect(project.show_add_containers()).not.toBe(true)

     # Don't tell them to upgrade their plan if it supports higher speed
     project.focused_parallel(3)
-    @expect(project.show_parallel_upgrade_plan_p()).not.toBe(true)
-    @expect(project.show_parallel_upgrade_speed_p()).toBe(true)
+    @expect(project.show_upgrade_plan()).not.toBe(true)
+    @expect(project.show_add_containers()).toBe(true)

     # Don't tell them to upgrade their speed if their plan doesn't supports it
     project.focused_parallel(4)
-    @expect(project.show_parallel_upgrade_plan_p()).toBe(true)
-    @expect(project.show_parallel_upgrade_speed_p()).not.toBe(true)
+    @expect(project.show_upgrade_plan()).toBe(true)
+    @expect(project.show_add_containers()).not.toBe(true)

     project.billing.containers(5)
     project.focused_parallel(2)
-    @expect(project.show_parallel_upgrade_plan_p()).not.toBe(true)
-    @expect(project.show_parallel_upgrade_speed_p()).not.toBe(true)
+    @expect(project.show_upgrade_plan()).not.toBe(true)
+    @expect(project.show_add_containers()).not.toBe(true)

     project.focused_parallel(3)
-    @expect(project.show_parallel_upgrade_plan_p()).not.toBe(true)
-    @expect(project.show_parallel_upgrade_speed_p()).not.toBe(true)
+    @expect(project.show_upgrade_plan()).not.toBe(true)
+    @expect(project.show_add_containers()).not.toBe(true)

     project.focused_parallel(4)
-    @expect(project.show_parallel_upgrade_plan_p()).toBe(true)
-    @expect(project.show_parallel_upgrade_speed_p()).not.toBe(true)
+    @expect(project.show_upgrade_plan()).toBe(true)
+    @expect(project.show_add_containers()).not.toBe(true)


Убрал определение не использующихся переменных

--- src/chocolate.coffee
+++ src/chocolate.coffee
@@ -413,7 +413,7 @@
           'height':     image.height()
           'margin-top': '-' + image.height() + 'px'

-        image.on 'mouseenter mouseleave', (event) -> popover.toggleClass 'choco-hover'
+        image.on 'mouseenter mouseleave', -> popover.toggleClass 'choco-hover'
         popover.on 'click', (event) -> showFirstImage event, cid

       preload.src = data.thumbnail


Clampable#clampToBounds

Clampable#clampToBounds

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -7,7 +7,8 @@
       I[property] = I[property].clamp(data.min, data.max)

   ###
-  @name
+  @name clamp
+  @methodOf Cla
   ###
   clamp: (data) ->
     Object.extend(I.clampData, data)


vm.create(): correctly handle updating SR on existing disks.

--- src/api/vm.coffee
+++ src/api/vm.coffee
@@ -107,17 +107,18 @@
   )

   xapiExistingVdis = existingDisks and map(existingDisks, (vdi, device) =>
-    sr = @getObject(vdi.$SR)

     if vdi.size?
       size = parseSize(vdi.size)
       diskSizesByDevice[device] = size

-    objectIds.push(sr.id)
+    if vdi.$SR
+      sr = @getObject(vdi.$SR)
+      objectIds.push(sr.id)

     return {
       size,
-      $SR: sr._xapiId,
+      $SR: sr and sr._xapiId,
       type: vdi.type
     }
   )


Adding comment about remove children on re-render

--- shared/base/view.coffee
+++ shared/base/view.coffee
@@ -238,6 +238,8 @@
   # Call @getView()
   # Attach childView
   attachChildViews: ->
+    # Remove all child views in case we are re-rendering through
+    # manual .render() or 'refresh' being triggered on the view.
     @removeChildViews()
     @childViews = BaseView.attach(@app, @)


Added debugging statements

Added debugging statements

--- lib/service/modules.coffee
+++ lib/service/modules.coffee
@@ -35,6 +35,7 @@
     pendingProxyTasks -= 1

   generateModules = (task) ->
+    console.log "generating modules"

     getSecurityContextString = (authorizationHeader, appMetadata) ->
       try
@@ -104,6 +105,7 @@
       tempObjectStore: tempObjectStore task.request.tempObjectStore
       validation: validation

+    console.log "Modules generated, returning API..."
     return api

   methods =


Collision docs

Collision docs

--- src/collision.coffee
+++ src/collision.coffee
@@ -1,23 +1,43 @@
 ###*
-Collision holds many methods useful for checking geometric overlap of various objects.
+Collision holds many useful methods for checking geometric overlap of various objects.

 @name Collision
 @namespace
 ###
 Collision =
+  ###*
+  Takes two bounds objects and returns true if they collide (overlap), false otherwise.
+  Bounds objects have x, y, width and height properties.
+
+  @name rectangular
+  @methodOf Collision
+
+  @param a
+  @param b
+  ###
   rectangular: (a, b) ->
     a.x < b.x + b.width &&
     a.x + a.width > b.x &&
     a.y < b.y + b.height &&
     a.y + a.height > b.y

+  ###*
+  Takes two circle objects and returns true if they collide (overlap), false otherwise.
+  Circle objects have x, y, and radius.
+
+  @name circular
+  @methodOf Collision
+
+  @param a
+  @param b
+  ###
   circular: (a, b) ->
     r = a.radius + b.radius
     dx = b.x - a.x
     dy = b.y - a.y

     r * r >= dx * dx + dy * dy
-
+
   rayCircle: (source, direction, target) ->
     radius = target.radius()
     target = target.position()
@@ -46,47 +66,47 @@
   rayRectangle: (source, direction, target) ->
     xw = target.xw
     yw = target.yw
-
+
     if source.x < target.x
       xval = target.x - xw
     else
       xval = target.x + xw
-
+
     if source.y < target.y
       yval = target.y - yw
     else
       yval = target.y + yw
-
+
     if direction.x == 0
       p0 = Point(target.x - xw, yval)
       p1 = Point(target.x + xw, yval)
-
+
       t = (yval - source.y) / direction.y
     else if direction.y == 0
       p0 = Point(xval, target.y - yw)
       p1 = Point(xval, target.y + yw)
-
+
       t = (xval - source.x) / direction.x
     else
       tX = (xval - source.x) / direction.x
       tY = (yval - source.y) / direction.y
-
+
       # TODO: These special cases are gross!
       if (tX < tY || (-xw < source.x - target.x < xw)) && !(-yw < source.y - target.y < yw)
         p0 = Point(target.x - xw, yval)
         p1 = Point(target.x + xw, yval)
-
+
         t = tY
       else
         p0 = Point(xval, target.y - yw)
         p1 = Point(xval, target.y + yw)
-
+
         t = tX
-
+
     if t > 0
       areaPQ0 = direction.cross(p0.subtract(source))
       areaPQ1 = direction.cross(p1.subtract(source))
-
+
       if areaPQ0 * areaPQ1 < 0
         hit = direction.scale(t).add(source)


check for presence of window object in StateHistory.isSupported()

--- src/batman.coffee
+++ src/batman.coffee
@@ -1619,7 +1619,7 @@
     segments.join('')

 class Batman.StateHistory extends Batman.HistoryManager
-  @isSupported: -> window.history?.pushState?
+  @isSupported: -> window?.history?.pushState?
   start: =>
     return if typeof window is 'undefined'
     return if @started


split-diff-view file remove

split-diff-view file remove

--- lib/split-diff-view.coffee
+++ lib/split-diff-view.coffee
@@ -1,24 +0,0 @@
-# not used for now
-module.exports =
-class SplitDiffView
-  constructor: (serializedState) ->
-
-     # Create root element
-     @element = document.createElement('div')
-     @element.classList.add('split-diff')
-
-     # Create message element
-     message = document.createElement('div')
-     message.textContent = "The SplitDiff package is Alive! It's ALIVE!"
-     message.classList.add('message')
-     @element.appendChild(message)
-
-  # Returns an object that can be retrieved when package is activated
-  serialize: ->
-
-  # Tear down any state and detach
-  destroy: ->
-    @element.remove()
-
-  getElement: ->
-    @element


Use package name as config prefix

Use package name as config prefix

--- lib/wrap-guide-view.coffee
+++ lib/wrap-guide-view.coffee
@@ -20,7 +20,7 @@
     atom.config.getPositiveInt('editor.preferredLineLength', 80)

   getGuideColumn: (path) ->
-    customColumns = atom.config.get('wrapGuide.columns')
+    customColumns = atom.config.get('wrap-guide.columns')
     return @getDefaultColumn() unless _.isArray(customColumns)
     for customColumn in customColumns when _.isObject(customColumn)
       {pattern, column} = customColumn


More class conversion

More class conversion

--- resources/assets/coffee/react/beatmap-discussions/nominations.coffee
+++ resources/assets/coffee/react/beatmap-discussions/nominations.coffee
@@ -21,54 +21,20 @@

 bn = 'beatmap-discussion-nomination'

-BeatmapDiscussions.Nominations = React.createClass
-  mixins: [React.addons.PureRenderMixin]
-
-  nominate: ->
-    return unless confirm(osu.trans('beatmaps.nominations.nominate-confirm'))
-
-    @doAjax 'nominate'
-
-  disqualify: ->
-    reason = prompt osu.trans('beatmaps.nominations.disqualification-prompt')
-    return unless reason
-
-    @doAjax 'disqualify', reason
-
-  doAjax: (action, comment) ->
-    LoadingOverlay.show()
-
-    params =
-      method: 'PUT'
-
-    if comment
-      params.data =
-        comment: comment
-
-    @xhr?.abort()
-
-    @xhr = $.ajax laroute.route("beatmapsets.#{action}", beatmapset: @props.beatmapset.id), params
-
-    .done (response) =>
-      $.publish 'beatmapset:update', beatmapset: response.beatmapset
-
-    .fail osu.ajaxError
-    .always LoadingOverlay.hide
-
-
-  componentDidMount: ->
+class BeatmapDiscussions.Nominations extends React.PureComponent
+  componentDidMount: =>
     osu.pageChange()

-  componentWillUnmount: ->
+  componentWillUnmount: =>
     @xhr?.abort()

-  componentDidUpdate: ->
+  componentDidUpdate: =>
     osu.pageChange()

-  render: ->
+  render: =>
     userCanNominate = @props.currentUser.isAdmin || @props.currentUser.isBNG || @props.currentUser.isQAT
     userCanDisqualify = @props.currentUser.isAdmin || @props.currentUser.isQAT
     mapCanBeNominated = (@props.beatmapset.status == 'pending')
@@ -145,3 +111,37 @@
               props:
                 disabled: @props.beatmapset.nominations.nominated
                 onClick: @nominate
+
+
+  disqualify: =>
+    reason = prompt osu.trans('beatmaps.nominations.disqualification-prompt')
+    return unless reason
+
+    @doAjax 'disqualify', reason
+
+
+  doAjax: (action, comment) =>
+    LoadingOverlay.show()
+
+    params =
+      method: 'PUT'
+
+    if comment
+      params.data =
+        comment: comment
+
+    @xhr?.abort()
+
+    @xhr = $.ajax laroute.route("beatmapsets.#{action}", beatmapset: @props.beatmapset.id), params
+
+    .done (response) =>
+      $.publish 'beatmapset:update', beatmapset: response.beatmapset
+
+    .fail osu.ajaxError
+    .always LoadingOverlay.hide
+
+
+  nominate: =>
+    return unless confirm(osu.trans('beatmaps.nominations.nominate-confirm'))
+
+    @doAjax 'nominate'


don't update project structure if file not created

--- services/web/app/coffee/Features/Project/ProjectEntityHandler.coffee
+++ services/web/app/coffee/Features/Project/ProjectEntityHandler.coffee
@@ -230,6 +230,7 @@

 	addFile:  (project_id, folder_id, fileName, fsPath, userId, callback = (error, fileRef, folder_id) ->)->
 		ProjectEntityHandler.addFileWithoutUpdatingHistory project_id, folder_id, fileName, fsPath, userId, (error, fileRef, folder_id, path, fileStoreUrl) ->
+			return callback(error) if error?
 			newFiles = [
 				file: fileRef
 				path: path


Test for valid (non-null) socket @ws in Client.reconnect() before @ws.close() to avoid system failure on disabled bot

--- src/client.coffee
+++ src/client.coffee
@@ -154,7 +154,10 @@
       @_pongTimeout = null

     @authenticated = false
-    @ws.close()
+
+    # Test for a null value on ws to prevent system failure (e.g. if Bot is disabled)
+    if @ws
+      @ws.close()

     @_connAttempts++
     # TODO: Check max reconnecting attempts and/or set a ceiling on this timeout


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color2.coffee
+++ src/color2.coffee
@@ -183,7 +183,15 @@
       hsl = @toHsl()
       hsl[1] += amount

-      return Color2(hslToRgb(hsl))
+      return Color2(hslToRgb(hsl))
+
+    saturate$: (amount) ->
+      hsl = @toHsl()
+      hsl[1] += amount
+
+      [@r, @g, @b, @a] = hslToRgb(hsl)
+
+      return this

     toHex: ->
       padString = (hexString) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color2.coffee
+++ src/color2.coffee
@@ -172,6 +172,8 @@
       hsl[0] = (hsl[0] + degrees) % 360

       [@r, @g, @b, @a] = hslToRgb(hsl)
+
+      @r = @r.floor()

       return this


No index building for non php files #25

No index building for non php files #25

--- lib/services/php-proxy.coffee
+++ lib/services/php-proxy.coffee
@@ -192,8 +192,10 @@
     @refresh()
     atom.workspace.observeTextEditors (editor) =>
       editor.onDidSave((event) =>
-        @clearCache()
-        @refresh(event.path)
+        # Only .php file
+        if event.path.substr(event.path.length - 4) == ".php"
+          @clearCache()
+          @refresh(event.path)
       )

     atom.config.onDidChange 'atom-autocomplete-php.binPhp', () =>


Update keymap.cson

Update keymap.cson

--- dot-atom/keymap.cson
+++ dot-atom/keymap.cson
@@ -20,4 +20,4 @@
 # * https://atom.io/docs/latest/customizing-atom#customizing-key-bindings
 # * https://atom.io/docs/latest/advanced/keymaps
 #
-# Bindings not working? Be aware that son follows CoffeeScript notation with differs with json.
+# Bindings not working? Be aware that cson follows CoffeeScript notation with differs with json.


Added another test

Added another test

--- test/args.coffee
+++ test/args.coffee
@@ -46,7 +46,7 @@
       done()

     for name, params of methods then do (name, params) ->
-      {key, type, exclude, aliases} = params
+      {key, type, exclude, aliases, description} = params
       key ||= name
       aliases ||= []

@@ -102,6 +102,12 @@
                 data.should.have.keys key, '_', '__', 'o'
                 data[key].should.be.ok

+          it 'should have description', (done) ->
+            filename = Math.random().toString(36)
+            webp = new Webp filename
+            webp[name].should.have.property 'description', description
+            done()
+
     describe 'convention', ->

       it 'should send -preset first', ->


SidebarMachineBox: Make data a Machine instance.

--- client/Social/Activity/sidebar/sidebarmachinebox.coffee
+++ client/Social/Activity/sidebar/sidebarmachinebox.coffee
@@ -6,7 +6,9 @@

     { machine } = data

-    @addSubView @machineItem = new NavigationMachineItem {}, machine
+    @machine = new Machine machine: KD.remote.revive machine
+
+    @addSubView @machineItem = new NavigationMachineItem {}, @machine

     @createWorkspacesLabel()
     @createWorkspacesList()


NFinderController: fix `mountVm` method call in `updateVMRoot` method

--- client/ide/filetree/controllers/findercontroller.coffee
+++ client/ide/filetree/controllers/findercontroller.coffee
@@ -212,7 +212,10 @@
     vmRoots[pipedVm] = path
     @appStorage.setValue 'vmRoots', vmRoots  if @getOptions().useStorage

-    @mountVm "#{vmName}:#{path}"
+    KD.singleton("vmController").fetchVmsByName [vmName], (err, [vm]) =>
+      return KD.showError err  if err
+      vm.path = path
+      @mountVm vm

   cleanup:->
     @treeController.removeAllNodes()


add factlink-control-frame class

add factlink-control-frame class

--- js-library/app/js/jail_iframe/classes/control_iframe.coffee
+++ js-library/app/js/jail_iframe/classes/control_iframe.coffee
@@ -3,6 +3,7 @@
   constructor: ->
     console.log('creating frame')
     @el = document.createElement('iframe')
+    @el.className = 'factlink-control-frame'
     #need to append to outer document before we can access frame document.
     FactlinkJailRoot.$factlinkCoreContainer.append(@el)
     @$el = $(@el)


Moved set_opinion for fact and fact_relation to base class

--- core/app/backbone/views/fact_relations/vote_view.coffee
+++ core/app/backbone/views/fact_relations/vote_view.coffee
@@ -4,6 +4,22 @@

   events:
     'click .btn-primary': 'save'
+
+  set_fact_relation_opinion: (opinion, enable_opinion) ->
+    is_current_opinion = @model.current_opinion() == opinion
+
+    if enable_opinion
+      @model.setOpinion opinion unless is_current_opinion
+    else
+      @model.removeOpinion() if is_current_opinion
+
+  set_fact_opinion: (opinion, enable_opinion) ->
+    is_current_opinion = @model.getFact().getFactWheel().isUserOpinion opinion
+
+    if enable_opinion
+      @_set_fact_opinion opinion unless is_current_opinion
+    else
+      @_unset_fact_opinion opinion if is_current_opinion

   _set_fact_opinion: (opinion) ->
     @model.getFact().getFactWheel().setActiveOpinionType opinion
@@ -23,29 +39,13 @@
     believes_fact: => @believes_fact()

   save: ->
-    @set_fact_relation_opinion @ui.fact_relation.is(':checked')
-    @set_fact_opinion @ui.fact.is(':checked')
+    @set_fact_relation_opinion 'believes', @ui.fact_relation.is(':checked')
+    @set_fact_opinion 'believe', @ui.fact.is(':checked')

     @trigger 'saved'

   believes_fact_relation: -> @model.isBelieving()
   believes_fact: -> @model.getFact().getFactWheel().isUserOpinion 'believe'
-
-  set_fact_relation_opinion: (enable_opinion, opinion='believes') ->
-    is_current_opinion = @model.current_opinion() == opinion
-
-    if enable_opinion
-      @model.setOpinion opinion unless is_current_opinion
-    else
-      @model.removeOpinion() if is_current_opinion
-
-  set_fact_opinion: (enable_opinion, opinion='believe') ->
-    is_current_opinion = @model.getFact().getFactWheel().isUserOpinion opinion
-
-    if enable_opinion
-      @_set_fact_opinion opinion unless is_current_opinion
-    else
-      @_unset_fact_opinion opinion if is_current_opinion

 class window.FactRelationVoteDownView extends FactRelationVoteView
   ui:


Update tests.

Update tests.

--- test/test.coffee
+++ test/test.coffee
@@ -3,17 +3,22 @@
     res = yield browser.evaluate -> 42
     res.should.eq 42

+    res = yield browser.evaluate (a, b, c) ->
+      a * b * c
+    , 1, 2, 3
+    res.should.eq 6
+
   it 'should support node.js style callbacks', ->
-    res = yield browser.evaluate (cb) ->
-      cb null, 1
-    res.should.eq 1
-
     p = browser.evaluate (cb) ->
         setTimeout ->
           cb new Error 'eep'
         , 10
+    (do ->  yield p).next.should.throw Error

-    (do ->  yield p).next.should.throw Error
+    res = yield browser.evaluate (a, b, c, cb) ->
+      cb null, a * b * c * 2
+    , 1, 2, 3
+    res.should.eq 12

   it 'should wait for promise to complete', ->
     res = yield browser.evaluate ->


Added a test for the edge case that came up in bulkGetOpsSince

--- test/test.coffee
+++ test/test.coffee
@@ -403,8 +403,8 @@
           assert.deepEqual ops, []
           done()

-    it 'caches the version in redis', (done) -> @create =>
-      @redis.flushdb =>
+    it 'caches the version in redis', (done) ->
+      @create => @redis.flushdb =>
         @collection.getOps @docName, 0, (err, ops) =>
           throw new Error err if err

@@ -416,6 +416,22 @@

     it 'errors if ops are missing from the snapshotdb and oplogs'
+
+  describe 'bulkGetOpsSince', ->
+    # This isn't really an external API, but there is a tricky edge case which
+    # can come up that its hard to recreate using bulkSubscribe directly.
+    it 'handles multiple gets which are missing from redis correctly', (done) -> # regression
+      # Nothing in redis, but the data of two documents are in the database.
+      @db.writeOp 'test', 'one', {v:0, create:{type:otTypes.text.uri}}, =>
+      @db.writeOp 'test', 'two', {v:0, create:{type:otTypes.text.uri}}, =>
+
+        @client.bulkGetOpsSince {test:{one:0, two:0}}, (err, result) ->
+          throw Error err if err
+          assert.deepEqual result,
+            test:
+              one: [{v:0, create:{type:otTypes.text.uri}}]
+              two: [{v:0, create:{type:otTypes.text.uri}}]
+            done()

   describe 'subscribe', ->
     for subType in ['single', 'bulk'] then do (subType) -> describe subType, ->


Add tests

Add tests

--- test/type.coffee
+++ test/type.coffee
@@ -173,9 +173,34 @@
         else
           8

-    test 'throw function arguments mismatch', ->
+    test 'throw if return type mismatch', ->
       throws ->
         CoffeeScript.parse """
           a :: Number = if true then 3 else ""
         """

+    test 'for', ->
+      list :: Number[] =
+        for i :: Number, n in [1..3]
+          nn :: Number  = 3
+          nn
+
+      list2 :: Number[] =
+        for i :: Number, n in [1..3]
+          i
+
+      list3 :: Number[] =
+        for i :: Number, n in [1..3]
+          n
+
+    test 'throw return type mismatch', ->
+      throws ->
+        CoffeeScript.parse """
+          arr :: Number[] = ("" for i in [1,2,3])
+        """
+
+    test 'throw target mismatch', ->
+      throws ->
+        CoffeeScript.parse """
+          arr :: Number[] = (i for i :: Number in [1,2,""])
+        """


fixing tingodb cursor behavioir

fixing tingodb cursor behavioir

--- modules/stores/platforms/node/lib/engines/MongoStore.coffee
+++ modules/stores/platforms/node/lib/engines/MongoStore.coffee
@@ -78,9 +78,9 @@
         find: (query, options, fields, fn)->

             #console.log 'query', query, options, fields
-            q = @_client.find(query)
-            q.count (err, size)=>
+            @_client.count {}, {}, (err, size)=>
                 return fn?(err) if err
+                q = @_client.find(query)

                 #console.log 'size', size
                 options ?= {}
@@ -96,12 +96,14 @@

                 for method in __OPTIONS
                     if options[method] && q[method]
-                        #console.log options[method] , q[method]
-                        q[method] options[method]
+                        #console.log 'phase 1 method', method, options[method]
+                        q = _q if _q = q[method] options[method]
+

                 for method, value of options
                     if __OPTIONS.indexOf(method) is -1 && q[method]
-                        q[method] value
+                        #console.log 'phase 2 method', method, value
+                        q = _q if _q = q[method] value

                 if fn
                     setImmediate ()=>


Improve database page

Improve database page

--- admin/static/coffee/ui_components/modals.coffee
+++ admin/static/coffee/ui_components/modals.coffee
@@ -161,6 +161,7 @@
                 when 'datacenter' then return datacenters.get(@item_uuid)
                 when 'namespace' then return namespaces.get(@item_uuid)
                 when 'machine' then return machines.get(@item_uuid)
+                when 'database' then return databases.get(@item_uuid)
                 else return null

         get_item_url: ->
@@ -168,6 +169,7 @@
                 when 'datacenter' then return 'datacenters'
                 when 'namespace' then return namespaces.get(@item_uuid).get('protocol') + '_namespaces'
                 when 'machine' then return 'machines'
+                when 'database' then return 'databases'
                 else return null

         render: ->


fixing seamless script

fixing seamless script

--- src/scripts/seamless.coffee
+++ src/scripts/seamless.coffee
@@ -15,8 +15,8 @@

 module.exports = (robot) ->

-  robot.respond /leamsess/gi, (msg) ->
-    msg.respond 'Fetching...'
+  robot.respond /leamsess|seamless/gi, (msg) ->
+    msg.send 'Fetching...'
     options =
       host: 'gojee-seamless.herokuapp.com',
       port: 80,


Add languages to settings

Add languages to settings

--- src/scripts/settings.coffee
+++ src/scripts/settings.coffee
@@ -1,4 +1,6 @@
 define (require) ->
+  languages = require('cs!configs/languages')
+
   return {
     # Directory from which webview is served
     root: '/'
@@ -10,4 +12,7 @@

     # Google Analytics tracking ID
     analyticsID: 'UA-7903479-1'
+
+    # Supported languages
+    languages: languages
   }


Makes build install node dependencies and adds mdl-themes to dependencies list

--- build.coffee
+++ build.coffee
@@ -94,7 +94,7 @@

 install_dependencies = () ->
     console.log 'Installing dependencies'
-    components = ['material-design-lite', 'jquery']
+    components = ['material-design-lite', 'mdl-themes', 'jquery']
     for component in components
         unless exists ['bower_components', component.split('#')[0]].join '/'
             console.log '... installing ' + component
@@ -135,6 +135,9 @@
     cmd = "convert #{input} #{opts} #{output}"
     execute cmd

+install_desktop_node = ->
+    execute 'npm --prefix desktop/www install desktop/www'
+
 execute 'npm install'

 # Removes all contents from mobile/www
@@ -169,4 +172,7 @@
 # Generate desktop icons
 gen_desktop_icons()

+# Install node dependencies of desktop version
+install_desktop_node()
+
 console.log ''


webapp/billing: FAQ entry about customized invoices

--- src/smc-webapp/billing.cjsx
+++ src/smc-webapp/billing.cjsx
@@ -1115,6 +1115,14 @@
             We do strongly suggest the classes upgrade all projects to "members-only" hosting,
             since this provides much better computers with higher availability.

+    invoice:
+        q: How do I get an invoice with a specific information?
+        a:
+            After purchasing, please email us at <HelpEmailLink />, reference what you bought,
+            and tell us the payer{"'"}s name, contact information and any other specific
+            instructions.   We will then respond with a custom invoice for your purchase that
+            satisfies your unique requirements.
+
     close_browser:
         q: Can I close my web-browser while I{"'"}m working?
         a:


Fix course year plan not highlighting

Fix course year plan not highlighting

--- src/smc-webapp/billing.cjsx
+++ src/smc-webapp/billing.cjsx
@@ -1114,7 +1114,7 @@
         is_static : false

     is_selected: (plan, period) ->
-        if @props.period is 'year'
+        if @props.period?.slice(0, 4) is 'year'
             return @props.selected_plan is "#{plan}-year"
         else
             return @props.selected_plan is plan


DE16366: Make policies scoped to field+value

--- kanban/KanbanAppSpec.coffee
+++ kanban/KanbanAppSpec.coffee
@@ -6,6 +6,200 @@
 ]

 describe 'Rally.apps.kanban.KanbanApp', ->
+
+  beforeEach ->
+    @ajax.whenQuerying('userstory').respondWith()
+    @ajax.whenQuerying('defect').respondWith()
+
+    @projectRef = Rally.environment.getContext().getProject()._ref
+
+  afterEach ->
+    @app?.destroy()
+
+  it 'has the correct default settings', ->
+    @createApp().then =>
+
+      expect(@app.getSetting('groupByField')).toBe 'ScheduleState'
+      expect(@app.getSetting('columns')).toBe Ext.JSON.encode(
+        Defined:
+          wip: ''
+        'In-Progress':
+          wip: ''
+        Completed:
+          wip: ''
+        Accepted:
+          wip: ''
+      )
+      expect(@app.getSetting('cardFields')).toBe 'Name,Discussion,Tasks,Defects'
+
+  it 'does not show add new when user is not a project editor', ->
+    Rally.environment.getContext().getPermissions().userPermissions[0].Role = 'Viewer'
+    @createApp().then =>
+
+      expect(@app.down 'rallyaddnew').toBeNull()
+
+  it 'shows add new for user who is a project editor', ->
+    @createApp().then =>
+      expect(@app.down 'rallyaddnew').toBeDefined()
+
+  it 'should not schedule a new item in an iteration', ->
+    @createApp().then =>
+      editorOpenedStub = @stub(Rally.nav.Manager, 'create')
+      addNewHelper = new Helpers.AddNewHelper '.kanban'
+      addNewHelper.addWithDetails('foo').then =>
+        expect(editorOpenedStub).toHaveBeenCalledOnce()
+        expect(editorOpenedStub.getCall(0).args[1].iteration).toBe 'u'
+
+  it 'should set group by field to first column value', ->
+    @createApp().then =>
+      editorOpenedStub = @stub(Rally.nav.Manager, 'create')
+      addNewHelper = new Helpers.AddNewHelper '.kanban'
+      addNewHelper.addWithDetails('foo').then =>
+        expect(editorOpenedStub).toHaveBeenCalledOnce()
+        expect(editorOpenedStub.getCall(0).args[1]['c_' + @app.getSetting('groupByField')]).toBe @app.cardboard.getColumns()[0].getValue()
+
+  it 'should show correct fields on cards', ->
+    @createApp({cardFields: 'Name,Defects,Project'}).then =>
+
+      expect(@app.down('rallycardboard').cardConfig.fields).toContain 'Name'
+      expect(@app.down('rallycardboard').cardConfig.fields).toContain 'Defects'
+      expect(@app.down('rallycardboard').cardConfig.fields).toContain 'Project'
+
+  it 'should show columns with correct wips based on settings', ->
+    columnSettings =
+      Defined:
+        wip: 1
+      'In-Progress':
+        wip: 2
+
+    @createApp({columns: Ext.JSON.encode(columnSettings), groupByField: 'ScheduleState'}).then =>
+
+      columns = @app.down('rallycardboard').getColumns()
+      expect(columns.length).toBe 2
+      expect(columns[0].wipLimit).toBe columnSettings.Defined.wip
+      expect(columns[1].wipLimit).toBe columnSettings['In-Progress'].wip
+
+  it 'should filter the board when a type checkbox is clicked', ->
+    @createApp().then =>
+      board = @app.down('rallycardboard')
+      filterSpy = @spy board, 'addLocalFilter'
+
+      # Clicking defect will uncheck it as its checked by default
+      @click(css: '.defect-type-checkbox input')
+
+      once(
+        condition: => filterSpy.calledOnce
+        description: 'filter to be called without defect'
+      ).then =>
+        args = filterSpy.getCall(0).args
+        expect(args[1]).toEqual ['hierarchicalrequirement']
+
+      @click(css: '.defect-type-checkbox input')
+      once(
+        condition: => filterSpy.calledTwice
+        description: 'filter to be called with defect'
+      ).then =>
+        args = filterSpy.getCall(1).args
+        expect(args[1]).toEqual ['defect', 'hierarchicalrequirement']
+
+  it 'should contain menu options', ->
+    @createApp().then =>
+      options = @app.getOptions()
+
+      expect(options.length).toBe 3
+      expect(options[0].text).toBe 'Show Cycle Time Report'
+      expect(options[1].text).toBe 'Show Throughput Report'
+      expect(options[2].text).toBe 'Print'
+
+  it 'should correctly build report config for non schedule state field stories', ->
+    @createApp().then =>
+      @stub(@app, 'getSetting').returns('KanbanState')
+      @stub(@app, '_getShownTypes').returns([{workItemType: 'G'}])
+      report_config = @app._buildReportConfig(Rally.ui.report.StandardReport.Reports.CycleLeadTime)
+
+      expect(report_config.filter_field).toBe @app.groupByField.displayName
+      expect(report_config.work_items).toBe 'G'
+      expect(report_config.report.id).toBe Rally.ui.report.StandardReport.Reports.CycleLeadTime.id
+
+  it 'should correctly build report config for schedule state field with story and defect types', ->
+    @createApp().then =>
+      report_config = @app._buildReportConfig(Rally.ui.report.StandardReport.Reports.Throughput)
+
+      expect(report_config.filter_field).toBeUndefined()
+      expect(report_config.work_items).toBe 'N'
+      expect(report_config.report.id).toBe Rally.ui.report.StandardReport.Reports.Throughput.id
+
+  it 'should correctly build standard report component config', ->
+    @createApp().then =>
+      report_config = {report: 5}
+      standard_report_config = @app._buildStandardReportConfig(report_config)
+
+      expect(standard_report_config.project).toBe @app.getContext().getDataContext().project
+      expect(standard_report_config.projectScopeDown).toBe @app.getContext().getDataContext().projectScopeDown
+      expect(standard_report_config.projectScopeUp).toBe @app.getContext().getDataContext().projectScopeUp
+      expect(standard_report_config.reportConfig).toBe report_config
+
+  it 'should exclude items with a release set in the last column', ->
+    @createApp(hideReleasedCards: true).then =>
+      columns = @app.down('rallycardboard').getColumns()
+      lastColumn = columns[columns.length-1]
+
+      expect(lastColumn.storeConfig.filters.length).toBe 1
+      expect(lastColumn.storeConfig.filters[0].property).toBe 'Release'
+      expect(lastColumn.storeConfig.filters[0].value).toBeNull()
+
+  it 'should not exclude items with a release set in the last column', ->
+    @createApp(hideReleasedCards: false).then =>
+      columns = @app.down('rallycardboard').getColumns()
+      lastColumn = columns[columns.length-1]
+
+      expect(lastColumn.storeConfig.filters.length).toBe 0
+
+  it 'should show filter info when following global project', ->
+    @createApp().then =>
+      filterInfo = @app.down('rallyfilterinfo')
+      expect(filterInfo.getProjectName()).toBe 'Following Global Project Setting'
+
+  it 'should show filter info when scoped to a specific project', ->
+    projectScopeUp = true
+    projectScopeDown = false
+    @createApp(project: @projectRef, projectScopeUp: projectScopeUp, projectScopeDown: projectScopeDown).then =>
+      filterInfo = @app.down('rallyfilterinfo')
+      expect(filterInfo.getProjectName()).toBe @app.getContext().getProject().Name
+      expect(filterInfo.getScopeUp()).toBe projectScopeUp
+      expect(filterInfo.getScopeDown()).toBe projectScopeDown
+
+  it 'should show filter info when a query is set', ->
+    query = '(Name contains Foo)'
+    @createApp(query: query).then =>
+      filterInfo = @app.down('rallyfilterinfo')
+      expect(filterInfo.getQuery()).toBe query
+
+  it 'should show plan estimate when plan estimate field is enabled', ->
+    @ajax.whenQuerying('userstory').respondWithCount(1)
+    @createApp(cardFields: "Name,Discussion,Tasks,Defects,PlanEstimate").then =>
+      expect(@app.getEl().down('.PlanEstimate')).not.toBeNull()
+
+  it 'should not show plan estimate when plan estimate field is disabled', ->
+    @ajax.whenQuerying('userstory').respondWithCount(1)
+    @createApp(cardFields: "Name,Discussion,Tasks,Defects").then =>
+      expect(@app.getEl().down('.PlanEstimate')).toBeNull()
+
+  it 'should specify the correct policy preference setting key', ->
+    policy = 'Foo'
+    settingsKey = 'ScheduleStateDefinedPolicy'
+    settings = {}
+    settings[settingsKey] = policy
+    @createApp(settings).then =>
+      @assertPolicyCmpConfig(settingsKey, policy)
+
+  it 'should load legacy non field scoped policy setting', ->
+    policy = 'Foo'
+    settingsKey = 'ScheduleStateDefinedPolicy'
+    settings = {}
+    settings['DefinedPolicy'] = policy
+    @createApp(settings).then =>
+      @assertPolicyCmpConfig(settingsKey, policy)

   helpers
     createApp: (settings = {}) ->
@@ -24,181 +218,9 @@

       @waitForComponentReady @app

-  beforeEach ->
-    @ajax.whenQuerying('userstory').respondWith()
-    @ajax.whenQuerying('defect').respondWith()
-
-    @projectRef = Rally.environment.getContext().getProject()._ref
-
-  afterEach ->
-    @app?.destroy()
-
-  it 'has the correct default settings', ->
-    @createApp().then =>
-
-      expect(@app.getSetting('groupByField')).toBe 'ScheduleState'
-      expect(@app.getSetting('columns')).toBe Ext.JSON.encode(
-        Defined:
-          wip: ''
-        'In-Progress':
-          wip: ''
-        Completed:
-          wip: ''
-        Accepted:
-          wip: ''
-      )
-      expect(@app.getSetting('cardFields')).toBe 'Name,Discussion,Tasks,Defects'
-
-  it 'does not show add new when user is not a project editor', ->
-    Rally.environment.getContext().getPermissions().userPermissions[0].Role = 'Viewer'
-    @createApp().then =>
-
-      expect(@app.down 'rallyaddnew').toBeNull()
-
-  it 'shows add new for user who is a project editor', ->
-    @createApp().then =>
-      expect(@app.down 'rallyaddnew').toBeDefined()
-
-  it 'should not schedule a new item in an iteration', ->
-    @createApp().then =>
-      editorOpenedStub = @stub(Rally.nav.Manager, 'create')
-      addNewHelper = new Helpers.AddNewHelper '.kanban'
-      addNewHelper.addWithDetails('foo').then =>
-        expect(editorOpenedStub).toHaveBeenCalledOnce()
-        expect(editorOpenedStub.getCall(0).args[1].iteration).toBe 'u'
-
-  it 'should set group by field to first column value', ->
-    @createApp().then =>
-      editorOpenedStub = @stub(Rally.nav.Manager, 'create')
-      addNewHelper = new Helpers.AddNewHelper '.kanban'
-      addNewHelper.addWithDetails('foo').then =>
-        expect(editorOpenedStub).toHaveBeenCalledOnce()
-        expect(editorOpenedStub.getCall(0).args[1]['c_' + @app.getSetting('groupByField')]).toBe @app.cardboard.getColumns()[0].getValue()
-
-  it 'should show correct fields on cards', ->
-    @createApp({cardFields: 'Name,Defects,Project'}).then =>
-
-      expect(@app.down('rallycardboard').cardConfig.fields).toContain 'Name'
-      expect(@app.down('rallycardboard').cardConfig.fields).toContain 'Defects'
-      expect(@app.down('rallycardboard').cardConfig.fields).toContain 'Project'
-
-  it 'should show columns with correct wips based on settings', ->
-    columnSettings =
-      Defined:
-        wip: 1
-      'In-Progress':
-        wip: 2
-
-    @createApp({columns: Ext.JSON.encode(columnSettings), groupByField: 'ScheduleState'}).then =>
-
-      columns = @app.down('rallycardboard').getColumns()
-      expect(columns.length).toBe 2
-      expect(columns[0].wipLimit).toBe columnSettings.Defined.wip
-      expect(columns[1].wipLimit).toBe columnSettings['In-Progress'].wip
-
-  it 'should filter the board when a type checkbox is clicked', ->
-    @createApp().then =>
-      board = @app.down('rallycardboard')
-      filterSpy = @spy board, 'addLocalFilter'
-
-      # Clicking defect will uncheck it as its checked by default
-      @click(css: '.defect-type-checkbox input')
-
-      once(
-        condition: => filterSpy.calledOnce
-        description: 'filter to be called without defect'
-      ).then =>
-        args = filterSpy.getCall(0).args
-        expect(args[1]).toEqual ['hierarchicalrequirement']
-
-      @click(css: '.defect-type-checkbox input')
-      once(
-        condition: => filterSpy.calledTwice
-        description: 'filter to be called with defect'
-      ).then =>
-        args = filterSpy.getCall(1).args
-        expect(args[1]).toEqual ['defect', 'hierarchicalrequirement']
-
-  it 'should contain menu options', ->
-    @createApp().then =>
-      options = @app.getOptions()
-
-      expect(options.length).toBe 3
-      expect(options[0].text).toBe 'Show Cycle Time Report'
-      expect(options[1].text).toBe 'Show Throughput Report'
-      expect(options[2].text).toBe 'Print'
-
-  it 'should correctly build report config for non schedule state field stories', ->
-    @createApp().then =>
-      @stub(@app, 'getSetting').returns('KanbanState')
-      @stub(@app, '_getShownTypes').returns([{workItemType: 'G'}])
-      report_config = @app._buildReportConfig(Rally.ui.report.StandardReport.Reports.CycleLeadTime)
-
-      expect(report_config.filter_field).toBe @app.groupByField.displayName
-      expect(report_config.work_items).toBe 'G'
-      expect(report_config.report.id).toBe Rally.ui.report.StandardReport.Reports.CycleLeadTime.id
-
-  it 'should correctly build report config for schedule state field with story and defect types', ->
-    @createApp().then =>
-      report_config = @app._buildReportConfig(Rally.ui.report.StandardReport.Reports.Throughput)
-
-      expect(report_config.filter_field).toBeUndefined()
-      expect(report_config.work_items).toBe 'N'
-      expect(report_config.report.id).toBe Rally.ui.report.StandardReport.Reports.Throughput.id
-
-  it 'should correctly build standard report component config', ->
-    @createApp().then =>
-      report_config = {report: 5}
-      standard_report_config = @app._buildStandardReportConfig(report_config)
-
-      expect(standard_report_config.project).toBe @app.getContext().getDataContext().project
-      expect(standard_report_config.projectScopeDown).toBe @app.getContext().getDataContext().projectScopeDown
-      expect(standard_report_config.projectScopeUp).toBe @app.getContext().getDataContext().projectScopeUp
-      expect(standard_report_config.reportConfig).toBe report_config
-
-  it 'should exclude items with a release set in the last column', ->
-    @createApp(hideReleasedCards: true).then =>
-      columns = @app.down('rallycardboard').getColumns()
-      lastColumn = columns[columns.length-1]
-
-      expect(lastColumn.storeConfig.filters.length).toBe 1
-      expect(lastColumn.storeConfig.filters[0].property).toBe 'Release'
-      expect(lastColumn.storeConfig.filters[0].value).toBeNull()
-
-  it 'should not exclude items with a release set in the last column', ->
-    @createApp(hideReleasedCards: false).then =>
-      columns = @app.down('rallycardboard').getColumns()
-      lastColumn = columns[columns.length-1]
-
-      expect(lastColumn.storeConfig.filters.length).toBe 0
-
-  it 'should show filter info when following global project', ->
-    @createApp().then =>
-      filterInfo = @app.down('rallyfilterinfo')
-      expect(filterInfo.getProjectName()).toBe 'Following Global Project Setting'
-
-  it 'should show filter info when scoped to a specific project', ->
-      projectScopeUp = true
-      projectScopeDown = false
-      @createApp(project: @projectRef, projectScopeUp: projectScopeUp, projectScopeDown: projectScopeDown).then =>
-        filterInfo = @app.down('rallyfilterinfo')
-        expect(filterInfo.getProjectName()).toBe @app.getContext().getProject().Name
-        expect(filterInfo.getScopeUp()).toBe projectScopeUp
-        expect(filterInfo.getScopeDown()).toBe projectScopeDown
-
-  it 'should show filter info when a query is set', ->
-      query = '(Name contains Foo)'
-      @createApp(query: query).then =>
-        filterInfo = @app.down('rallyfilterinfo')
-        expect(filterInfo.getQuery()).toBe query
-
-  it 'should show plan estimate when plan estimate field is enabled', ->
-    @ajax.whenQuerying('userstory').respondWithCount(1)
-    @createApp(cardFields: "Name,Discussion,Tasks,Defects,PlanEstimate").then =>
-      expect(@app.getEl().down('.PlanEstimate')).not.toBeNull()
-
-  it 'should not show plan estimate when plan estimate field is disabled', ->
-    @ajax.whenQuerying('userstory').respondWithCount(1)
-    @createApp(cardFields: "Name,Discussion,Tasks,Defects").then =>
-      expect(@app.getEl().down('.PlanEstimate')).toBeNull()
-
+    assertPolicyCmpConfig: (settingsKey, policy) ->
+      column = @app.down('rallycardboard').getColumns()[0]
+      prefConfigSettings = column.policyCmpConfig.prefConfig.settings
+      expect(Ext.Object.getKeys(prefConfigSettings)[0]).toBe settingsKey
+      expect(prefConfigSettings[settingsKey]).toBe policy
+      expect(column.policyCmpConfig.policies).toBe policy


Use native keybindings to move commit detail

--- keymaps/git-experiment.cson
+++ keymaps/git-experiment.cson
@@ -36,3 +36,5 @@

 'git-experiment-commit-details-view':
   'left': 'git-experiment:focus-commit-list'
+  'down': 'native!'
+  'up': 'native!'


Little typo in the doc

Little typo in the doc

--- library/nucleus/api.coffee
+++ library/nucleus/api.coffee
@@ -141,5 +141,5 @@
     document.describe @prototype.OPTIONS, (method, service) ->
         @leads tools.urlWithHost no, service.location()
         @notes "This method is default implemented for each service"
-        @synopsis "Get a set of HTTP methods supported by services"
+        @synopsis "Get a set of HTTP methods supported by service"
         @outputs "An array of supported methods, JSON or string"


lodchart: animation of points at markers in top figure

--- lodchart/test_lodchart.coffee
+++ lodchart/test_lodchart.coffee
@@ -27,6 +27,15 @@
                     return d3.rgb(200,200,200) if i % 2
                     d3.rgb(230,230,230))

+  # animate points at markers on click
+  mychart.markerSelect()
+            .on "click", (d) ->
+                  r = d3.select(this).attr("r")
+                  d3.select(this)
+                    .transition().duration(500).attr("r", r*3)
+                    .transition().duration(500).attr("r", r)
+
+# two LOD charts within one SVG
 d3.json "scanone.json", (data) ->
   mychart_em = lodchart().lodvarname("lod.em")
                          .height(h)
@@ -58,4 +67,3 @@

   chart2.datum(data)
     .call(mychart_hk)
-


Change the data mount point to /resin-data

--- src/config.coffee
+++ src/config.coffee
@@ -15,6 +15,6 @@
 		Binds: [
 			'/mnt/mmcblk0p1/config.json:/boot/config.json'
 			'/var/run/docker.sock:/run/docker.sock'
-			'/var/lib/docker/data:/data'
+			'/resin-data/resin-supervisor:/data'
 			'/proc/net/fib_trie:/mnt/fib_trie'
 		]


Not use underscore here

Not use underscore here

--- src/config.coffee
+++ src/config.coffee
@@ -1,4 +1,3 @@
-_      = require 'underscore'
 fs     = require 'fs'
 logger = require 'loggy'

@@ -9,7 +8,7 @@
     {@token, @repos, @members} = JSON.parse fs.readFileSync(@_getConfigFilePath(), 'utf8')

   _getConfigFilePath: ->
-    path = if !_.isUndefined(@configFile) and fs.existsSync("#{process.cwd()}/#{@configFile}")
+    path = if @configFile? and fs.existsSync("#{process.cwd()}/#{@configFile}")
       "#{process.cwd()}/#{@configFile}"
     else if fs.existsSync "#{process.cwd()}/#{fileName}"
       "#{process.cwd()}/#{fileName}"


Move static function outside

Move static function outside

--- resources/assets/coffee/react/_components/icon-expand.coffee
+++ resources/assets/coffee/react/_components/icon-expand.coffee
@@ -18,13 +18,13 @@
 {span} = React.DOM
 el = React.createElement

+elem = ({position, icon}) ->
+  span
+    key: position
+    className: "icon-stack__icon icon-stack__icon--#{position}"
+    el Icon, name: icon, modifiers: ['fw']
+
 @IconExpand = ({expand = true}) ->
-  elem = ({position, icon}) ->
-    span
-      key: position
-      className: "icon-stack__icon icon-stack__icon--#{position}"
-      el Icon, name: icon, modifiers: ['fw']
-
   span
     className: 'icon-stack'
     span className: 'icon-stack__base',


Removed unwanted logs

Removed unwanted logs

--- src/steroids/connect.coffee
+++ src/steroids/connect.coffee
@@ -181,10 +181,6 @@

       maker = =>
         return if isMaking
-
-
-        console.log "isMaking " + isMaking
-
         isMaking = true

         steroidsCli.log
@@ -199,17 +195,14 @@
             doFullReload()
         .then =>
           isMaking = false
-        console.log "value if should Make" + shouldMake

       appWatcher.on ["add", "change", "unlink"], (path)=>
-        console.log "Change detected in app"
         maker();
         return;

       wwwWatcher.on ["add", "change", "unlink"], (path)=>
-        console.log "Change detected in www folder"
         maker();
         return;


Update the game in progress after it ends

--- resources/assets/coffee/react/mp-history/main.coffee
+++ resources/assets/coffee/react/mp-history/main.coffee
@@ -52,8 +52,17 @@
     .done (data) =>
       return if _.isEmpty data.events.data

-      newEvents = _.concat @state.events, data.events.data
-      lastEvent = _.last(newEvents)
+      lastIndex = _.findLastIndex @state.events, (o) => o.id == @state.since + 1
+
+      lastIndex =
+        if lastIndex == -1
+          @state.events.length - 1
+        else
+          lastIndex - 1
+
+      newEvents = _.concat @state.events[..lastIndex], data.events.data
+      lastEvent = _.last newEvents
+      lastGameEvent = _.findLast newEvents, (o) -> o.game?

       newUsers = _(data.users.data)
         .keyBy (o) -> o.id
@@ -64,7 +73,7 @@
         events: newEvents
         allEventsCount: data.all_events_count
         users: newUsers
-        since: _.last(newEvents).id
+        since: if !lastGameEvent? || lastGameEvent.game.data.end_time then lastEvent.id else lastGameEvent.id - 1
         disbanded: lastEvent.event_type == 'match-disbanded'

     .always =>


$deleteAllDrafts

$deleteAllDrafts

Signed-off-by: Jessica González <52329a27ea5670aeec0efeeb0773bf1b4f1affa1@missallsunday.com>

--- src/summernoteDrafts.coffee
+++ src/summernoteDrafts.coffee
@@ -129,7 +129,7 @@
         title: lang.load
         fade: options.dialogsFade
         body: body
-        footer = footer).render().appendTo $container
+        footer: footer).render().appendTo $container
       return

     @destroy = =>
@@ -175,5 +175,18 @@

             else
               alert lang.noDraft
+
+      $deleteAllDrafts = @$dialog.find 'button.deleteAll'
+        .click (e) ->
+          if confirm lang.youSure
+            for key, draft of drafts
+              do ->
+                store.remove key
+
+            uiDialog = self.$dialog.find 'ul.list-group'
+              .hide 'slow', ->
+                $(this).remove()
+                return
+
       return
     return


Drag&Drop support

Drag&Drop support

--- src/cropit.coffee
+++ src/cropit.coffee
@@ -6,6 +6,7 @@
     imageBackgroundBorderWidth: 0
     imageState: null
     allowCrossOrigin: false
+    allowDrag: true
     fitWidth: false
     fitHeight: false

@@ -113,9 +114,15 @@
     @$preview.on Cropit.PREVIEW_EVENTS, @onPreviewEvent.bind @
     @$zoomSlider.on Cropit.ZOOM_INPUT_EVENTS, @onZoomSliderChange.bind @

+    if @options.allowDrag
+      jQuery.event.props.push('dataTransfer');
+      @$preview.on 'dragover.cropit dragleave.cropit', @onDragOver.bind @
+      @$preview.on 'drop.cropit', @onDrop.bind @
+
   unbindListeners: ->
     @$fileInput.off 'change.cropit'
     @$preview.off Cropit.PREVIEW_EVENTS
+    @$preview.off 'dragover.cropit dragleave.cropit drop.cropit'
     @$zoomSlider.off Cropit.ZOOM_INPUT_EVENTS

   reset: ->
@@ -125,8 +132,10 @@
   onFileChange: ->
     @options.onFileChange?()

+    @loadFileReader @$fileInput.get(0).files[0]
+
+  loadFileReader: (file) ->
     fileReader = new FileReader()
-    file = @$fileInput.get(0).files[0]
     if file?.type.match 'image'
       @setImageLoadingClass()

@@ -140,6 +149,25 @@

   onFileReaderError: ->
     @options.onFileReaderError?()
+
+  onDragOver: (e) ->
+    e.preventDefault()
+    e.dataTransfer.dropEffect = 'copy'
+    @$preview.toggleClass 'drag-hover', e.type == 'dragover'
+
+  onDrop: (e) ->
+    e.preventDefault()
+    e.stopPropagation()
+    files = e.dataTransfer.files
+    i = 0
+
+    while f = files[i]
+      if f.type.match("image")
+        @loadFileReader f
+        break
+      i++
+
+    @$preview.toggleClass 'drag-hover', false

   loadImage: (imageSrc) ->
     @imageSrc = imageSrc


bad bug

bad bug

--- src/dt-jquery.coffee
+++ src/dt-jquery.coffee
@@ -87,7 +87,7 @@

     replace_callback: (oldtag, newtag) ->
         if newtag._jquery.length is 0
-            createSpaceholder.call(that, newtag, newtag.parent._jquery)
+            createSpaceholder.call(this, newtag, newtag.parent._jquery)
         super
         $fyBuilder(newtag) if newtag is newtag.builder


修正Field自动生成内部编辑器时的逻辑错误

修正Field自动生成内部编辑器时的逻辑错误

--- src/widget/edit/form.coffee
+++ src/widget/edit/form.coffee
@@ -227,7 +227,8 @@
 		if bind then @_bindSetter(bind)

 		propertyDef = @_getPropertyDef()
-		@_applyPropertyDefProperties?(propertyDef)
+		if propertyDef
+			@_applyPropertyDefProperties?(propertyDef)

 		if bind and dom.childElementCount is 0
 			dom.appendChild($.xCreate(
@@ -246,11 +247,13 @@
 					editContent = { tagName: "c-datepicker", bind: bind, readOnly: @_readOnly or formReadOnly }
 				else if @_type is "textarea"
 					editContent = { tagName: "c-textarea", bind: bind, readOnly: @_readOnly or formReadOnly }
-
-			editDom = cola.xCreate(editContent)
-			dom.appendChild(editDom)
-			cola.xRender(editDom, @_scope)
-			editDom.setAttribute(cola.constants.IGNORE_DIRECTIVE, "")
+				else
+					editContent = { tagName: "c-input", bind: bind, readOnly: @_readOnly or formReadOnly }
+
+				editDom = cola.xCreate(editContent)
+				dom.appendChild(editDom)
+				cola.xRender(editDom, @_scope)
+				editDom.setAttribute(cola.constants.IGNORE_DIRECTIVE, "")

 		@_labelDom = dom.querySelector("label")
 		@_messageDom = dom.querySelector("message")


Hopefully fix registration

Hopefully fix registration

--- app/routes/register.coffee
+++ app/routes/register.coffee
@@ -23,8 +23,7 @@
     .then (token) ->
       link = "#{ config.url }/register/#{ token }"

-      if DEBUG_ROUTES
-
+      if global.DEBUG_ROUTES
         return res.send link

       res.send 'success'


Require atom after window is required

Require atom after window is required

--- src/window-bootstrap.coffee
+++ src/window-bootstrap.coffee
@@ -1,9 +1,9 @@
 # Like sands through the hourglass, so are the days of our lives.
 startTime = new Date().getTime()

-Atom = require './atom'
 require './window'

+Atom = require './atom'
 window.atom = new Atom()
 window.setUpEnvironment('editor')
 window.startEditorWindow()


Fix for trend diagram stats table

Fix for trend diagram stats table

git-svn-id: 00f01ee4f729ccc52c3e336777c3e81b5adc88db@115547 ef392f78-ee14-0410-84e5-9db46baae5bb

--- app/scripts/results.coffee
+++ app/scripts/results.coffee
@@ -1080,6 +1080,7 @@
         $("#myGrid").height(600)

         #return false
+        console.log "grad data", data
         grid = new Slick.Grid $("#myGrid"), data, columns,
             enableCellNavigation: false
             enableColumnReorder: false
@@ -1692,6 +1693,7 @@

             HTMLFormatter = (row, cell, value, columnDef, dataContext) -> value

+
             time_table_data = []
             time_table_columns_intermediate = {}
             for row in series
@@ -1701,7 +1703,18 @@
                     time_table_columns_intermediate[timestamp] =
                         "name" : timestamp
                         "field" : timestamp
-                        "formatter" : window.statsProxy.valueFormatter
+                        "formatter" : (row, cell, value, columnDef, dataContext) ->
+                            loc = {
+                                'sv' : "sv-SE"
+                                'en' : "gb-EN"
+                            }[$("body").scope().lang]
+                            fmt = (valTup) ->
+                                if typeof valTup[0] == "undefined" then return ""
+                                return "" +
+                                        "" + Number(valTup[1].toFixed(1)).toLocaleString(loc) + " " +
+                                        "(" + valTup[0].toLocaleString(loc) + ") " +
+                                  ""
+                            return fmt(value)
                     i = _.indexOf (_.pluck row.abs_data, "x"), item.x, true
                     #new_time_row[timestamp] = {"relative" : item.y, "absolute" : row.abs_data[i].y}
                     new_time_row[timestamp] = [item.y, row.abs_data[i].y]


Hide people for more than 13 zool level

Hide people for more than 13 zool level

--- app/assets/javascripts/gmaps4histvest.js.coffee
+++ app/assets/javascripts/gmaps4histvest.js.coffee
@@ -11,15 +11,17 @@
         }
         @my_map = new google.maps.Map(document.getElementById('map'), @my_mapOptions);
         @visible_infowindow = null
-        @bounds_object = new google.maps.LatLngBounds()
-        @people_clusterer = null
-        @topics_clusterer = null
+        @bounds_object = new google.maps.LatLngBounds()
+        @topics_clusterer = null
+        @people_clusterer = null
         @touch_version = false

         # action when clicking on marker content
         $(document).on('click', '.infowindow .marker-topic[data-url]', ->
             window.location = $(this).data('url') unless $('body').hasClass('touch')
         )
+
+        google.maps.event.addListener @my_map, 'zoom_changed', @togglePeople

     extend_bounds_with_objects: (objects) ->
         for obj in objects
@@ -40,8 +42,7 @@
     adjust_to_bounds_of_related_locations: ->
         related_locations = []
         for marker in @markers
-            related_locations.push marker if marker.belongs_to_current_topic
-        console.log related_locations
+            related_locations.push marker if marker.belongs_to_current_topic
         if related_locations.length > 1
             @extend_bounds_with_objects(related_locations)
             @set_center(@bounds_object.getCenter())
@@ -107,18 +108,18 @@

     clusterize: ->
         @topics_clusterer.clearMarkers() if @topics_clusterer != null
-        @people_clusterer.clearMarkers() if @people_clusterer != null
+        @people_clusterer.clearMarkers() if @people_clusterer != null

-        topics_array = new Array
+        topics_array = new Array
         people_array = new Array

         for marker in @markers
             marker.google_marker.count = marker.count
             topics_array.push marker.google_marker if marker.type == 'topic'
-            people_array.push marker.google_marker if marker.type == 'person'
+            people_array.push marker.google_marker if marker.type == 'person'

         @topics_clusterer = @create_clusterer(topics_array, 'topic')
-        @people_clusterer = @create_clusterer(people_array, 'people')
+        @people_clusterer = @create_clusterer(people_array, 'people')

     create_clusterer: (markers_array, type) ->
         if type == 'people'
@@ -139,18 +140,17 @@
                 textColor: '#ffffff'
             }]
         else
-            styles = []
+            styles = []
         clusterer = new MarkerClusterer(@my_map, markers_array, {
-            maxZoom: 11,
-            gridSize: 50,
-            styles: styles
+            maxZoom: 15,
+            gridSize: 25,
+            styles: styles
         })
         clusterer.setCalculator (markers, numStyles)->
             index = 0
             title = ""
             count = 0
-            for marker in markers
-                console.log marker
+            for marker in markers
                 if marker.count
                     count = count + marker.count
                 else
@@ -164,4 +164,13 @@
             index = Math.min index, numStyles
             return text: count, index: index, title: title
         clusterer
-        +
+    togglePeople: =>
+        showPeople = @my_map.getZoom() > 13
+        @people_clusterer.setMap if showPeople then @my_map else null
+        for marker in @markers
+            if marker.type == 'person'
+                if showPeople
+                    marker.google_marker.setMap @my_map
+                else
+                    marker.google_marker.setMap null


Calculator exponentiation Fixes #4721515

--- math/expression_to_string_spec.coffee
+++ math/expression_to_string_spec.coffee
@@ -31,8 +31,8 @@
       power = []

       exp = @exp_pos_builder('^': [10, []])
-      expect(@to_string(exp)).toEqual "10 ^ "
-      expect(@to_html_string(exp)).toEqual "10 ˆ "
+      expect(@to_string(exp)).toEqual "10 ^ ( "
+      expect(@to_html_string(exp)).toEqual "10 ˆ ( "

   describe "multiplication", ->
     it "", ->
@@ -53,7 +53,7 @@
     it "displays partial parentheses", ->
       exp = @exp_pos_builder(10, '*', [])
       actual = @to_html_string(exp)
-      expect(actual).toEqual "10 × "
+      expect(actual).toEqual "10 × ( "

     it "displays single sub-expressions with parentheses", ->
       exp = @exp_pos_builder(10, '*', [5])
@@ -63,4 +63,4 @@
   it "correctly displays pi", ->
     exp = @exp_pos_builder('pi')
     actual = @to_html_string(exp)
-    expect(actual).toEqual "π"
+    expect(actual).toEqual "π"


OX-238 fixed initial interpolation setting

--- app/assets/javascripts/oxalis/controller.coffee
+++ app/assets/javascripts/oxalis/controller.coffee
@@ -96,6 +96,7 @@
       @cameraController.setRouteClippingDistance @model.user.routeClippingDistance
       @sceneController.setRouteClippingDistance @model.user.routeClippingDistance
       @sceneController.setDisplayCrosshair @model.user.displayCrosshair
+      @sceneController.setInterpolation @model.user.interpolation
       @sceneController.setDisplaySV PLANE_XY, @model.user.displayPreviewXY
       @sceneController.setDisplaySV PLANE_YZ, @model.user.displayPreviewYZ
       @sceneController.setDisplaySV PLANE_XZ, @model.user.displayPreviewXZ


fixing minor error

fixing minor error

Former-commit-id: 24f9290cc93eb660741371ebd818c2de16d75d0a [formerly 35b95f5941da102e34a117eba5a0d76a5abf6baf] [formerly f35d2d242f68edcdbb628e56652e19e4af3c6f68 [formerly f35d2d242f68edcdbb628e56652e19e4af3c6f68 [formerly dd06a00af1089ab7222f11a3eede81579bce7a39]]]
Former-commit-id: 6f49e0f601b5bd9f207c96981b75a9855fa292bb [formerly 855293eca67f5466fd7e6811c435af12883ac884]
Former-commit-id: 898933560c3c347f8ae8a23e599e41a506c38074
Former-commit-id: 129f24a02eedba05676e0a515dacb14e6b0f8a65

--- app/assets/javascripts/views/resultsview.coffee
+++ app/assets/javascripts/views/resultsview.coffee
@@ -121,7 +121,7 @@
           '-webkit-transform': "scale(#{ratio},#{ratio}) translate(#{ 1/ratio * offsetX}px,#{ 1/ratio * offsetY}px)",
           'transform': "scale(#{ratio},#{ratio}) translate(#{ 1/ratio * offsetX}px,#{ 1/ratio * offsetY}px)"

-      _.delay , =>
+      _.delay =>
         $histogram.css { opacity: 1, display: '' }
         #window.delay 25, ->
         $participants.fadeOut()


Apparently we need to set widget parameter, to get nicely grouped relics

--- app/assets/javascripts/widgets/direction.coffee
+++ app/assets/javascripts/widgets/direction.coffee
@@ -204,6 +204,7 @@
   search_params = $('#new_search').serializeObject().search
   search_params.api_key = "oz"
   search_params.per_page = 100
+  search_params.widget = 1

   window.parent.postMessage(JSON.stringify(
     event: "on_params_changed", params: search_params


Convert visibility in the Mutating text section

--- src/editor.coffee
+++ src/editor.coffee
@@ -662,10 +662,10 @@
   Section: Mutating Text
   ###

-  # Public: Replaces the entire contents of the buffer with the given {String}.
+  # Essential: Replaces the entire contents of the buffer with the given {String}.
   setText: (text) -> @buffer.setText(text)

-  # Public: Set the text in the given {Range} in buffer coordinates.
+  # Essential: Set the text in the given {Range} in buffer coordinates.
   #
   # * `range` A {Range} or range-compatible {Array}.
   # * `text` A {String}
@@ -673,7 +673,7 @@
   # Returns the {Range} of the newly-inserted text.
   setTextInBufferRange: (range, text, normalizeLineEndings) -> @getBuffer().setTextInRange(range, text, normalizeLineEndings)

-  # Public: Mutate the text of all the selections in a single transaction.
+  # Extended: Mutate the text of all the selections in a single transaction.
   #
   # All the changes made inside the given {Function} can be reverted with a
   # single call to {::undo}.
@@ -853,7 +853,7 @@
         @addSelectionForBufferRange([[row, 0], [row, Infinity]])
       @addSelectionForBufferRange([[end.row, 0], [end.row, end.column]]) unless end.column is 0

-  # Public: For each selection, transpose the selected text.
+  # Extended: For each selection, transpose the selected text.
   #
   # If the selection is empty, the characters preceding and following the cursor
   # are swapped. Otherwise, the selected characters are reversed.
@@ -868,14 +868,14 @@
       else
         selection.insertText selection.getText().split('').reverse().join('')

-  # Public: Convert the selected text to upper case.
+  # Extended: Convert the selected text to upper case.
   #
   # For each selection, if the selection is empty, converts the containing word
   # to upper case. Otherwise convert the selected text to upper case.
   upperCase: ->
     @replaceSelectedText selectWordIfEmpty:true, (text) -> text.toUpperCase()

-  # Public: Convert the selected text to lower case.
+  # Extended: Convert the selected text to lower case.
   #
   # For each selection, if the selection is empty, converts the containing word
   # to upper case. Otherwise convert the selected text to upper case.


Add join/part convenience functions.

Add join/part convenience functions.

--- src/hubot/irc.coffee
+++ src/hubot/irc.coffee
@@ -15,8 +15,18 @@
     for str in strings
       @send user, "#{user.name}: #{str}"

+  join: (channel) ->
+    self = @
+    @bot.join channel, () ->
+      console.log('joined %s', channel)
+
+  part: (channel) ->
+    @bot.part channel, () ->
+      console.log('left %s', channel)
+
   run: ->
     self = @
+
     options =
       nick:     process.env.HUBOT_IRC_NICK
       port:     process.env.HUBOT_IRC_PORT
@@ -47,8 +57,7 @@
           bot.say 'NickServ', "identify #{options.nickpass}"
         else if options.nickpass and from is 'NickServ' and text.indexOf('now identified') isnt -1
           for room in options.rooms
-            bot.join room, ->
-              console.log('%s has joined %s', options.nick, room)
+            @join room

     bot.addListener 'message', (from, to, message) ->
       console.log "From #{from} to #{to}: #{message}"


account for line node changing (applying bullet)

--- src/editor.coffee
+++ src/editor.coffee
@@ -383,6 +383,8 @@
       endOffset = Tandem.Position.getIndex(nativeSel.focusNode, nativeSel.focusOffset, endLine)
       #[selStart, selEnd] = this.transformSelection(modificationStart, startIndex, endIndex, charAdditions)
       fn()
+      startLine = startLine.ownerDocument.getElementById(startLine.id) if startLine.parentNode == null
+      endLine = endLine.ownerDocument.getElementById(endLine.id) if endLine.parentNode == null
       startPos = new Tandem.Position(this, startLine, startOffset)
       endPos = new Tandem.Position(this, endLine, endOffset)
       savedSelectionRange = new Tandem.Range(this, startPos, endPos)


Update argument lists in editor.coffee

Update argument lists in editor.coffee

--- src/editor.coffee
+++ src/editor.coffee
@@ -294,7 +294,7 @@
   # Set the number of characters that can be displayed horizontally in the
   # editor.
   #
-  # editorWidthInChars - A {Number} representing the width of the {EditorView}
+  # * `editorWidthInChars` A {Number} representing the width of the {EditorView}
   # in characters.
   setEditorWidthInChars: (editorWidthInChars) ->
     @displayBuffer.setEditorWidthInChars(editorWidthInChars)
@@ -308,7 +308,7 @@

   # Public: Enable or disable soft tabs for this editor.
   #
-  # softTabs - A {Boolean}
+  # * `softTabs` A {Boolean}
   setSoftTabs: (@softTabs) -> @softTabs

   # Public: Toggle soft tabs for this editor
@@ -319,7 +319,7 @@

   # Public: Enable or disable soft wrap for this editor.
   #
-  # softWrap - A {Boolean}
+  # * `softWrap` A {Boolean}
   setSoftWrap: (softWrap) -> @displayBuffer.setSoftWrap(softWrap)

   # Public: Toggle soft wrap for this editor
@@ -361,12 +361,16 @@
   # unchanged. If the {Point} does not describe a valid position, the closest
   # valid position is returned instead.
   #
-  # For example:
-  #   * `[-1, -1]` is converted to `[0, 0]`.
-  #   * If the line at row 2 is 10 long, `[2, Infinity]` is converted to
-  #     `[2, 10]`.
-  #
-  # bufferPosition - The {Point} representing the position to clip.
+  # ## Examples
+  #
+  # ```coffee
+  # editor.clipBufferPosition([-1, -1]) # -> `[0, 0]`
+  #
+  # # When the line at buffer row 2 is 10 characters long
+  # editor.clipBufferPosition([2, Infinity]) # -> `[2, 10]`
+  # ```
+  #
+  # * `bufferPosition` The {Point} representing the position to clip.
   #
   # Returns a {Point}.
   clipBufferPosition: (bufferPosition) -> @buffer.clipPosition(bufferPosition)
@@ -374,7 +378,7 @@
   # Public: Clip the start and end of the given range to valid positions in the
   # buffer. See {::clipBufferPosition} for more information.
   #
-  # range - The {Range} to clip.
+  # * `range` The {Range} to clip.
   #
   # Returns a {Range}.
   clipBufferRange: (range) -> @buffer.clipRange(range)
@@ -386,7 +390,7 @@
   # the tab length is 2, a row with 4 leading spaces would have an indentation
   # level of 2.
   #
-  # bufferRow - A {Number} indicating the buffer row.
+  # * `bufferRow` A {Number} indicating the buffer row.
   #
   # Returns a {Number}.
   indentationForBufferRow: (bufferRow) ->
@@ -399,11 +403,11 @@
   # Note that if soft tabs are enabled and the tab length is 2, a row with 4
   # leading spaces would have an indentation level of 2.
   #
-  # bufferRow - A {Number} indicating the buffer row.
-  # newLevel - A {Number} indicating the new indentation level.
-  # options - An {Object} with the following keys:
-  #   :preserveLeadingWhitespace - true to preserve any whitespace already at
-  #                                the beginning of the line (default: false).
+  # * `bufferRow` A {Number} indicating the buffer row.
+  # * `newLevel` A {Number} indicating the new indentation level.
+  # * `options` An {Object} with the following keys:
+  #   * `preserveLeadingWhitespace` `true` to preserve any whitespace already at
+  #      the beginning of the line (default: false).
   setIndentationForBufferRow: (bufferRow, newLevel, {preserveLeadingWhitespace}={}) ->
     if preserveLeadingWhitespace
       endColumn = 0
@@ -419,7 +423,7 @@
   # the tab length is 2, a row with 4 leading spaces would have an indentation
   # level of 2.
   #
-  # line - A {String} representing a line of text.
+  # * `line` A {String} representing a line of text.
   #
   # Returns a {Number}.
   indentLevelForLine: (line) ->
@@ -442,7 +446,7 @@
   #
   # See {TextBuffer::saveAs} for more details.
   #
-  # filePath - A {String} path.
+  # * `filePath` A {String} path.
   saveAs: (filePath) -> @buffer.saveAs(filePath)

   # Copies the current file path to the native clipboard.
@@ -494,8 +498,8 @@

   # Returns the range for the given buffer row.
   #
-  # row - A row {Number}.
-  # options - An options hash with an `includeNewline` key.
+  # * `row` A row {Number}.
+  # * `options` An options hash with an `includeNewline` key.
   #
   # Returns a {Range}.
   bufferRangeForBufferRow: (row, {includeNewline}={}) -> @buffer.rangeForRow(row, includeNewline)
@@ -503,13 +507,13 @@
   # Public: Returns a {String} representing the contents of the line at the
   # given buffer row.
   #
-  # row - A {Number} representing a zero-indexed buffer row.
+  # * `row` A {Number} representing a zero-indexed buffer row.
   lineForBufferRow: (row) -> @buffer.lineForRow(row)

   # Public: Returns a {Number} representing the line length for the given
   # buffer row, exclusive of its line-ending character(s).
   #
-  # row - A {Number} indicating the buffer row.
+  # * `row` A {Number} indicating the buffer row.
   lineLengthForBufferRow: (row) -> @buffer.lineLengthForRow(row)

   # {Delegates to: TextBuffer.scan}
@@ -536,8 +540,8 @@
   # The position is also clipped via {::clipScreenPosition} following the
   # conversion, which only makes a difference when `options` are supplied.
   #
-  # bufferPosition - A {Point} or {Array} of [row, column].
-  # options - An options hash for {::clipScreenPosition}.
+  # * `bufferPosition` A {Point} or {Array} of [row, column].
+  # * `options` An options hash for {::clipScreenPosition}.
   #
   # Returns a {Point}.
   screenPositionForBufferPosition: (bufferPosition, options) -> @displayBuffer.screenPositionForBufferPosition(bufferPosition, options)
@@ -546,8 +550,8 @@
   #
   # The position is clipped via {::clipScreenPosition} prior to the conversion.
   #
-  # bufferPosition - A {Point} or {Array} of [row, column].
-  # options - An options hash for {::clipScreenPosition}.
+  # * `bufferPosition` A {Point} or {Array} of [row, column].
+  # * `options` An options hash for {::clipScreenPosition}.
   #
   # Returns a {Point}.
   bufferPositionForScreenPosition: (screenPosition, options) -> @displayBuffer.bufferPositionForScreenPosition(screenPosition, options)
@@ -569,12 +573,16 @@
   # unchanged. If the {Point} does not describe a valid position, the closest
   # valid position is returned instead.
   #
-  # For example:
-  #   * `[-1, -1]` is converted to `[0, 0]`.
-  #   * If the line at screen row 2 is 10 long, `[2, Infinity]` is converted to
-  #     `[2, 10]`.
-  #
-  # bufferPosition - The {Point} representing the position to clip.
+  # ## Examples
+  #
+  # ```coffee
+  # editor.clipScreenPosition([-1, -1]) # -> `[0, 0]`
+  #
+  # # When the line at screen row 2 is 10 characters long
+  # editor.clipScreenPosition([2, Infinity]) # -> `[2, 10]`
+  # ```
+  #
+  # * `bufferPosition` The {Point} representing the position to clip.
   #
   # Returns a {Point}.
   clipScreenPosition: (screenPosition, options) -> @displayBuffer.clipScreenPosition(screenPosition, options)
@@ -606,7 +614,7 @@
   # anonymous CoffeeScript function, the method returns the following array:
   # `["source.coffee", "meta.inline.function.coffee", "variable.parameter.function.coffee"]`
   #
-  # bufferPosition - A {Point} or {Array} of [row, column].
+  # * `bufferPosition` A {Point} or {Array} of [row, column].
   #
   # Returns an {Array} of {String}s.
   scopesForBufferPosition: (bufferPosition) -> @displayBuffer.scopesForBufferPosition(bufferPosition)
@@ -635,13 +643,18 @@

   # Public: For each selection, replace the selected text with the given text.
   #
-  # Emits: `will-insert-text -> ({text, cancel})` before the text has
-  # been inserted. Calling `cancel` will prevent the text from being
-  # inserted.
-  # Emits: `did-insert-text -> ({text})` after the text has been inserted.
-  #
-  # text - A {String} representing the text to insert.
-  # options - See {Selection::insertText}.
+  # ## Events
+  #
+  #  * `will-insert-text` Emit before the text has been inserted.
+  #    * `event` event {Object}
+  #      * `text` {String} text to be inserted
+  #      * `cancel` {Function} Call to prevent the text from being inserted
+  #  * `did-insert-text` Emit after the text has been inserted.
+  #    * `event` event {Object}
+  #      * `text` {String} text to be inserted
+  #
+  # * `text` A {String} representing the text to insert.
+  # * `options` See {Selection::insertText}.
   #
   # Returns a {Range} when the text has been inserted
   # Returns a {Bool} false when the text has not been inserted
@@ -800,7 +813,7 @@
   # editor, each selection will be replaced with the content of the
   # corresponding clipboard selection text.
   #
-  # options - See {Selection::insertText}.
+  # * `options` See {Selection::insertText}.
   pasteText: (options={}) ->
     {text, metadata} = atom.clipboard.readWithMetadata()

@@ -857,7 +870,7 @@

   # Public: Fold all foldable lines at the given indent level.
   #
-  # level - A {Number}.
+  # * `level` A {Number}.
   foldAllAtIndentLevel: (level) ->
     @languageMode.foldAllAtIndentLevel(level)

@@ -867,13 +880,13 @@
   # If the given row is foldable, the fold will begin there. Otherwise, it will
   # begin at the first foldable row preceding the given row.
   #
-  # bufferRow - A {Number}.
+  # * `bufferRow` A {Number}.
   foldBufferRow: (bufferRow) ->
     @languageMode.foldBufferRow(bufferRow)

   # Public: Unfold all folds containing the given row in buffer coordinates.
   #
-  # bufferRow - A {Number}
+  # * `bufferRow` A {Number}
   unfoldBufferRow: (bufferRow) ->
     @displayBuffer.unfoldBufferRow(bufferRow)

@@ -881,7 +894,7 @@
   #
   # A *foldable* row is a row that *starts* a row range that can be folded.
   #
-  # bufferRow - A {Number}
+  # * `bufferRow` A {Number}
   #
   # Returns a {Boolean}.
   isFoldableAtBufferRow: (bufferRow) ->
@@ -920,7 +933,7 @@

   # Public: Determine whether the given row in buffer coordinates is folded.
   #
-  # bufferRow - A {Number}
+  # * `bufferRow` A {Number}
   #
   # Returns a {Boolean}.
   isFoldedAtBufferRow: (bufferRow) ->
@@ -928,7 +941,7 @@

   # Public: Determine whether the given row in screen coordinates is folded.
   #
-  # screenRow - A {Number}
+  # * `screenRow` A {Number}
   #
   # Returns a {Boolean}.
   isFoldedAtScreenRow: (screenRow) ->
@@ -1091,7 +1104,7 @@
   # All the changes made inside the given {Function} can be reverted with a
   # single call to {::undo}.
   #
-  # fn - A {Function} that will be called once for each {Selection}. The first
+  # * `fn` A {Function} that will be called once for each {Selection}. The first
   #      argument will be a {Selection} and the second argument will be the
   #      {Number} index of that selection.
   mutateSelectedText: (fn) ->
@@ -1110,8 +1123,8 @@

   # Public: Get all the decorations within a screen row range.
   #
-  # startScreenRow - the {Number} beginning screen row
-  # endScreenRow - the {Number} end screen row (inclusive)
+  # * `startScreenRow` the {Number} beginning screen row
+  # * `endScreenRow` the {Number} end screen row (inclusive)
   #
   # Returns an {Object} of decorations in the form
   #  `{1: [{id: 10, type: 'gutter', class: 'someclass'}], 2: ...}`
@@ -1141,20 +1154,20 @@
   #     </div>
   #     ```
   #
-  # marker - A {Marker} you want this decoration to follow.
-  # decorationParams - An {Object} representing the decoration eg. `{type: 'gutter', class: 'linter-error'}`
-  #   :type - There are a few supported decoration types:
+  # * `marker` A {Marker} you want this decoration to follow.
+  # * `decorationParams` An {Object} representing the decoration eg. `{type: 'gutter', class: 'linter-error'}`
+  #   * `type` There are a few supported decoration types:
   #     * `gutter`: Applies the decoration to the line numbers spanned by the marker.
   #     * `line`: Applies the decoration to the lines spanned by the marker.
   #     * `highlight`: Applies the decoration to a "highlight" behind the marked range.
-  #   :class - This CSS class will be applied to the decorated line number,
+  #   * `class` This CSS class will be applied to the decorated line number,
   #     line, or highlight.
-  #   :onlyHead - If `true`, the decoration will only be applied to the head
+  #   * `onlyHead` If `true`, the decoration will only be applied to the head
   #     of the marker. Only applicable to the `line` and `gutter` types.
-  #   :onlyEmpty - If `true`, the decoration will only be applied if the
+  #   * `onlyEmpty` If `true`, the decoration will only be applied if the
   #     associated marker is empty. Only applicable to the `line` and
   #     `gutter` types.
-  #   :onlyNonEmpty - If `true`, the decoration will only be applied if the
+  #   * `onlyNonEmpty` If `true`, the decoration will only be applied if the
   #     associated marker is non-empty.  Only applicable to the `line` and
   #     gutter types.
   #
@@ -1180,25 +1193,25 @@
   # In addition, there are several special properties that will be compared
   # with the range of the markers rather than their properties.
   #
-  # properties - An {Object} containing properties that each returned marker
+  # * `properties` An {Object} containing properties that each returned marker
   #   must satisfy. Markers can be associated with custom properties, which are
   #   compared with basic equality. In addition, several reserved properties
   #   can be used to filter markers based on their current range:
-  #     :startBufferRow - Only include markers starting at this row in buffer
+  #   * `startBufferRow` Only include markers starting at this row in buffer
   #       coordinates.
-  #     :endBufferRow - Only include markers ending at this row in buffer
+  #   * `endBufferRow` Only include markers ending at this row in buffer
   #       coordinates.
-  #     :containsBufferRange - Only include markers containing this {Range} or
+  #   * `containsBufferRange` Only include markers containing this {Range} or
   #       in range-compatible {Array} in buffer coordinates.
-  #     :containsBufferPosition - Only include markers containing this {Point}
+  #   * `containsBufferPosition` Only include markers containing this {Point}
   #       or {Array} of `[row, column]` in buffer coordinates.
   findMarkers: (properties) ->
     @displayBuffer.findMarkers(properties)

   # Public: Mark the given range in screen coordinates.
   #
-  # range - A {Range} or range-compatible {Array}.
-  # options - See {TextBuffer::markRange}.
+  # * `range` A {Range} or range-compatible {Array}.
+  # * `options` See {TextBuffer::markRange}.
   #
   # Returns a {DisplayBufferMarker}.
   markScreenRange: (args...) ->
@@ -1206,8 +1219,8 @@

   # Public: Mark the given range in buffer coordinates.
   #
-  # range - A {Range} or range-compatible {Array}.
-  # options - See {TextBuffer::markRange}.
+  # * `range` A {Range} or range-compatible {Array}.
+  # * `options` See {TextBuffer::markRange}.
   #
   # Returns a {DisplayBufferMarker}.
   markBufferRange: (args...) ->
@@ -1215,8 +1228,8 @@

   # Public: Mark the given position in screen coordinates.
   #
-  # position - A {Point} or {Array} of `[row, column]`.
-  # options - See {TextBuffer::markRange}.
+  # * `position` A {Point} or {Array} of `[row, column]`.
+  # * `options` See {TextBuffer::markRange}.
   #
   # Returns a {DisplayBufferMarker}.
   markScreenPosition: (args...) ->
@@ -1224,8 +1237,8 @@

   # Public: Mark the given position in buffer coordinates.
   #
-  # position - A {Point} or {Array} of `[row, column]`.
-  # options - See {TextBuffer::markRange}.
+  # * `position` A {Point} or {Array} of `[row, column]`.
+  # * `options` See {TextBuffer::markRange}.
   #
   # Returns a {DisplayBufferMarker}.
   markBufferPosition: (args...) ->
@@ -1282,8 +1295,8 @@

   # Add a {Selection} based on the given {DisplayBufferMarker}.
   #
-  # marker  - The {DisplayBufferMarker} to highlight
-  # options - An {Object} that pertains to the {Selection} constructor.
+  # * `marker` The {DisplayBufferMarker} to highlight
+  # * `options` An {Object} that pertains to the {Selection} constructor.
   #
   # Returns the new {Selection}.
   addSelection: (marker, options={}) ->
@@ -1304,9 +1317,9 @@

   # Public: Add a selection for the given range in buffer coordinates.
   #
-  # bufferRange - A {Range}
-  # options - An options {Object}:
-  #   :reversed - A {Boolean} indicating whether to create the selection in a
+  # * `bufferRange` A {Range}
+  # * `options` An options {Object}:
+  #   * `reversed` A {Boolean} indicating whether to create the selection in a
   #     reversed orientation.
   #
   # Returns the added {Selection}.
@@ -1319,9 +1332,9 @@
   # Public: Set the selected range in buffer coordinates. If there are multiple
   # selections, they are reduced to a single selection with the given range.
   #
-  # bufferRange - A {Range} or range-compatible {Array}.
-  # options - An options {Object}:
-  #   :reversed - A {Boolean} indicating whether to create the selection in a
+  # * `bufferRange` A {Range} or range-compatible {Array}.
+  # * `options` An options {Object}:
+  #   * `reversed` A {Boolean} indicating whether to create the selection in a
   #     reversed orientation.
   setSelectedBufferRange: (bufferRange, options) ->
     @setSelectedBufferRanges([bufferRange], options)
@@ -1329,9 +1342,9 @@
   # Public: Set the selected range in screen coordinates. If there are multiple
   # selections, they are reduced to a single selection with the given range.
   #
-  # screenRange - A {Range} or range-compatible {Array}.
-  # options - An options {Object}:
-  #   :reversed - A {Boolean} indicating whether to create the selection in a
+  # * `screenRange` A {Range} or range-compatible {Array}.
+  # * `options` An options {Object}:
+  #   * `reversed` A {Boolean} indicating whether to create the selection in a
   #     reversed orientation.
   setSelectedScreenRange: (screenRange, options) ->
     @setSelectedBufferRange(@bufferRangeForScreenRange(screenRange, options), options)
@@ -1339,9 +1352,9 @@
   # Public: Set the selected ranges in buffer coordinates. If there are multiple
   # selections, they are replaced by new selections with the given ranges.
   #
-  # bufferRanges - An {Array} of {Range}s or range-compatible {Array}s.
-  # options - An options {Object}:
-  #   :reversed - A {Boolean} indicating whether to create the selection in a
+  # * `bufferRanges` An {Array} of {Range}s or range-compatible {Array}s.
+  # * `options` An options {Object}:
+  #   * `reversed` A {Boolean} indicating whether to create the selection in a
   #     reversed orientation.
   setSelectedBufferRanges: (bufferRanges, options={}) ->
     throw new Error("Passed an empty array to setSelectedBufferRanges") unless bufferRanges.length
@@ -1391,7 +1404,7 @@
   # Public: Get the most recent {Selection} or the selection at the given
   # index.
   #
-  # index - Optional. The index of the selection to return, based on the order
+  # * `index` Optional. The index of the selection to return, based on the order
   #   in which the selections were added.
   #
   # Returns a {Selection}.
@@ -1422,7 +1435,7 @@
   # Public: Determine if a given range in buffer coordinates intersects a
   # selection.
   #
-  # bufferRange - A {Range} or range-compatible {Array}.
+  # * `bufferRange` A {Range} or range-compatible {Array}.
   #
   # Returns a {Boolean}.
   selectionIntersectsBufferRange: (bufferRange) ->
@@ -1433,9 +1446,9 @@
   #
   # If there are multiple cursors, they will be consolidated to a single cursor.
   #
-  # position - A {Point} or {Array} of `[row, column]`
-  # options  - An {Object} combining options for {::clipScreenPosition} with:
-  #   :autoscroll - Determines whether the editor scrolls to the new cursor's
+  # * `position` A {Point} or {Array} of `[row, column]`
+  # * `options` An {Object} combining options for {::clipScreenPosition} with:
+  #   * `autoscroll` Determines whether the editor scrolls to the new cursor's
   #     position. Defaults to true.
   setCursorScreenPosition: (position, options) ->
     @moveCursors (cursor) -> cursor.setScreenPosition(position, options)
@@ -1457,9 +1470,9 @@
   #
   # If there are multiple cursors, they will be consolidated to a single cursor.
   #
-  # position - A {Point} or {Array} of `[row, column]`
-  # options  - An {Object} combining options for {::clipScreenPosition} with:
-  #   :autoscroll - Determines whether the editor scrolls to the new cursor's
+  # * `position` A {Point} or {Array} of `[row, column]`
+  # * `options` An {Object} combining options for {::clipScreenPosition} with:
+  #   * `autoscroll` Determines whether the editor scrolls to the new cursor's
   #     position. Defaults to true.
   setCursorBufferPosition: (position, options) ->
     @moveCursors (cursor) -> cursor.setBufferPosition(position, options)
@@ -1509,7 +1522,7 @@

   # Public: Get the text in the given {Range} in buffer coordinates.
   #
-  # range - A {Range} or range-compatible {Array}.
+  # * `range` A {Range} or range-compatible {Array}.
   #
   # Returns a {String}.
   getTextInBufferRange: (range) ->
@@ -1517,8 +1530,8 @@

   # Public: Set the text in the given {Range} in buffer coordinates.
   #
-  # range - A {Range} or range-compatible {Array}.
-  # text - A {String}
+  # * `range` A {Range} or range-compatible {Array}.
+  # * `text` A {String}
   #
   # Returns the {Range} of the newly-inserted text.
   setTextInBufferRange: (range, text, normalizeLineEndings) -> @getBuffer().setTextInRange(range, text, normalizeLineEndings)
@@ -1532,7 +1545,7 @@

   # Public: Returns the word surrounding the most recently added cursor.
   #
-  # options - See {Cursor::getBeginningOfCurrentWordBufferPosition}.
+  # * `options` See {Cursor::getBeginningOfCurrentWordBufferPosition}.
   getWordUnderCursor: (options) ->
     @getTextInBufferRange(@getCursor().getCurrentWordBufferRange(options))

@@ -1615,9 +1628,8 @@
   # Public: Scroll the editor to reveal the most recently added cursor if it is
   # off-screen.
   #
-  # options - An optional hash of options.
-  #   :center - Center the editor around the cursor if possible. Defauls to
-  #             true.
+  # * `options` An optional hash of options.
+  #   * `center` Center the editor around the cursor if possible. Defauls to true.
   scrollToCursorPosition: (options) ->
     @getCursor().autoscroll(center: options?.center ? true)

@@ -1657,7 +1669,7 @@
   #
   # This method may merge selections that end up intesecting.
   #
-  # position - An instance of {Point}, with a given `row` and `column`.
+  # * `position` An instance of {Point}, with a given `row` and `column`.
   selectToScreenPosition: (position) ->
     lastSelection = @getLastSelection()
     lastSelection.selectToScreenPosition(position)
@@ -1875,7 +1887,7 @@

   # Public: Select the range of the given marker if it is valid.
   #
-  # marker - A {DisplayBufferMarker}
+  # * `marker` A {DisplayBufferMarker}
   #
   # Returns the selected {Range} or `undefined` if the marker is invalid.
   selectMarker: (marker) ->
@@ -1974,7 +1986,7 @@
   # abort the transaction, call {::abortTransaction} to terminate the function's
   # execution and revert any changes performed up to the abortion.
   #
-  # fn - A {Function} to call inside the transaction.
+  # * `fn` A {Function} to call inside the transaction.
   transact: (fn) -> @buffer.transact(fn)

   # Public: Start an open-ended transaction.


Clean up Editor class overview

Clean up Editor class overview

--- src/editor.coffee
+++ src/editor.coffee
@@ -10,20 +10,19 @@
 Selection = require './selection'
 TextMateScopeSelector = require('first-mate').ScopeSelector

-# Public: The core model of Atom.
+# Public: Represents all essential editing state for a single {TextBuffer},
+# including cursor and selection positions, folds, and soft wraps. If you're
+# manipulating the state of an {Editor}, use this class. If you're interested in
+# the visual appearance of editors, use {EditorView} instead.
 #
-# An {Editor} represents a unique view of each document, with its own
-# {Cursor}s and scroll position.
+# A single {TextBuffer} can belong to multiple {Editor}s. For example, if the
+# same file is open in two different panes, Atom creates a separate {Editor} for
+# each pane. If the buffer is manipulated the changes are reflected in both
+# editors, but each maintains its own cursor position, folded lines, etc.
 #
-# For instance if a user creates a split, Atom creates a second {Editor}
-# but both {Editor}s interact with the same buffer underlying buffer. So
-# if you type in either buffer it immediately appears in both but if you scroll
-# in one it doesn't scroll the other.
-#
-# Almost all packages will interact primiarily with this class as it provides
-# access to objects you'll most commonly interact with. To access it you'll
-# want to register a callback on {WorkspaceView} which will be fired once for every
-# existing {Editor} as well as any future {Editor}s.
+# The easiest way to gain access to {Editor} objects is by registering a
+# callback on the `atom.workspace` global to be called with all current and
+# future {Editor}s:
 #
 # ## Example
 # ```coffeescript


:memo: Bool -> Boolean

:memo: Bool -> Boolean

--- src/editor.coffee
+++ src/editor.coffee
@@ -644,7 +644,7 @@
   # text - A {String} representing the text to insert.
   # options - See {Selection::insertText}.
   #
-  # Returns a {Bool} indicating whether or not the text was inserted.
+  # Returns a {Boolean} indicating whether or not the text was inserted.
   insertText: (text, options={}) ->
     willInsert = true
     cancel = -> willInsert = false


remove parens

remove parens

--- src/esnext.coffee
+++ src/esnext.coffee
@@ -142,7 +142,7 @@

   module._compile(js, filePath)

-register = () ->
+register = ->
   require.extensions['.js'] = loadFile

 module.exports =


Downgrade to npm v1.2.18

Downgrade to npm v1.2.18

npm 1.2.19 appears to be 6 times slower for doing local
installs.

https://github.com/isaacs/npm/issues/3422

--- src/installer.coffee
+++ src/installer.coffee
@@ -32,7 +32,7 @@
     console.log 'Installing npm locally...'

     mkdir(@atomModulesDirectory)
-    @spawn 'npm', ['install', 'npm', '--silent'], {cwd: @atomDirectory}, (code) ->
+    @spawn 'npm', ['install', 'npm@v1.2.18', '--silent'], {cwd: @atomDirectory}, (code) ->
       if code is 0
         callback()
       else


Fix #1068: When change the project name reload nav menu

--- app/coffee/modules/admin/project-profile.coffee
+++ app/coffee/modules/admin/project-profile.coffee
@@ -63,10 +63,12 @@
                 @location.replace()
             return @q.reject(xhr)

+        @scope.$on "project:loaded", =>
+            @appTitle.set("Project profile - " + @scope.sectionName + " - " + @scope.project.name)
+
     loadProject: ->
         return @rs.projects.get(@scope.projectId).then (project) =>
             @scope.project = project
-            @scope.$emit('project:loaded', project)
             @scope.pointsList = _.sortBy(project.points, "order")
             @scope.usStatusList = _.sortBy(project.us_statuses, "order")
             @scope.taskStatusList = _.sortBy(project.task_statuses, "order")
@@ -105,7 +107,7 @@
             promise.then ->
                 $loading.finish(target)
                 $confirm.notify("success")
-                $scope.$emit("project:loaded", $scope.project)
+                $rootscope.$broadcast("project:loaded", $scope.project)

             promise.then null, (data) ->
                 $loading.finish(target)


Make requests and expertises show up in admin rooms

--- packages/rocketchat-ui-admin/client/rooms/adminRooms.coffee
+++ packages/rocketchat-ui-admin/client/rooms/adminRooms.coffee
@@ -12,7 +12,7 @@
 	roomCount: ->
 		return Template.instance().rooms?().count()
 	name: ->
-		if @t is 'c' or @t is 'p'
+		if @t is 'c' or @t is 'p' or @t is 'r' or @t is 'e'
 			return @name
 		else if @t is 'd'
 			return @usernames.join ' x '
@@ -23,6 +23,10 @@
 			return TAPi18n.__ 'Direct Message'
 		if @t is 'p'
 			return TAPi18n.__ 'Private Group'
+		if @t is 'r'
+			return TAPi18n.__ 'Request'
+		if @t is 'e'
+			return TAPi18n.__ 'Expertise'
 	default: ->
 		if this.default
 			return t('True')
@@ -65,7 +69,7 @@
 		types = instance.types.get()

 		if types.length is 0
-			types = ['c', 'd', 'p']
+			types = ['c', 'd', 'p', 'r', 'e']

 		limit = instance.limit.get()
 		subscription = instance.subscribe 'adminRooms', filter, types, limit


NEW: animator event props: target & animator

--- source/Art/Engine/Animation/PersistantAnimator.coffee
+++ source/Art/Engine/Animation/PersistantAnimator.coffee
@@ -1,8 +1,7 @@
-Foundation = require 'art-foundation'
 Events = require 'art-events'

 {
-  log, BaseObject
+  log
   isFunction, isString
   capitalize
   inspectedObjectLiteral
@@ -10,7 +9,10 @@
   isPlainObject
   eq
   rubyOr
-} = Foundation
+  isNumber
+  rubyTrue
+} = require 'art-standard-lib'
+{BaseObject} = require 'art-class-system'
 {EventedMixin} = Events

 ###
@@ -278,14 +280,22 @@
 module.exports = class PersistantAnimator extends EventedMixin BaseObject

   @interpolate: interpolate = (startValue, toValue, pos) ->
-    if isFunction startValue.interpolate
+    if pos == 0
+      startValue
+    else if pos == 1
+      toValue
+    else unless rubyTrue(startValue) && rubyTrue(toValue)
+      startValue || toValue
+    else if isFunction startValue.interpolate
       startValue.interpolate toValue, pos
     else if isPlainObject startValue
       out = {}
       out[k] = interpolate v, toValue[k], pos for k, v of startValue
       out
+    else if isNumber startValue
+      startValue + (toValue - startValue) * pos
     else
-      startValue + (toValue - startValue) * pos
+      toValue

   @getter "options prop element startValue currentValue toValue continuous voidValue currentSecond startSecond"
   @getter
@@ -406,7 +416,7 @@
     throw new Error if @_active
     @_lastSecond = @_startSecond = @_activatedAtSecond = @_currentSecond # - @frameSeconds
     @_startValue = @_currentValue
-    @queueEvent "start"
+    @queueEvent "start", target: @_element, animator: @
     @_active = true

   _toValueChanged: ->
@@ -414,7 +424,7 @@
     @_startValue = @_currentValue

   _deactivate: ->
-    @queueEvent "done"
+    @queueEvent "done", target: @_element, animator: @
     @_active = false

   animateAbsoluteTime: (@_element, @_currentValue, toValue, @_currentSecond) ->
@@ -435,7 +445,8 @@
     newValue = @animate()

     if @_active
-      @queueEvent "update" if animationSeconds > 0
+      if animationSeconds > 0
+        @queueEvent "update", target: @_element, animator: @
       @_element.onNextEpoch =>
         @_element[@_prop] = @_toValue
     else


Clickable status update

Clickable status update

--- public/assets/coffee/form.coffee
+++ public/assets/coffee/form.coffee
@@ -6,3 +6,15 @@
   $('#btn-cancel').click (e) ->
     $('#form-parcel').addClass('hide')
     $('#btn-toggle-parcel').show()
+
+  $('a.status').click (e) ->
+    e.preventDefault()
+    status = $(@).children('span').data('status')
+    $.ajax "#{location.href}",
+      type: 'PUT'
+      dataType: 'json'
+      data: { status: status }
+      success: (data, textStatus, jqXHR) ->
+        location.reload()
+      error: (jqXHR, textStatus, errorThrown) ->
+      complete: (jqXHR, textStatus) ->