feat(aix): change snippet (#165)

feat(aix): change snippet (#165)

--- snippets/language-coursescript.cson
+++ snippets/language-coursescript.cson
@@ -1312,27 +1312,18 @@
     'body':"""
       [TYPE AIXPresentationTeaching]
       Video(stream=true): $1
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXPresentationAward':
     'prefix': 'aixpa'
     'body': """
       [TYPE AIXPresentationAward]
       Video(stream=true): $1
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXPresentationExchange':
     'prefix': 'aixpe'
     'body': """
       [TYPE AIXPresentationExchange]
       Video(stream=true): $1
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXAudio2Audio':
     'prefix': 'aixa2a'
@@ -1343,12 +1334,8 @@
       Video(stream=true): $3
       Video(stream=true): $4
       Video(stream=true): $5
-      Audio(video_point=true): $6
-      QuestionPart:
-        Scorer: $7
-      \"""
-      display_layout: REGULAR
-      \"""
+      QuestionPart:
+        Audio: $6
     """
   'AIXAudio2AudioFree':
     'prefix': 'aixa2afree'
@@ -1361,9 +1348,6 @@
       Text(stream=true): $5
       QuestionPart:
         Scorer: $6
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXA2PPuzzle':
     'prefix': 'aixa2ppuzzle'
@@ -1390,9 +1374,6 @@
           coordinate: x=$18,y=$19
       TR_Pic: $20
       coordinate: x=$21,y=$22
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXA2PTool':
     'prefix': 'aixa2ptool'
@@ -1418,9 +1399,6 @@
           Pic: $16
       TR_Pic: $17
       coordinate: x=18,y=19
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXA2PDrag2':
     'prefix': 'aixa2pdrag2'
@@ -1453,9 +1431,6 @@
           coordinate: x=$22,y=$23
       TR_Pic: $24
       coordinate: x=$25,y=$26
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXA2PTap1':
     'prefix': 'aixa2ptap1'
@@ -1480,9 +1455,6 @@
           coordinate: x=$14,y=$15
       TR_Pic: $16
       coordinate: x=$17,y=$18
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXPA2ABuild1':
     'prefix': 'aixpa2abuild1'
@@ -1497,7 +1469,7 @@
       Pic(sr_start=true): $7
       Pic(sr_end=true): $8
       QuestionPart:
-        Scorer: $9
+        Audio: $9
         Audio(sound_effect=true): $10
         Animation:
         Pic: $11
@@ -1506,9 +1478,6 @@
         coordinate: x=$15,y=$16
       TR_Pic: $17
       coordinate: x=$18,y=$19
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXA2PDrag1':
     'prefix': 'aixa2pdrag1'
@@ -1519,24 +1488,16 @@
       Video(stream=true): $3
       Video(stream=true): $4
       Video(stream=true): $5
-      Pic(background=true): $6
-      Pic(sr_start=true): $7
-      Pic(sr_end=true): $8
       QuestionPart:
         Opts:
         Mix:
-          Pic(checked=true): $9
+          Pic(checked=true): $6
+          Pic: $7
+          Audio(sound_effect=true): $8
+        Mix:
+          Pic: $9
           Pic: $10
           Audio(sound_effect=true): $11
-        Mix:
-          Pic: $12
-          Pic: $13
-          Audio(sound_effect=true): $14
-      TR_Pic: $15
-      coordinate: x=$16,y=$17
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXPA2AFree':
     'prefix': 'aixpa2afree'
@@ -1562,9 +1523,6 @@
           coordinate: x=$15,y=$16
       TR_Pic: $17
       coordinate: x=$18,y=$19
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXPA2ATrigger':
     'prefix': 'aixpa2atrigger'
@@ -1579,7 +1537,7 @@
       Pic(sr_start=true): $7
       Pic(sr_end=true): $8
       QuestionPart:
-        Scorer: $9
+        Audio: $9
         Video: $10
         Animation:
         Pic: $11
@@ -1588,9 +1546,6 @@
         coordinate: x=$15,y=$16
       TR_Pic: $17
       coordinate: x=$18,y=$19
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'LingokidsKaraokeReader':
     'prefix': 'lingokidsk'
@@ -1627,18 +1582,10 @@
       Video(stream=true): $3
       Video(stream=true): $4
       Video(stream=true): $5
-      Pic(background=true): $6
-      Pic(sr_start=true): $7
-      Pic(sr_end=true): $8
-      QuestionPart:
-        Pic: $9
-        Text: $10
-        Audio: $11
-      TR_Pic: $12
-      coordinate: x=$13,y=$14
-      \"""
-      display_layout: REGULAR
-      \"""
+      QuestionPart:
+        Pic: $6
+        Text: $7
+        Audio: $8
     """
   'AIXPA2AJet2':
     'prefix': 'aixpa2ajet2'
@@ -1649,18 +1596,10 @@
       Video(stream=true): $3
       Video(stream=true): $4
       Video(stream=true): $5
-      Pic(background=true): $6
-      Pic(sr_start=true): $7
-      Pic(sr_end=true): $8
-      QuestionPart:
-        Pic: $9
-        Text: $10
-        Audio: $11
-      TR_Pic: $12
-      coordinate: x=$13,y=$14
-      \"""
-      display_layout: REGULAR
-      \"""
+      QuestionPart:
+        Pic: $6
+        Text: $7
+        Audio: $8
     """
   'AIXA2PFall':
     'prefix': 'aixa2pfall'
@@ -1672,23 +1611,16 @@
       Video(stream=true): $4
       Video(stream=true): $5
       Pic(background=true): $6
-      Pic(sr_start=true): $7
-      Pic(sr_end=true): $8
-      QuestionPart:
-        Text: $9
-        Pic: $10
+      QuestionPart:
+        Text: $7
+        Pic: $8
         Opts:
         Mix:
-          Pic(check=true): $11
+          Pic(check=true): $9
+          Audio(sound_effect=true): $10
+        Mix:
+          Pic: $11
           Audio(sound_effect=true): $12
-        Mix:
-          Pic: $13
-          Audio(sound_effect=true): $14
-      TR_Pic: $15
-      coordinate: x=$16,y=$17
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXA2PDrag3':
     'prefix': 'aixa2pdrag3'
@@ -1728,9 +1660,6 @@
           coordinate: x=$29,y=$30
       TR_Pic: $31
       coordinate: x=$32,y=$33
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXA2PTap2':
     'prefix': 'aixa2ptap2'
@@ -1762,9 +1691,6 @@
           coordinate: x=$21,y=$22
       TR_Pic: $23
       coordinate: x=$24,y=$25
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXPA2ABuild2':
     'prefix': 'aixpa2abuild2'
@@ -1779,7 +1705,7 @@
       Pic(sr_start=true): $7
       Pic(sr_end=true): $8
       QuestionPart:
-        Scorer: $9
+        Audio: $9
         Audio(sound_effect=true): $10
         Animation:
         Pic: $11
@@ -1788,9 +1714,6 @@
         coordinate: x=$15,y=$16
       TR_Pic: $17
       coordinate: x=$18,y=$19
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'VocabBank':
     'prefix': "VocabBank"
@@ -1878,9 +1801,6 @@
           coordinate: x=$11,y=$12
           Pic(sr_start=true): $13
           Pic(sr_end=true): $14
-      \"""
-      display_layout: REGULAR
-      \"""
     """
   'AIXA2PMole':
     'prefix': 'aixa2pmole'
@@ -1891,33 +1811,29 @@
       Video(stream=true): $3
       Video(stream=true): $4
       Video(stream=true): $5
-      Pic(background=true): $6
-      QuestionPart:
-        Audio: $7
+      QuestionPart:
+        Audio: $6
         Opts:
         Mix:
-          Audio(sound_effect=true): $8
+          Audio(sound_effect=true): $7
           Animation:
-          Pic(checked=true): $9
-          Pic: $10
-        Mix:
-          Audio(sound_effect=true): $11
+          Pic(checked=true): $8
+          Pic: $9
+        Mix:
+          Audio(sound_effect=true): $10
           Animation:
-          Pic(checked=true): $12
-          Pic: $13
-        Mix:
-          Audio(sound_effect=true): $14
+          Pic(checked=true): $11
+          Pic: $12
+        Mix:
+          Audio(sound_effect=true): $13
           Animation:
-          Pic(checked=true): $15
-          Pic: $16
-        Mix:
-          Audio(sound_effect=true): $17
+          Pic: $14
+          Pic: $15
+        Mix:
+          Audio(sound_effect=true): $16
           Animation:
-          Pic(checked=true): $18
-          Pic: $19
-      \"""
-      display_layout: REGULAR
-      \"""
+          Pic: $17
+          Pic: $18
     """
   'AIXT2PMole':
     'prefix': 'aixt2pmole'
@@ -1928,31 +1844,128 @@
       Video(stream=true): $3
       Video(stream=true): $4
       Video(stream=true): $5
+      QuestionPart:
+        Text: $6
+        Opts:
+        Mix:
+          Audio(sound_effect=true): $7
+          Animation:
+          Pic(checked=true): $8
+          Pic: $9
+        Mix:
+          Audio(sound_effect=true): $10
+          Animation:
+          Pic(checked=true): $11
+          Pic: $12
+        Mix:
+          Audio: $13
+          Animation:
+          Pic(checked=true): $14
+          Pic: $15
+        Mix:
+          Audio(sound_effect=true): $16
+          Animation:
+          Pic: $17
+          Pic: $18
+    """
+  'AIXPA2ARP1':
+    'prefix': 'aixpa2arp1'
+    'body':"""
+      [TYPE AIXPA2ARP1]
+      Video(stream=true): $1
+      Video(stream=true): $2
+      Video(stream=true): $3
+      Video(stream=true): $4
+      Video(stream=true): $5
       Pic(background=true): $6
       QuestionPart:
-        Text: $7
-        Opts:
-        Mix:
-          Audio(sound_effect=true): $8
-          Animation:
-          Pic(checked=true): $9
-          Pic: $10
-        Mix:
-          Audio(sound_effect=true): $11
-          Animation:
-          Pic(checked=true): $12
+        Pic: $7
+        coordinate: x=$8,y=$9
+        Pic(practice_role=true): $10
+        coordinate: x=$11,y=$12
+        Pic(topic=true): $13
+        coordinate: x=$14,y=$15
+        Pic(topic=true): $16
+        coordinate: x=$17,y=$18
+        Audio: $19
+        Audio(practice_role=true): $20
+        Audio(chunk=true): $21
+        Audio(chunk=true): $22
+        Audio: $23
+    """
+  'AIXPA2ARP2':
+    'prefix': 'aixpa2arp2'
+    'body':"""
+      [TYPE AIXPA2ARP2]
+      Video(stream=true): $1
+      Video(stream=true): $2
+      Video(stream=true): $3
+      Video(stream=true): $4
+      Video(stream=true): $5
+      Pic(background=true): $6
+      QuestionPart:
+        Pic: $7
+        coordinate: x=$8,y=$9
+        Pic(practice_role=true): $10
+        coordinate: x=$11,y=$12
+        Pic(topic=true): $13
+        coordinate: x=$14,y=$15
+        Pic(topic=true): $16
+        coordinate: x=$17,y=$18
+        Audio: $19
+        Audio(practice_role=true): $20
+        Audio: $23
+    """
+  'AIXA2PFree':
+    'prefix':'aixa2pfree'
+    'body':"""
+      [TYPE AIXA2cPFree]
+      Video(stream=true): $1
+      Video(stream=true): $2
+      Video(stream=true): $3
+      Video(stream=true): $4
+      Text(stream=true): $5
+      Video(stream=true): $6
+      Text(stream=true): $7
+      Video(stream=true): $8
+      Text(stream=true): $9
+      Pic(background=true): $10
+      QuestionPart:
+      Opts:
+      Mix:
+        Text: $11
+        Audio(sound_effect=true): $12
+        Animation:
           Pic: $13
-        Mix:
-          Audio(sound_effect=true): $14
-          Animation:
-          Pic(checked=true): $15
-          Pic: $16
-        Mix:
-          Audio(sound_effect=true): $17
-          Animation:
-          Pic(checked=true): $18
-          Pic: $19
-      \"""
-      display_layout: REGULAR
-      \"""
-    """
+          coordinate: x=$14,y=$15
+          Pic: $16
+          coordinate: x=$17,y=$18
+      Mix:
+        Text: $19
+        Audio(sound_effect=true): $20
+        Animation:
+          Pic: $21
+          coordinate: x=$22,y=$23
+          Pic: $24
+          coordinate: x=$25,y=$26
+      Mix:
+        Text: $27
+        Audio(sound_effect=true): $28
+        Animation:
+          Pic: $29
+          coordinate: x=$30,y=$31
+          Pic: $32
+          coordinate: x=$33,y=$34
+      Pic(sr_strat=true): $35
+      Pic(sr_end=true): $36
+    """
+  'AIXVideoPlay':
+    'prefix': 'aixvideoplay'
+    'body':"""
+      [TYPE AIXVideoPlay]
+      Video(stream=true): $1
+      Video(stream=true): $2
+      Video(stream=true): $3
+      QuestionPart:
+      Video: $4
+    """


Removed sample test

Removed sample test

--- test/hello-world_test.coffee
+++ test/hello-world_test.coffee
@@ -1,19 +0,0 @@
-chai = require 'chai'
-sinon = require 'sinon'
-chai.use require 'sinon-chai'
-
-expect = chai.expect
-
-describe 'hello-world', ->
-  beforeEach ->
-    @robot =
-      respond: sinon.spy()
-      hear: sinon.spy()
-
-    require('../src/hello-world')(@robot)
-
-  it 'registers a respond listener', ->
-    expect(@robot.respond).to.have.been.calledWith(/hello/)
-
-  it 'registers a hear listener', ->
-    expect(@robot.hear).to.have.been.calledWith(/orly/)


No more <output> in markup after #2560, fix #2851

--- form-builder/src/main/resources/forms/orbeon/builder/resources/section-grid-repeat/section-editor.coffee
+++ form-builder/src/main/resources/forms/orbeon/builder/resources/section-grid-repeat/section-editor.coffee
@@ -14,7 +14,7 @@
     frBodyLeft = 0;
     pageX = 0; pageY = 0
     SectionTitleSelector = '.fr-section-title:first'
-    SectionLabelSelector = '.fr-section-label:first a, .fr-section-label:first output'
+    SectionLabelSelector = '.fr-section-label:first a, .fr-section-label:first .xforms-output-output'

     FSM.create
         transitions : [


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/tween.coffee
+++ src/tween.coffee
@@ -44,12 +44,13 @@
     properties = Object.extend({}, properties) # Make a local copy

     easing = properties.easing || "linear"
+
     delete properties.easing
     delete properties.complete

     for property, target of properties
       I.activeTweens[property] =
-        complete: compl
+        complete: complete
         end: target
         start: I[property]
         easing: easing


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/tween.coffee
+++ src/tween.coffee
@@ -41,7 +41,7 @@
   player.tween 30,
     x: 50
     y: 50
-    easing: "quadratic"
+    complete: "quadratic"
   </pre></code>

   @name tween


Test for https://github.com/codecombat/codecombat/issues/654 (now properly failing)

--- test/protect_api_spec.coffee
+++ test/protect_api_spec.coffee
@@ -330,15 +330,18 @@
     code = """
       function Foo(arr) {
           this.arr = arr;
-          this.bar();
+          this.val = this.bar();
       }

       Foo.prototype.bar = function() {
           return this.arr[0];
       };

-      new Foo([1, 2, 3]);
-    """
-    aether = new Aether protectAPI: true
-    aether.transpile code
-    expect(aether.problems.errors.length).toEqual 0+      return new Foo([1, 2, 3]).val;
+    """
+    aether = new Aether protectAPI: true
+    aether.transpile code
+    expect(aether.problems.errors.length).toEqual 0
+    that = {}
+    method = aether.createMethod that
+    expect(method()).toBe 1


expand std range in test spec

expand std range in test spec

--- test/spec/helper.spec.coffee
+++ test/spec/helper.spec.coffee
@@ -43,8 +43,8 @@
         exp = Math.sqrt cycle.length * 1 / math.factorial before.length
         std = math.std _.values sum

-        expect(std)    .toBeGreaterThan(exp * 0.9)
-        expect(std).not.toBeGreaterThan(exp * 1.1)
+        expect(std)    .toBeGreaterThan(exp * 0.85)
+        expect(std).not.toBeGreaterThan(exp * 1.15)


Fixed total time calculations in User#toRawPayroll

--- src/models/user.coffee
+++ src/models/user.coffee
@@ -126,25 +126,34 @@
     row = {}
     row[headers.date] = moment.tz(constants.TIMEZONE).format('M/DD/YYYY')
     row[headers.name] = @name
-    dayLength = @activeTime()
     loggedTime = unpaidTime = vacationTime = sickTime = 0
     for punch in @punches
       if punch.date.isBefore(start) or punch.date.isAfter(end)
         continue
-      else if punch.times.block
-        loggedTime += punch.times.block
+      else if not punch.elapsed and not punch.times.block
+        continue
       else if punch.mode is 'in'
         continue
-      else if not punch.elapsed
-        continue
       else if punch.mode is 'vacation'
-        vacationTime += punch.elapsed
+        if punch.times.block
+          vacationTime += punch.times.block
+        else
+          vacationTime += punch.elapsed
       else if punch.mode is 'unpaid'
-        unpaidTime += punch.elapsed
+        if punch.times.block
+          unpaidTime += punch.times.block
+        else
+          unpaidTime += punch.elapsed
       else if punch.mode is 'sick'
-        sickTime += punch.elapsed
+        if punch.times.block
+          sickTime += punch.times.block
+        else
+          sickTime += punch.elapsed
       else
-        loggedTime += punch.elapsed
+        if punch.times.block
+          loggedTime += punch.times.block
+        else
+          loggedTime += punch.elapsed

     loggedTime = +loggedTime.toFixed(2)
     vacationTime = +vacationTime.toFixed(2)


commits use both template and commentchar configs

--- lib/models/git-commit-beta.coffee
+++ lib/models/git-commit-beta.coffee
@@ -20,7 +20,7 @@

 getTemplate = ->
   git.cmd(['config', '--get', 'commit.template']).then (filePath) ->
-    if filePath then fs.readFileSync(Path.get(filePath.trim())) else ''
+    if filePath then fs.readFileSync(Path.get(filePath.trim())).toString().trim() else ''

 prepFile = (status, filePath) ->
   git.cmd(['config', '--get', 'core.commentchar']).then (commentchar) ->


no message

no message

--- lib/project/create-project.coffee
+++ lib/project/create-project.coffee
@@ -78,7 +78,7 @@
           moduleConfigPath = pathM.join modulePath, desc.moduleConfigFileName

           moduleCB = (err) ->
-            console.error err
+            return console.error err if err?
           createCallBack = (err) =>
             return console.error err if err?
             Util.writeFile indexFilePath, Util.getIndexHtmlCore(moduleConfig),moduleCB


placeholder endpoints

placeholder endpoints

--- code/serv.coffee
+++ code/serv.coffee
@@ -30,7 +30,7 @@
 mongoose.connect process.env['COBALT_DB']

 app.get "/", (req, res) ->
-  res.send "Hello World"
+  res.send "Finish this."

 # Check API key for all POSTs
 # TODO: should this be middleware?
@@ -44,6 +44,10 @@
         res.send {error: "Unauthorised"}, 403
   else
     res.send {error: "No API key supplied"}, 403
+
+# Documentation for SSHing to a box.
+app.get "/:box_name$", (req, res) ->
+  res.send "Finish this." + req.params.box_name

 # Create a box
 app.post "/:box_name$", (req, res) ->


Use small pills for the income and expenses report.

--- app/assets/javascripts/dot_ledger/views/reports/income_and_expenses/filter.js.coffee
+++ app/assets/javascripts/dot_ledger/views/reports/income_and_expenses/filter.js.coffee
@@ -2,7 +2,7 @@
   class @Filter extends Backbone.Marionette.ItemView
     template: 'reports/income_and_expenses/filter'

-    className: 'nav nav-pills nav-justified'
+    className: 'nav nav-small nav-pills'

     tagName: 'ul'


Fix menu item for ordered list

Fix menu item for ordered list

Fixes #141

--- menus/menu.cson
+++ menus/menu.cson
@@ -103,7 +103,7 @@
             }
             {
               'label': 'Ordered List'
-              'command': 'markdown-writer:toggle-h5'
+              'command': 'markdown-writer:toggle-ol'
             }
             {
               'label': 'Task List'


Fix clear filters button

Fix clear filters button

--- app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee
+++ app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee
@@ -12,6 +12,10 @@
   $scope.sharedResource = false
   $scope.columns = Columns.columns
   $scope.sorting = SortOptions
+  $scope.distributorFilter = ''
+  $scope.supplierFilter = ''
+  $scope.orderCycleFilter = ''
+  $scope.quickSearch = ''
   $scope.page = 1
   $scope.per_page = 50

@@ -22,7 +26,9 @@
     $scope.distributorFilter = ''
     $scope.supplierFilter = ''
     $scope.orderCycleFilter = ''
-    $scope.quickSearch = ""
+    $scope.quickSearch = ''
+    $scope.page = 1
+    $scope.refreshData()

   $scope.changePage = (newPage) ->
     $scope.page = newPage
@@ -76,8 +82,6 @@
       StatusMessage.clear()
       unless $scope.initialized
         $scope.initialized = true
-        $timeout ->
-          $scope.resetSelectFilters()

   $scope.$watch 'bulk_order_form.$dirty', (newVal, oldVal) ->
     if newVal == true


fix proposal sorting

fix proposal sorting

Former-commit-id: 09f640891cafe6dc2d0787f3b9e789157138ae4d [formerly e632d7ccd13d81d91fddd63e0141dd57ef5345d6] [formerly 6e0d98644de19df2c5be7edb5646455915bce508 [formerly 6e0d98644de19df2c5be7edb5646455915bce508 [formerly 6ad3aab4e0ebd52a4a0f4099215dfb2a2c2e14bd]]]
Former-commit-id: 49faea15a5900ce9b0e8c6d53df41b128b4eed28 [formerly 2b98e1348a7eaa46b08bd8614fc87db665fd31f0]
Former-commit-id: 9f64c9a0bb0135f059409c7523294837442cc2d2
Former-commit-id: b952fdf460ce082f8cf35781b2fbb9a93e65d66b

--- app/assets/javascripts/backbone/apps/franklin/proposals/proposals_controller.coffee
+++ app/assets/javascripts/backbone/apps/franklin/proposals/proposals_controller.coffee
@@ -86,7 +86,8 @@

     setupFilterView : (collection) ->
       view = @getFilterView collection
-      @listenTo view, 'sort:requested', (sort_by) => @handleSortRequested collection, sort_by
+      @listenTo view, 'sort:requested', (sort_by) =>
+        @handleSortRequested collection, sort_by
       view

     handleBeforeViewAdded : (view) ->
@@ -116,7 +117,7 @@
     requestProposals : (collection, is_active, callback = null, callback_params = {}) ->
       proposals = App.request 'proposals:get', true

-      @listenToOnce App.vent, 'proposals:fetched:done', =>
+      App.execute 'when:fetched', proposals, =>
         proposals = App.request 'proposals:get'
         @resetCollection proposals, collection, is_active
         callback(callback_params) if callback


fix #3701 - fix html content in block text for the timeline

--- app/modules/user-timeline/user-timeline-item/user-timeline-item-type.service.coffee
+++ app/modules/user-timeline/user-timeline-item/user-timeline-item-type.service.coffee
@@ -88,7 +88,8 @@
             key: 'TIMELINE.NEW_COMMENT_US',
             translate_params: ['username', 'obj_name'],
             description: (timeline) ->
-                return $(timeline.getIn(['data', 'comment_html'])).text()
+                text = timeline.getIn(['data', 'comment_html'])
+                return $($.parseHTML(text)).text()
         },
         { # NewIssueComment
             check: (timeline, event) ->
@@ -96,7 +97,8 @@
             key: 'TIMELINE.NEW_COMMENT_ISSUE',
             translate_params: ['username', 'obj_name'],
             description: (timeline) ->
-                return $(timeline.getIn(['data', 'comment_html'])).text()
+                text = timeline.getIn(['data', 'comment_html'])
+                return $($.parseHTML(text)).text()
         },
         { # NewTaskComment
             check: (timeline, event) ->
@@ -104,7 +106,8 @@
             key: 'TIMELINE.NEW_COMMENT_TASK'
             translate_params: ['username', 'obj_name'],
             description: (timeline) ->
-                return $(timeline.getIn(['data', 'comment_html'])).text()
+                text = timeline.getIn(['data', 'comment_html'])
+                return $($.parseHTML(text)).text()
         },
         { # UsMove
             check: (timeline, event) ->
@@ -147,7 +150,8 @@
             translate_params: ['username', 'obj_name'],
             description: (timeline) ->
                 if timeline.hasIn(['data', 'value_diff', 'value', 'blocked_note_html'])
-                    return $(timeline.getIn(['data', 'value_diff', 'value', 'blocked_note_html']).get(1)).text()
+                    text = timeline.getIn(['data', 'value_diff', 'value', 'blocked_note_html']).get(1)
+                    return $($.parseHTML(text)).text()
                 else
                     return false
         },


:new: Add BottomContainer::setCount

:new: Add BottomContainer::setCount

--- lib/views/bottom-container.coffee
+++ lib/views/bottom-container.coffee
@@ -37,6 +37,11 @@
   onDidChangeTab: (callback) ->
     return @emitter.on 'did-change-tab', callback

+  setCount: ({Project, File, Line}) ->
+    @tabs.File.count = File
+    @tabs.Project.count = Project
+    @tabs.Line.count = Line
+
   updateTabs: ->
     active = @state.scope
     for name, tab of @tabs


Display error notification when Checkout fails

--- lib/views/branch-list-view.coffee
+++ lib/views/branch-list-view.coffee
@@ -50,9 +50,12 @@

   checkout: (branch) ->
     git.cmd(@args.concat(branch), cwd: @repo.getWorkingDirectory())
-    # using `stderr` for success here
+    # command terminates with an error-ish exit code
     .catch (data) =>
-      notifier.addSuccess data
+      if data.includes 'error'
+        notifier.addError data
+      else
+        notifier.addSuccess data
       atom.workspace.observeTextEditors (editor) =>
         if filepath = editor.getPath()?.toString()
           fs.exists filepath, (exists) =>


[Activity] removed there is no activity hint on load.

--- client/landing/app/Applications/Activity.kdapplication/activitylistcontroller.coffee
+++ client/landing/app/Applications/Activity.kdapplication/activitylistcontroller.coffee
@@ -10,7 +10,7 @@
     options.startWithLazyLoader = yes
     options.showHeader         ?= no
     options.noItemFoundWidget or= new KDCustomHTMLView
-      cssClass : "lazy-loader"
+      cssClass : "lazy-loader hidden"
       partial  : "There is no activity."

     # this is regressed until i touch this again. - SY


Don't add repeated entries to history

Don't add repeated entries to history

--- lib/ghci.coffee
+++ lib/ghci.coffee
@@ -82,7 +82,8 @@
     return false unless @finished and (not @timeout?)
     @history.back.push @history.forw...
     @history.forw = []
-    @history.back.push lines.join(EOL)
+    if (text = lines.join(EOL)) and @history.back.slice(-1)[0] isnt text
+      @history.back.push text
     @history.curr = ''
     @timeout = setTimeout (=>
       tkill @ghci.pid, 'SIGINT'


Fixed TypeError when use '--default-options-off'

--- lib/hint.coffee
+++ lib/hint.coffee
@@ -24,7 +24,7 @@
   options = buildTrueObj(
     if config.withDefaults
     then _.union config.options, defaultOptions
-    else options)
+    else config.options)
   _.map paths, (path) ->
     try
       source = fs.readFileSync(path)


https://github.com/atom/atom/issues/3473 issued reported

--- lib/hole.coffee
+++ lib/hole.coffee
@@ -14,8 +14,6 @@
       point = @agda.editor.buffer.positionForCharacterIndex headIndex
       marker = @agda.editor.markBufferPosition point

-    marker.on 'changed', (event) =>
-      console.log event.newHeadBufferPosition.toArray()

     @agda.editor.cursors[0].on 'moved', (event) =>
       cursorOld = event.oldBufferPosition
@@ -25,36 +23,17 @@
       markerLeft = marker.oldHeadBufferPosition
       markerCenter = markerLeft.translate new Point 0, 1
       markerRight = markerLeft.translate new Point 0, 2
+      if cursorNew.isEqual markerCenter
+        if cursorOld.isEqual markerLeft
+          # from left -->
+          @agda.editor.setCursorBufferPosition markerRight
+        else if cursorOld.isEqual markerRight
+          # from right <--
+          @agda.editor.setCursorBufferPosition markerLeft
+        else
+          # from somewhere else
+          @agda.editor.setCursorBufferPosition markerRight

-      if cursorNew.isEqual markerCenter
-        if cursorOld.isEqual markerLeft # from left -->
-          @agda.editor.moveCursorRight()
-        else if cursorOld.isEqual markerRight # from right <--
-          @agda.editor.moveCursorLeft()
-        else # from somewhere else
-          @agda.editor.moveCursorRight()
-
-        # direction = cursorNew.compare cursorOld
-        # if direction is 1 # =>
-        #   console.log '==>'
-        #   @agda.editor.moveCursorRight()
-        # else if direction is -1 # <=
-        #   console.log '<=='
-        #   @agda.editor.moveCursorLeft()
-
-
-
-    # tailIndices = indicesOf text, /!\}/
-    #
-    # for headIndex, i in headIndices
-    #   tailIndex = tailIndices[i]
-    #   headPoint = @agda.editor.buffer.positionForCharacterIndex headIndex
-    #   tailPoint = @agda.editor.buffer.positionForCharacterIndex tailIndex
-    #   marker = @agda.editor.markBufferRange [headPoint.toArray(), tailPoint.toArray()]
-    #   marker.on 'changed', (event) =>
-    #     console.log 'changed'
-    #     console.log event.oldHeadBufferPosition.toArray(), event.oldTailBufferPosition.toArray()
-    #     console.log event.newHeadBufferPosition.toArray(), event.newTailBufferPosition.toArray()

   indicesOf = (string, pattern) ->
     indices = []


Added selection of all the filename when editing [#110255316]

--- src/code/views/menu-bar-view.coffee
+++ src/code/views/menu-bar-view.coffee
@@ -11,13 +11,14 @@
     if props.filename?.length > 0 then props.filename else (tr "~MENUBAR.UNTITLED_DOCUMENT")

   getEditableFilename: (props) ->
-    if props.filename?.length > 0 then props.filename else ""
+    if props.filename?.length > 0 then props.filename else (tr "~MENUBAR.UNTITLED_DOCUMENT")

   getInitialState: ->
     state =
       editingFilename: false
       filename: @getFilename @props
       editableFilename: @getEditableFilename @props
+      initialEditableFilename: @getEditableFilename @props

   componentWillReceiveProps: (nextProps) ->
     @setState
@@ -44,12 +45,12 @@
   focusFilename: ->
     el = @filename()
     el.focus()
-    if typeof el.selectionStart is 'number'
-      el.selectionStart = el.selectionEnd = el.value.length
-    else if typeof el.createTextRange isnt 'undefined'
-      range = el.createTextRange()
-      range.collapse false
-      range.select()
+    el.select()
+
+  cancelEdit: ->
+    @setState
+      editingFilename: false
+      editableFilename: if @state.filename?.length > 0 then @state.filename else @state.initialEditableFilename

   rename: ->
     filename = @state.editableFilename.replace /^\s+|\s+$/, ''
@@ -60,13 +61,13 @@
         filename: filename
         editableFilename: filename
     else
-      @setState editingFilename: false
+      @cancelEdit()

   watchForEnter: (e) ->
     if e.keyCode is 13
       @rename()
     else if e.keyCode is 27
-      @setState editingFilename: false
+      @cancelEdit()

   help: ->
     window.open @props.options.help, '_blank'


Adjust update call

Adjust update call

--- src/coffee/orderdistribution.coffee
+++ src/coffee/orderdistribution.coffee
@@ -153,7 +153,7 @@
           id: channelId
         externalId: externalId
       ]
-    client.orders.byId(orderId).save(data)
+    client.orders.byId(orderId).update(data)
     .then =>
       @logger.debug "Sync info successfully saved for order #{orderId}"
       Q()


Reload eventStatistics team-wide

Reload eventStatistics team-wide

--- src/persistence.coffee
+++ src/persistence.coffee
@@ -397,9 +397,22 @@
     (statistic, callback) ->
       toRemove = statistic.statisticData.slice()
       toRemove.push statistic.eventStatistics...
-
-      linking.unlinkItems toRemove, lookup
-      deleteStatistic.call(this, statistic).fail((err) ->
+      toRemove.push statistic.memberStatistics...
+      toRemove.push statistic.teamStatistics...
+      toRemove.push statistic.statisticAggregates...
+
+      linking.unlinkItems toRemove, lookup
+      deleteStatistic.call(this, statistic).then((result) ->
+        teamId = statistic.teamId
+        statisticId = result.id
+        bulkLoadTypes = [
+          'memberStatistic',
+          'teamStatistic',
+          'statisticAggregate',
+          'eventStatistic'
+        ]
+        sdk.bulkLoad(teamId, bulkLoadTypes).then -> result
+      ).fail((err) ->
         linking.linkItems toRemove, lookup
         err
       ).callback callback
@@ -419,13 +432,11 @@
           'teamStatistic',
           'statisticAggregate',
           'statistic',
-          'statisticGroup'
+          'statisticGroup',
+          'eventStatistic'
         ]

-        promises.when(
-          sdk.bulkLoad(teamId, bulkLoadTypes)
-          sdk.loadEventStatistics statisticId: statisticId
-        ).then -> result
+        sdk.bulkLoad(teamId, bulkLoadTypes).then -> result
       ).callback callback

   # Update member statistics when saving statisticData
@@ -434,12 +445,12 @@
       bulkSaveStatisticData.call(this, templates, callback).then((result) ->
         if result[0]? and result[0].teamId?
           teamId = result[0].teamId
-          statisticId = result[0].statisticId
-          bulkLoadTypes = ['memberStatistic', 'statisticAggregate']
-          promises.when(
-            sdk.bulkLoad(teamId, bulkLoadTypes)
-            sdk.loadEventStatistics statisticId: statisticId
-          ).then -> result
+          bulkLoadTypes = [
+            'memberStatistic',
+            'statisticAggregate',
+            'eventStatistic'
+          ]
+          sdk.bulkLoad(teamId, bulkLoadTypes).then -> result
       ).callback callback

   wrapMethod sdk, 'saveStatisticDatum', (saveStatisticDatum) ->
@@ -448,11 +459,12 @@
       .then((result) ->
         teamId = result.teamId
         statisticId = result.statisticId
-        bulkLoadTypes = ['memberStatistic', 'statisticAggregate']
-        promises.when(
-          sdk.bulkLoad(teamId, bulkLoadTypes)
-          sdk.loadEventStatistics statisticId: statisticId
-        ).then -> result
+        bulkLoadTypes = [
+          'memberStatistic',
+          'statisticAggregate',
+          'eventStatistic'
+        ]
+        sdk.bulkLoad(teamId, bulkLoadTypes).then -> result
       ).callback callback

   # Remove deleted member statisticData when using bulk delete command
@@ -466,13 +478,13 @@
       linking.unlinkItems toRemove, lookup

       bulkDeleteStatisticData.call(this, member, event).then((result) ->
-        promises.when(
-          teamId = member.teamId
-          eventId = event.id
-          bulkLoadTypes = ['memberStatistic', 'statisticAggregate']
-          sdk.bulkLoad(teamId, bulkLoadTypes)
-          sdk.loadEventStatistics eventId: eventId
-        ).then -> result
+        teamId = member.teamId
+        bulkLoadTypes = [
+          'memberStatistic',
+          'statisticAggregate',
+          'eventStatistic'
+        ]
+        sdk.bulkLoad(teamId, bulkLoadTypes).then -> result
       ).fail((err) ->
         linking.linkItems toRemove, lookup
         err


JMachine::approve: allow users to mark their state as approved in this.users

When one shares their machine with someone else, we are adding them into users
list as approved: False which then they need to set this field to True for their
accounts if they are willing to use this machine. This method will set the
approved field as True for them after making required checks.

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -37,6 +37,8 @@
         some            :
           (signature Object, Function)
       instance          :
+        approve         :
+          (signature Function)
         reviveUsers     :
           (signature Function)
         shareWith       :
@@ -549,3 +551,24 @@
   #   @shareWith$ client, options, callback

+  approve: secure revive
+
+    shouldReviveClient   : yes
+    shouldLockProcess    : yes
+    shouldReviveProvider : no
+    hasOptions           : no
+
+  , (client, callback)->
+
+    { r: { user } } = client
+
+    # An owner cannot approve their own machine
+    if isOwner user, this
+      return callback null
+
+    JMachine.update
+      "_id"      : @getId()
+      "users.id" : user._id
+    , $set       : "users.$.approved" : yes
+    , (err)-> callback err
+


Only close the active modal

Only close the active modal


display subspecies & varieties in Species+ autocomplete

--- app/assets/javascripts/species/controllers/search_controller.js.coffee
+++ app/assets/javascripts/species/controllers/search_controller.js.coffee
@@ -24,7 +24,10 @@
     Species.AutoCompleteTaxonConcept.find(
       taxonomy: @get('taxonomy')
       taxon_concept_query: taxonConceptQuery
-      ranks: ['KINGDOM', 'PHYLUM', 'CLASS', 'ORDER', 'FAMILY', 'SUBFAMILY', 'GENUS', 'SPECIES']
+      ranks: [
+        'KINGDOM', 'PHYLUM', 'CLASS', 'ORDER', 'FAMILY', 'SUBFAMILY',
+        'GENUS', 'SPECIES', 'SUBSPECIES', 'VARIETY'
+      ]
       autocomplete: true
     )
   ).property('taxonConceptQuery')


Update provider improve error messages

Update provider improve error messages

Updated to use the new version of atom-linter linter provider methods improved error handling messages and added option to allow linter to be disabledon lack of config file

--- lib/main.coffee
+++ lib/main.coffee
@@ -1,27 +1,36 @@
 {CompositeDisposable} = require 'atom'
-{findFile} = helpers = require 'atom-linter'
+{find} = helpers = require 'atom-linter'
 path = require 'path'

 module.exports =
   config:
+    noConfigDisable:
+      title: 'Disable when no sass-lint config file is found in your project'
+      type: 'boolean'
+      default: false
+    configPath:
+      title: '.sass-lint.yml Path'
+      description: 'A .sass-lint.yml file to use if no config file is found in the current project'
+      type: 'string'
+      default: ''
     executablePath:
       title: 'sass-lint package Path'
+      description: 'If you\'d like to use a copy of sass-lint other than the one included with this package, specify the path to it here'
       type: 'string'
       default: path.join(__dirname, '..', 'node_modules', 'sass-lint')
-    configPath:
-      title: 'The .sass-lint.yml config file you would like to use e.g. /path/to/.sass-lint.yml'
-      type: 'string'
-      default: ''

   activate: ->
-
+    require('atom-package-deps').install()
     @subs = new CompositeDisposable
+    @subs.add atom.config.observe 'linter-sass-lint.noConfigDisable',
+      (noConfigDisable) =>
+        @noConfigDisable = noConfigDisable
+    @subs.add atom.config.observe 'linter-sass-lint.configPath',
+      (configPath) =>
+        @configPath = configPath
     @subs.add atom.config.observe 'linter-sass-lint.executablePath',
       (executablePath) =>
         @executablePath = executablePath
-    @subs.add atom.config.observe 'linter-sass-lint.configPath',
-      (configPath) =>
-        @configPath = configPath

   deactivate: ->
     @subs.dispose()
@@ -35,8 +44,20 @@
       lint: (editor) =>
         configExt = '.sass-lint.yml'
         filePath = editor.getPath()
-        config = if @configPath is '' then findFile filePath, configExt else @configPath
-        linter = require(@executablePath)
+        projectConfig = find filePath, configExt
+        globalConfig = if @configPath is '' then null else @configPath
+        config = if projectConfig isnt null then projectConfig else globalConfig
+
+        try
+          linter = require(@executablePath)
+        catch error
+          atom.notifications.addWarning """
+            **Sass-lint package missing**
+
+            The sass-lint package cannot be found, please check sass-lint package path option of this package. \n
+            If you leave this option empty the sass-lint package included with linter-sass-lint will be used.
+          """
+          return []

         if config isnt null and path.extname(config) isnt '.yml'
           config = path.join @configPath, configExt
@@ -49,7 +70,7 @@
             Please add the full path and filename to this plugins configPath option.
           """

-        if config is null
+        if config is null and @noConfigDisable is false
           atom.notifications.addError """
             **No .sass-lint.yml config file found.** You can find an example of one
             [here](https://github.com/sasstools/sass-lint/blob/master/lib/config/sass-lint.yml)
@@ -57,6 +78,9 @@
             [here](https://github.com/sasstools/sass-lint/tree/master/docs).
           """

+          return []
+
+        else if config is null and @noConfigDisable is true
           return []

         try
@@ -76,16 +100,29 @@
               filePath: filePath
               range: [[lineIdx, 0], [lineIdx, colEndIdx]]
             ]
+          else
+            atom.notifications.addError """
+              **sass-lint had a problem**
+              Please consider filing an issue with [sass-lint](https://github.com/sasstools/sass-lint/)
+              including the text below and any other information possible.

+              #{error.stack}
+            """, {dismissable: true}
           return []

         if results[0] then return results[0].messages.map (msg) ->
           line = if msg.line then msg.line - 1 else 0
           col = if msg.column then msg.column - 1 else 0
+          text = if msg.message then ' ' + msg.message else 'Unknown Error'
+          html = '' + msg.ruleId + '' + text

-          type: if msg.severity is 1 then 'Warning' else if msg.severity is 2 then 'Error' else 'Info'
-          text: if msg.message then msg.ruleId + ': ' + msg.message else 'Unknown Error'
-          filePath: filePath
-          range: [[line, col], [line, col + 1]]
+          result = {
+            type: if msg.severity is 1 then 'Warning' else if msg.severity is 2 then 'Error' else 'Info',
+            html,
+            filePath: filePath,
+            range: [[line, col], [line, col + 1]]
+          }
+
+          return result

         return []


Add `standAloneMinimapForEditor` in API

Add `standAloneMinimapForEditor` in API

--- lib/main.coffee
+++ lib/main.coffee
@@ -253,6 +253,15 @@

     minimap

+  standAloneMinimapForEditor: (textEditor) ->
+    return unless textEditor?
+
+    Minimap ?= require './minimap'
+    new Minimap({
+      textEditor: atom.workspace.getActiveTextEditor()
+      standAlone: true
+    })
+
   # Returns the {Minimap} of the active `TextEditor`.
   #
   # Returns a {Minimap}.


Treat imports separately to handle multiline statements

--- lib/main.coffee
+++ lib/main.coffee
@@ -35,8 +35,18 @@
       # E262 - inline comment should start with '# '
       # E265 - block comment should start with '# '
       return [[lineNumber, colNumber - 1], [lineNumber, colNumber + 1]]
-    when 'F401', 'F821', 'F841'
+    when 'F401'
       # F401 - 'SYMBOL' imported but unused
+      symbol = /'([^']+)'/.exec(message)[1]
+      while true
+        offset = 0
+        tokenizedLine = textEditor.tokenizedLineForScreenRow(lineNumber)
+        for token in tokenizedLine.tokens
+          if token.value is symbol
+            return [[lineNumber, offset], [lineNumber, offset + token.bufferDelta]]
+          offset += token.bufferDelta
+        lineNumber += 1
+    when 'F821', 'F841'
       # F821 - undefined name 'SYMBOL'
       # F841 - local variable 'SYMBOL' is assigned but never used
       symbol = /'([^']+)'/.exec(message)[1]


Formatting

Formatting

--- lib/main.coffee
+++ lib/main.coffee
@@ -13,7 +13,7 @@
       default: true
     indentListItems:
       title: 'Indent list-items'
-      description: 'Automatically in- and outdent list-items by pressing `TAB` and `SHIFT + TAB`'
+      description: 'Automatically in- and outdent list-items by pressing `TAB` and `SHIFT+TAB`'
       type: 'boolean'
       default: true

@@ -22,19 +22,20 @@
   activate: (state) ->
     @subscriptions = new CompositeDisposable()

-    # NOTE
-    # https://atom.io/docs/api/v1.2.0/TextEditor
-    # https://atom.io/docs/api/v1.2.0/ScopeDescriptor
-    # https://atom.io/docs/latest/behind-atom-scoped-settings-scopes-and-scope-descriptors
+    # Add commands to overwrite the behavior of tab within list-item context
+    @subscriptions.add atom.commands.add 'atom-workspace', 'markdown:indent-list-item': (event) => @indentListItem(event)
+    @subscriptions.add atom.commands.add 'atom-workspace', 'markdown:outdent-list-item': (event) => @outdentListItem(event)
+
+    # Only when in dev-mode,
+    # create the {language-markdown:compile-grammar} command,
+    # via which the compiler can be executed
+    if atom.inDevMode()
+      @subscriptions.add atom.commands.add 'atom-workspace', 'markdown:compile-grammar-and-reload': => @compileGrammar()

     # NOTE
     # Thank you to @jonmagic from whom I've borrowed the first bit of code to make adding new list-items a reality. My implementation has since then taken a completely different approach, but his attempt was a pleasant jump-start.
     # https://github.com/jonmagic/gfm-lists
     # @burodepeper
-
-    @subscriptions.add atom.commands.add 'atom-workspace', 'markdown:indent-list-item': (event) => @indentListItem(event)
-
-    @subscriptions.add atom.commands.add 'atom-workspace', 'markdown:outdent-list-item': (event) => @outdentListItem(event)

     # Create a new list-item after pressing [enter]
     @subscriptions.add atom.workspace.observeTextEditors (editor) ->
@@ -113,12 +114,6 @@
                     # Force {text} to become a string; prevents rare errors
                     editor.insertText(text + '')
                     break
-
-    # Only when in dev-mode,
-    # create the {language-markdown:compile-grammar} command,
-    # via which the compiler can be executed
-    if atom.inDevMode()
-      @subscriptions.add atom.commands.add 'atom-workspace', 'markdown:compile-grammar-and-reload': => @compileGrammar()

   indentListItem: (event) ->
     {editor, position} = @getEditorAndPosition(event)


+ set layer dimension relative to resolution

--- lib/main.coffee
+++ lib/main.coffee
@@ -2,13 +2,13 @@

   constructor: (element_id) ->
     @element   = document.getElementById(element_id);
-    console.log(window.devicePixelRatio);
+    @resolution = window.devicePixelRatio;
     @stage     = new PIXI.Stage(0x454545);
     @renderer  = PIXI.autoDetectRenderer(
       @element.width,
       @element.height,
       view: @element,
-      resolution: window.devicePixelRatio
+      resolution: @resolution
     );
     #document.body.appendChild(@renderer.view);

@@ -48,8 +48,8 @@
   create: () =>
     console.log('create main');
     @map.create
-      width: @element.width
-      height: @element.height
+      width: @element.width / @resolution
+      height: @element.height / @resolution
       fieldSize: 55
       ax: 0
       ay: 0


Actually open a package detail view from a URI

--- lib/main.coffee
+++ lib/main.coffee
@@ -10,11 +10,23 @@

 openPanel = (panelName, uri) ->
   settingsView ?= createSettingsView({uri: configUri})
-  detail = null
-  if uri
-    match = uriRegex.exec(uri)
-    detail = match[2] if match
-  settingsView.showPanel(panelName, {uri: uri, detail: detail})
+
+  # There appears to be a bug that regex.exec doesn't assign, or lazily assigns,
+  # so even if there is a match, it's null unless I immediately call it a second
+  # time. Probably should dig deeper on this to figure out exactly why it's
+  # happening here and file an issue on either Atom or Electron, as appropriate.
+  # TODO: remove if this strange behavior goes away with an Electron update.
+  match = uriRegex.exec(uri)
+  match = uriRegex.exec(uri)
+
+  panel = match?[1]
+  detail = match?[2]
+  options = uri: uri
+  if panel is "packages" and detail?
+    panelName = detail
+    options.pack = name: detail
+
+  settingsView.showPanel(panelName, options)

 deserializer =
   name: 'SettingsView'


Avoid multiple calls to date modal & add date to duplicated relations

--- app/frontend/javascripts/views/visualization-table-relations.js.coffee
+++ app/frontend/javascripts/views/visualization-table-relations.js.coffee
@@ -117,7 +117,7 @@

   # Method called from parent class `VisualizationTableBase`
   createRow: (index) ->
-    console.log 'createRow', index
+    #console.log 'createRow', index
     # We need to set `wait = true` to wait for the server before adding the new model to the collection
     # http://backbonejs.org/#Collection-create
     row_model = @collection.create {dataset_id: @model.get('dataset_id'), 'direction': false, wait: true}
@@ -132,8 +132,11 @@
           @table.setDataAtRowProp index, 'target_name', @duplicate.get('target_name')
         if @duplicate.get('relation_type')
           @table.setDataAtRowProp index, 'relation_type', @duplicate.get('relation_type')
+        @table.setDataAtRowProp index, 'from', @duplicate.get('from')
+        @table.setDataAtRowProp index, 'to', @duplicate.get('to')
+        @table.setDataAtRowProp index, 'date', @duplicate.get('date')
         @table.setDataAtRowProp index, 'direction', @duplicate.get('direction')
-        console.log 'now set duplicate values'
+        #console.log 'now set duplicate values'
         @duplicate = null
       else
         @table.setDataAtRowProp index, 'direction', false
@@ -235,18 +238,17 @@

   # Custom Renderer for date cells
   rowDateRenderer: (instance, td, row, col, prop, value, cellProperties) =>
-    Handsontable.Dom.empty(td)
+    Handsontable.Dom.empty td
     if value
       link = document.createElement('DIV')
       link.innerHTML = value
-      td.appendChild(link)
     else
       link = document.createElement('A')
       link.className = 'icon-plus'
       link.innerHTML = link.title = 'Edit Date'
-      td.appendChild(link)
+    td.appendChild link
     # Add description modal on click event or keydown (enter or space)
-    Handsontable.Dom.addEvent td, 'click', (e) =>
+    Handsontable.Dom.addEvent link, 'click',  (e) =>
       e.preventDefault()
       @showDateModal row
     return td


Add note about an issue with list-items in embedded code

--- lib/main.coffee
+++ lib/main.coffee
@@ -30,8 +30,14 @@
             previousRowNumber = event.range.start.row
             previousRowRange = editor.buffer.rangeForRow(previousRowNumber)
             previousLine = editor.getTextInRange(previousRowRange)
+            # FIXME
+            # Because the line is tokenized outside of its context, a line that
+            # looks like it contains a list-item, but is part of a fenced-code-
+            # block, will still be considered a valid list-item. A solution
+            # would be to get the {tokens} from the {previousLine} via the
+            # {editor}, as it was implemented in an earlier, rather verbose
+            # version.
             {tokens} = grammar.tokenizeLine(previousLine)
-            # TODO check if this doesn't cause problems with enters in embedded code

             tokens.reverse()
             for token in tokens


#6 support sass too and do path manipulation before adding exts

--- lib/main.coffee
+++ lib/main.coffee
@@ -28,23 +28,18 @@

     if extname = path.extname(editor.getURI()) # ext of current file.
       exts.push extname.substr(1)
-
+
     {scopeName} = editor.getGrammar()

-    exts = exts.concat getExtensionsForScope(scopeName)
+    exts = exts.concat(getExtensionsForScope(scopeName))
     files = ("#{file}.#{ext}" for ext in exts)
-    files.push file
-
-    # Support for sass partials
-    if ~scopeName.indexOf('scss')
-      files.push file.replace(/(.*)\/(.*)$/, "$1/_$2.scss")
-
-    _.uniq files
+    files.push(file)
+
+    _.uniq(files)

   # Return first existing filePath in following order.
   #  - File with same extension to current file's
   #  - File with extensions... from current Grammar.fileTypes
-  #  - File
   #  - File have same basename
   detectFilePath: (filePath) ->
     # Search existing file from file list.
@@ -62,6 +57,14 @@

     if filePath = @detectFilePath(path.resolve(dirName, fileName))
       return filePath
+
+    # If grammar was sass or scss we try to find partial file which
+    # starts with underscore.
+    {scopeName} = editor.getGrammar()
+    if scopeName in ['source.sass', 'source.css.scss']
+      [precedings..., lastPart] = fileName.split(path.sep)
+      sassPartialFileName = path.join([precedings..., "_" + lastPart]...)
+      return @detectFilePath(path.resolve(dirName, sassPartialFileName))

     # Surpport git diff output
     if fileName.match(/^[ab]\//)


improve offset handling during resize

improve offset handling during resize

--- app/assets/javascripts/components/mark/tools/text-row-tool/index.cjsx
+++ app/assets/javascripts/components/mark/tools/text-row-tool/index.cjsx
@@ -26,13 +26,32 @@
         @forceUpdate()

   handleDrag: (e) ->
-    console.log 'mark.yUpper/yLower: ', @state.mark.yUpper, ' ', @state.mark.yLower
+    # console.log 'mark.yUpper/yLower: ', @state.mark.yUpper, ' ', @state.mark.yLower
+    # mark = @state.mark
+    offset = @props.getEventOffset e
+    # mark.x = offset.x
+    # mark.y = offset.y
+    # @setState mark: mark, =>
+    #   console.log 'updated mark: ', mark.yUpper, mark.yLower
+
     mark = @state.mark
-    offset = @props.getEventOffset(e)
-    mark.x = offset.x
-    mark.y = offset.y
-    @setState mark: mark, =>
-      console.log 'updated mark: ', mark.yUpper, mark.yLower
+    mark.x = Math.round offset.x #+ @state.markOffset.x
+    mark.y = Math.round offset.y #+ @state.markOffset.y
+    markHeight = mark.yLower - mark.yUpper
+    mark.yUpper = Math.round mark.y - markHeight/2
+    mark.yLower = Math.round mark.y + markHeight/2
+
+    # prevent dragging mark beyond image bounds
+    # offset = @state.markOffset.y
+    # return if ( y + offset - markHeight/2 ) < 0
+    # return if ( y + offset + markHeight/2 ) > @state.imageHeight
+
+    # prevent dragging mark beyond image bounds
+    return if ( offset.y - markHeight/2 ) < 0
+    return if ( offset.y + markHeight/2 ) > @props.imageHeight
+
+
+    @setState mark: mark

   handleResize: (whichOne, e) ->
     mark = @state.mark


Added a valid filter value

Added a valid filter value

--- app/assets/javascripts/trade/routes/sandbox_shipments_route.js.coffee
+++ app/assets/javascripts/trade/routes/sandbox_shipments_route.js.coffee
@@ -1,5 +1,5 @@
 Trade.SandboxShipmentsRoute = Ember.Route.extend

   model: () ->
-    Trade.SandboxShipment.find({'query_params_to_come': 'nothing'})
-    +    Trade.SandboxShipment.find({'appendix': 'I'})
+


Remove json-ld metadata for shows without location

`Event` types now have a required `location` field. For shows which don't have location we cannot provide one so removing it altogether
https://developers.google.com/search/docs/data-types/event#datatypes

--- src/desktop/apps/show/routes.coffee
+++ src/desktop/apps/show/routes.coffee
@@ -147,7 +147,7 @@
       res.locals.sd.INCLUDE_SAILTHRU = res.locals.sd.PARTNER_SHOW?
       res.locals.ViewHelpers = ViewHelpers
       res.locals.DateHelpers = DateHelpers
-      res.locals.jsonLD = JSON.stringify ViewHelpers.toJSONLD data.partner_show
+      res.locals.jsonLD = JSON.stringify ViewHelpers.toJSONLD data.partner_show if data.partner_show.has_location
       data.artworkColumns = ViewHelpers.groupByColumnsInOrder(data.partner_show.artworks)
       res.render 'index', data
     .catch next


defend against undefined property

defend against undefined property

--- services/web/public/coffee/ide/share/controllers/ShareProjectModalController.coffee
+++ services/web/public/coffee/ide/share/controllers/ShareProjectModalController.coffee
@@ -81,7 +81,7 @@
 						return addNextMember()

 					# NOTE: groups aren't really a thing in ShareLaTeX, partially inherited from DJ
-					if member.display in currentInviteEmails and inviteId = _.find($scope.project.invites, (invite) -> invite.email == member.display)?._id
+					if member.display in currentInviteEmails and inviteId = _.find(($scope.project.invites || []), (invite) -> invite.email == member.display)?._id
 						request = projectInvites.resendInvite(inviteId)
 					else if member.type == "user"
 						request = projectInvites.sendInvite(member.email, $scope.inputs.privileges)


Fix infinite loading

Fix infinite loading

--- components/block_collection/client/manage_block_collection_view.coffee
+++ components/block_collection/client/manage_block_collection_view.coffee
@@ -5,16 +5,15 @@
 mediator = require '../../../lib/mediator.coffee'
 Block = require '../../../models/block.coffee'
 ManageBlockView = require './manage_block_view.coffee'
-BlockCollectionView = require './block_collection_view.coffee'
+UserBlockCollectionView = require './user_block_collection_view.coffee'

-module.exports = class ManageBlockCollectionView extends BlockCollectionView
+module.exports = class ManageBlockCollectionView extends UserBlockCollectionView

   events:
     "click .manage__block__sort__link": "sortBlocks"

   initialize: (options)->
     super
-    @blocks.on 'add', @appendBlockView, @

   sortBlocks: (e)->
     column = $(e.target).data('sort')
@@ -27,11 +26,9 @@
     @blocks.fetch
       success: =>
         @$('.manage__block__collection__contents').html('')
-        debugger
+
         for model in @blocks.models
           @renderBlockView(model, true)
-
-        debugger

   renderBlockView: (block, autoRender = false)->
     new ManageBlockView
@@ -39,4 +36,3 @@
       model: block
       autoRender: autoRender
       channel: @channel if @channel
-


Add Comment to the CommentsCollection

Add Comment to the CommentsCollection

--- core/app/backbone/views/facts/auto_complete_fact_relations_view.coffee
+++ core/app/backbone/views/facts/auto_complete_fact_relations_view.coffee
@@ -131,8 +131,13 @@

   initialize: (opts) ->
     @comments = opts.comments
+
   submit: ->
     content = @$('.content').val()
+
+    comment = new Comment( content: content )
+    @comments.add comment
+    comment.save()

@@ -164,6 +169,8 @@

   onRender: ->
     @inputRegion.switchTo 'search_view'
+    # TODO: For development:
+    @inputRegion.switchTo 'add_comment_view'

   searchView: ->
     searchView = new AutoCompleteFactRelationsView


gokmen's fix on sh kite api

gokmen's fix on sh kite api

--- kites/sharedHosting/api.coffee
+++ kites/sharedHosting/api.coffee
@@ -166,26 +166,27 @@
       console.error err if err
       callback? err, null

-    mkdirp appRootPath, (err)->
-      if err then cb err
-      else
-        exec "stat #{versionedPath}", (err, stdout, stderr)->
-          unless err or stderr.length
-            cb "[ERROR] Version is already published, change version and try again!"
-          else
-            exec "rm -f #{latestPath} && cp -r #{userAppPath} #{versionedPath} && ln -s #{versionedPath} #{latestPath}", (err, stdout, stderr)->
-              if err or stderr then cb err
-              else
-                manifestPath = "#{versionedPath}/.manifest"
-                exec "cat #{manifestPath}", (err, stdout, stderr)->
-                  if err or stderr then cb err
-                  else
-                    exec "rm -f #{manifestPath}", ->
-                      manifest = JSON.parse stdout
-                      manifest.authorNick = username
-                      delete manifest.devMode if manifest.devMode
-                      unescapedManifestPath = "/opt/Apps/#{username}/#{appName}/#{version}/.manifest"
-                      fs.writeFile unescapedManifestPath, JSON.stringify(manifest, null, 2), 'utf8', cb
+    createAppsDir username, (err)->
+      makedirp appRootPath, username, (err)->
+        if err then cb err
+        else
+          exec "stat #{versionedPath}", (err, stdout, stderr)->
+            unless err or stderr.length
+              cb "[ERROR] Version is already published, change version and try again!"
+            else
+              exec "rm -f #{latestPath} && cp -r #{userAppPath} #{versionedPath} && ln -s #{versionedPath} #{latestPath}", (err, stdout, stderr)->
+                if err or stderr then cb err
+                else
+                  manifestPath = "#{versionedPath}/.manifest"
+                  exec "cat #{manifestPath}", (err, stdout, stderr)->
+                    if err or stderr then cb err
+                    else
+                      exec "rm -f #{manifestPath}", ->
+                        manifest = JSON.parse stdout
+                        manifest.authorNick = username
+                        delete manifest.devMode if manifest.devMode
+                        unescapedManifestPath = "/opt/Apps/#{username}/#{appName}/#{version}/.manifest"
+                        fs.writeFile unescapedManifestPath, JSON.stringify(manifest, null, 2), 'utf8', cb

   downloadApp: (options, callback)->


Nicer default message.

Nicer default message.

--- src/extras/testing/test_case.coffee
+++ src/extras/testing/test_case.coffee
@@ -102,3 +102,10 @@
       QUnit.ok(false, "Expectation #{key} did not callback #{count} time(s)")

   clearExpectations: -> @_expectations = {}
+
+# Nicer messages for the command line runner
+do ->
+  originalPush = QUnit.push
+  QUnit.push = (result, actual, expected, message) ->
+    message ||= QUnit.jsDump.parse(expected) + " expected but was " + QUnit.jsDump.parse(actual)
+    originalPush.call(QUnit, result, actual, expected, message)


service chain is more forgiving, accepts empty params

--- lib/util.coffee
+++ lib/util.coffee
@@ -35,22 +35,30 @@

   # execute a stack of services (similar to async.waterfall)
   chain: (serviceName, input, stack, cb) ->
+
+    # defaults
+    serviceName ||= 'Service'
+    input ||= {}
     cb ||= ->
+
+    # validations
     unless (typeof input) is 'object'
       return new Error "#{serviceName} requires an arguments object as the first argument."
     unless Array.isArray(stack) and stack.length > 0
       return cb()

+    # stack iterator
     callNext = (index, args) ->

       # exit condition
       unless index < stack.length
-        unless (typeof args) is 'object'
-          return cb new Error "#{serviceName} must return an object."
         return cb null, args

       # run next service
       stack[index] args, (err, results) ->
+        results ||= {}
+        unless (typeof results) is 'object'
+          return cb new Error "#{stack[index].serviceName or serviceName} must return an object."
         return cb err if err
         callNext index + 1, results


Create Range from prototype

Create Range from prototype

…so that all the operations in the constructor can be skipped, ‘cause
we need `start` and `end` to be `null`.

--- src/marker-index.coffee
+++ src/marker-index.coffee
@@ -462,6 +462,4 @@
     throw new TypeError("Marker ID must be a string")

 templateRange = ->
-  range = new Range(Point.ZERO, Point.ZERO)
-  range.start = range.end = null
-  range
+  Object.create(Range.prototype)


fix unicode space

fix unicode space

--- src/glyphs/punctuation/space.coffee
+++ src/glyphs/punctuation/space.coffee
@@ -1,5 +1,5 @@
 exports.glyphs['space'] =
-	unicode: ' '
+	unicode: 32
 	ot:
 		advanceWidth: 250 * width
 	tags: [


Use the bash/sh/ksh lexer for "shell".

Use the bash/sh/ksh lexer for "shell".

--- grammars/restructuredtext.cson
+++ grammars/restructuredtext.cson
@@ -323,6 +323,19 @@
         ]
       }
       {
+        'begin': '^([ \\t]*)\\.\\.\\scode-block::\\s(shell|(ba|k)?sh)\\s*$'
+        'captures':
+          '2':
+            'name': 'entity.name.directive.restructuredtext'
+        'end': '^(?!\\1[ \\t])(?=\\S+)'
+        'contentName': 'source.shell'
+        'patterns': [
+          {
+            'include': 'source.shell'
+          }
+        ]
+      }
+      {
         'begin': '^([ \\t]*)\\.\\.\\scode-block::\\s(py(thon)?|sage)\\s*$'
         'captures':
           '2':


limit tooltips at 40 names

limit tooltips at 40 names

--- app/assets/javascripts/species/views/documents/documents_tooltip_component.js.coffee
+++ app/assets/javascripts/species/views/documents/documents_tooltip_component.js.coffee
@@ -6,7 +6,10 @@
   ).property('person')

   formattedData: ( ->
-    this.get('data').join(', ')
+    data = this.get('data')
+    dataStr = data.slice(0,40).join(', ')
+
+    if data.length <= 40 then dataStr else dataStr + '...'
   ).property()

   isTaxa: ( ->


remove an unnecessary newline

remove an unnecessary newline

--- lib/changes/git-changes.coffee
+++ lib/changes/git-changes.coffee
@@ -103,7 +103,6 @@
       Git.Branch.setUpstream(branch, "origin/#{name}")
     .then =>
       @emitter.emit('did-update-repository')
-

   checkoutBranch: (name) ->
     Git.Repository.open(@repoPath)


- Remove messy code, emit closeTopicsModal to close modal

--- client/landing/app/Applications/Topics.kdapplication/Views/TopicsListItemView.coffee
+++ client/landing/app/Applications/Topics.kdapplication/Views/TopicsListItemView.coffee
@@ -176,22 +176,13 @@

     super options,data

-    @titleLink = new KDCustomHTMLView
-      tagName     : 'a'
-      attributes  :
-        href      : '#'
-        class     : 'ttag'
-      pistachio   : '{{#(title)}}'
-    , data
+    @titleLink = new TagLinkView null, data

     @titleLink.registerListener
       KDEventTypes  : 'click'
       listener      : @
       callback      : (pubInst, event)=>
-        tag = @getData()
-        appManager.tell "Topics", "createContentDisplay", tag
-        event.stopPropagation()
-        no
+        @getDelegate().emit "closeTopicsModal"

   pistachio:->
     """


change some code style

change some code style

--- views/components/ship/index.cjsx
+++ views/components/ship/index.cjsx
@@ -95,32 +95,24 @@
       dataVersion: 0
     showDataVersion: 0
     shouldComponentUpdate: (nextProps, nextState)->
-      if nextProps.selectedKey[0]?
-        if nextProps.selectedKey[0] is @props.index
-          if nextProps.selectedKey[1] is @props.selectedKey[1]
-            if nextState.dataVersion isnt @showDataVersion
+      #only when this pane is visibile and its data is changed, this pane update.
+      if nextProps.selectedKey[0]?  # if layout is double-tabareas
+        if nextProps.selectedKey[0] is @props.index # if ship-pane is visibile
+          if nextProps.selectedKey[1] is @props.selectedKey[1] # rule out the condition of switching plugin-tab
+            if nextState.dataVersion isnt @showDataVersion # if dataVersion is changed, this pane should update!
               @showDataVersion = nextState.dataVersion
-              true
-            else
-              false
-          else
-            false
-        else
-          false
-      else
-        if nextProps.selectedKey is @props.index
-          if nextState.dataVersion isnt @showDataVersion
+              return true
+      else  # layout is single-tabareas
+        if nextProps.selectedKey is @props.index # if ship-pane is visibile
+          if nextState.dataVersion isnt @showDataVersion # if dataVersion is changed, this pane should update!
             @showDataVersion = nextState.dataVersion
-            true
-          else
-            false
-        else
-          false
+            return true
+      false
     handleClick: (idx) ->
       if idx isnt @state.activeDeck
         @setState
           activeDeck: idx
-          dataVersion: @state.dataVersion+=1
+          dataVersion: @state.dataVersion += 1
     handleResponse: (e) ->
       {method, path, body, postBody} = e.detail
       {names, ndocks} = @state
@@ -177,7 +169,7 @@
         decks: decks
         ndocks: ndocks
         states: states
-        dataVersion: @state.dataVersion+=1
+        dataVersion: @state.dataVersion += 1
     componentDidMount: ->
       window.addEventListener 'game.response', @handleResponse
     componentWillUnmount: ->


ADDED button toggle logic for Bow button.

--- app/assets/javascripts/angular/controllers/ViewProfileCtrl.coffee
+++ app/assets/javascripts/angular/controllers/ViewProfileCtrl.coffee
@@ -4,13 +4,36 @@
   userId = $routeParams.userId
   $scope.bowLabel = "Bow"

+
+  checkExistingApprenticeship = (user, currentUser) ->
+
+    # .then (result) ->
+    #   $scope.apprenticeships = result.data.apprenticeships
+    #   console.log 'apprenticeships = ', $scope.apprenticeships
+    #   console.log 'user = ', user
+    #   console.log 'current =', currentUser
+    #   existing = _.find($scope.apprenticeships, (apprenticeship) ->
+    #     apprenticeship.links.master.id == user.id and apprenticeship.links.apprentice.id == currentUser.id
+    #   )
+    #   return existing
+
   showOrHideBow = (user, currentUser) ->
-    console.log 'current', currentUser.id, currentUser.role
-    console.log 'user', user.id, user.role
     if currentUser.role == "apprentice" and user.role == "master"
       user.showBow = true
+      $http.get('/api/apprenticeships').then (result) ->
+        existing = _.find(result.data.apprenticeships, (apprenticeship) ->
+          apprenticeship.links.master.id == user.id and apprenticeship.links.apprentice.id == currentUser.id
+        )
+        if existing
+          $scope.bowLabel = "Connected"
+          $('#bow-button').removeAttr("data-toggle")
+        else
+          $scope.bowLabel = "Bow"
+          $('#bow-button').addAttr("data-toggle")
+
     else
       user.showBow = false
+

   defer.promise
     .then User.loadCurrentUser().then (result) ->
@@ -28,10 +51,11 @@
       $http.post('/api/apprenticeships', newApprenticeship).then ->
         console.log "Successfully created new apprenticeship"
         $('#bow-modal').modal('hide')
-        $scope.bowLabel = "Pending Bow"
+        $scope.bowLabel = "Connected"
         $('#bow-button').removeAttr("data-toggle")
     else
       console.log "apprenticeship must be between an apprentice and master"

 ])
+


fix closing position goes to crafting page

Former-commit-id: 3adb736800c7762e00246a484775314df740dba9 [formerly 987ca0ca361fb9037d5c57e496f352dfd1db1d18] [formerly 04fa0ffbfe43c4b084a298c8a17085cafb68066d [formerly 04fa0ffbfe43c4b084a298c8a17085cafb68066d [formerly bfba0b7fa422b98e625369a5ef902b9ee542db99]]]
Former-commit-id: 70c5a3bcd62ecec2d03f53afcb3dfafa2fa2b8da [formerly efc05d1d7f4a14c15655c2ae8801f35f0204ee68]
Former-commit-id: 8f1b67892cd650d9806908d21f07d4be59043217
Former-commit-id: 88f9522f40302414aaef2ac71d850dbd3d9c4bfd

--- app/assets/javascripts/backbone/apps/franklin/franklin_app.coffee
+++ app/assets/javascripts/backbone/apps/franklin/franklin_app.coffee
@@ -198,7 +198,8 @@

         crumbs = [
           ['homepage', '/'],
-          ["#{proposal.long_id}", Routes.new_position_proposal_path(long_id)]
+          ["#{proposal.long_id}", Routes.new_position_proposal_path(long_id)],
+          ["results", Routes.proposal_path(long_id)],
           ["#{user.get('name')}", Routes.proposal_position_path(long_id, position.id)] ]

         if region.currentView instanceof Franklin.Proposal.AggregateLayout


Add missing require

Add missing require

--- src/module-cache.coffee
+++ src/module-cache.coffee
@@ -154,6 +154,7 @@

 registerBuiltins = (devMode) ->
   if devMode
+    fs = require 'fs-plus'
     atomCoffeePath = path.join(cache.resourcePath, 'exports', 'atom.coffee')
     cache.builtins.atom = atomCoffeePath if fs.isFileSync(atomCoffeePath)
   cache.builtins.atom ?= path.join(cache.resourcePath, 'exports', 'atom.js')


Reverting LEVEL object.

Reverting LEVEL object.

--- nodes.coffee
+++ nodes.coffee
@@ -42,7 +42,7 @@
     o.level  = lvl if lvl?
     node     = @unfoldSoak(o) or this
     node.tab = o.indent
-    if o.level is LEVEL.TOP or node.isPureStatement() or not node.isStatement(o)
+    if o.level is LEVEL_TOP or node.isPureStatement() or not node.isStatement(o)
       node.compileNode o
     else
       node.compileClosure o
@@ -69,7 +69,7 @@

   # Compile to a source/variable pair suitable for looping.
   compileLoopReference: (o, name) ->
-    src = tmp = @compile o, LEVEL.LIST
+    src = tmp = @compile o, LEVEL_LIST
     unless NUMBER.test(src) or IDENTIFIER.test(src) and o.scope.check(src, immediate: on)
       src = "#{ tmp = o.scope.freeVariable name } = #{src}"
     [src, tmp]
@@ -205,7 +205,7 @@
   compileRoot: (o) ->
     o.indent = @tab = if o.bare then '' else TAB
     o.scope  = new Scope null, this, null
-    o.level  = LEVEL.TOP
+    o.level  = LEVEL_TOP
     code     = @compileWithDeclarations o
     code     = code.replace TRAILING_WHITESPACE, ''
     if o.bare then code else "(function() {\n#{code}\n}).call(this);\n"
@@ -228,7 +228,7 @@
     while node isnt node = node.unwrap() then
     node = node.unfoldSoak(o) or node
     node.tags.front = on
-    o.level = LEVEL.TOP
+    o.level = LEVEL_TOP
     code    = node.compile o
     if node.isStatement o then code else @tab + code + ';'

@@ -281,7 +281,7 @@
     if expr and expr not instanceof Return then expr.compile o, lvl else super o, lvl

   compileNode: (o) ->
-    o.level = LEVEL.PAREN
+    o.level = LEVEL_PAREN
     @tab + "return#{ if @expression then ' ' + @expression.compile o else '' };"

 #### Value
@@ -365,7 +365,7 @@
   compileNode: (o) ->
     @base.tags.front = @tags.front
     props = @properties
-    code  = @base.compile o, if props.length then LEVEL.ACCESS else null
+    code  = @base.compile o, if props.length then LEVEL_ACCESS else null
     code  = "(#{code})" if props[0] instanceof Accessor and @isSimpleNumber()
     (code += prop.compile o) for prop in props
     code
@@ -473,11 +473,11 @@
     @variable?.tags.front = @tags.front
     for arg in @args when arg instanceof Splat
       return @compileSplat o
-    args = (arg.compile o, LEVEL.LIST for arg in @args).join ', '
+    args = (arg.compile o, LEVEL_LIST for arg in @args).join ', '
     if @isSuper
       @compileSuper args, o
     else
-      (if @isNew then 'new ' else '') + @variable.compile(o, LEVEL.ACCESS) + "(#{args})"
+      (if @isNew then 'new ' else '') + @variable.compile(o, LEVEL_ACCESS) + "(#{args})"

   # `super()` is converted into a call against the superclass's implementation
   # of the current function.
@@ -495,9 +495,9 @@
       base = Value.wrap @variable
       if (name = base.properties.pop()) and base.isComplex()
         ref = o.scope.freeVariable 'this'
-        fun = "(#{ref} = #{ base.compile o, LEVEL.LIST })#{ name.compile o }"
+        fun = "(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }"
       else
-        fun = ref = base.compile o, LEVEL.ACCESS
+        fun = ref = base.compile o, LEVEL_ACCESS
         fun += name.compile o if name
       return "#{fun}.apply(#{ref}, #{splatargs})"
     idt = @idt 1
@@ -506,7 +506,7 @@
     #{idt}ctor.prototype = func.prototype;
     #{idt}var child = new ctor, result = func.apply(child, args);
     #{idt}return typeof result === "object" ? result : child;
-    #{@tab}})(#{ @variable.compile o, LEVEL.LIST }, #{splatargs}, function() {})
+    #{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatargs}, function() {})
     """

 #### Extends
@@ -553,7 +553,7 @@
   constructor: (@index) -> super()

   compile: (o) ->
-    (if @proto then '.prototype' else '') + "[#{ @index.compile o, LEVEL.PAREN }]"
+    (if @proto then '.prototype' else '') + "[#{ @index.compile o, LEVEL_PAREN }]"

   isComplex: -> @index.isComplex()

@@ -613,7 +613,7 @@
       return @compileSplatLiteral o
     objects = []
     for obj, i in @objects
-      code = obj.compile o, LEVEL.LIST
+      code = obj.compile o, LEVEL_LIST
       objects.push (if obj instanceof Comment
         "\n#{code}\n#{o.indent}"
       else if i is @objects.length - 1
@@ -742,22 +742,22 @@
     if isValue = @variable instanceof Value
       return @compilePatternMatch o if @variable.isArray() or @variable.isObject()
       return @compileConditional  o if @context in @CONDITIONAL
-    name = @variable.compile o, LEVEL.LIST
+    name = @variable.compile o, LEVEL_LIST
     if @value instanceof Code and match = @METHOD_DEF.exec name
       @value.name  = match[2]
       @value.klass = match[1]
-    val = @value.compile o, LEVEL.LIST
+    val = @value.compile o, LEVEL_LIST
     return "#{name}: #{val}" if @context is 'object'
     o.scope.find name unless isValue and (@variable.hasProperties() or @variable.namespaced)
     val = name + " #{ @context or '=' } " + val
-    if o.level <= LEVEL.LIST then val else "(#{val})"
+    if o.level <= LEVEL_LIST then val else "(#{val})"

   # Brief implementation of recursive pattern matching, when assigning array or
   # object literals to a value. Peeks at their properties to assign inner names.
   # See the [ECMAScript Harmony Wiki](http://wiki.ecmascript.org/doku.php?id=harmony:destructuring)
   # for details.
   compilePatternMatch: (o) ->
-    top       = o.level is LEVEL.TOP
+    top       = o.level is LEVEL_TOP
     {value}   = this
     {objects} = @variable.base
     return value.compile o unless olength = objects.length
@@ -774,7 +774,7 @@
       accessClass = if IDENTIFIER.test idx.value then Accessor else Index
       (value = Value.wrap value).properties.push new accessClass idx
       return new Assign(obj, value).compile o
-    valVar  = value.compile o, LEVEL.LIST
+    valVar  = value.compile o, LEVEL_LIST
     assigns = []
     splat   = false
     if not IDENTIFIER.test(valVar) or @variable.assigns(valVar)
@@ -800,10 +800,10 @@
         if typeof idx isnt 'object'
           idx = new Literal(if splat then "#{valVar}.length - #{ olength - idx }" else idx)
         val = new Value new Literal(valVar), [new accessClass idx]
-      assigns.push new Assign(obj, val).compile o, LEVEL.LIST
+      assigns.push new Assign(obj, val).compile o, LEVEL_LIST
     assigns.push valVar unless top
     code = assigns.join ', '
-    if o.level < LEVEL.LIST then code else "(#{code})"
+    if o.level < LEVEL_LIST then code else "(#{code})"

   # When compiling a conditional assignment, take care to ensure that the
   # operands are only evaluated once, even though we have to reference them
@@ -898,7 +898,7 @@
     super()
     @value = new Literal @name

-  compile: (o) -> @value.compile o, LEVEL.LIST
+  compile: (o) -> @value.compile o, LEVEL_LIST

   toString: ->
     {name} = this
@@ -957,7 +957,7 @@
     args = []
     end  = -1
     for arg, i in list
-      code = arg.compile o, LEVEL.LIST
+      code = arg.compile o, LEVEL_LIST
       prev = args[end]
       if arg not instanceof Splat
         if prev and starts(prev, '[') and ends(prev, ']')
@@ -1001,14 +1001,14 @@
     o.indent = @idt 1
     set      = ''
     {body}   = this
-    if o.level > LEVEL.TOP or @returns
+    if o.level > LEVEL_TOP or @returns
       rvar = o.scope.freeVariable 'result'
       set  = "#{@tab}#{rvar} = [];\n"
       body = Push.wrap rvar, body if body
     body = Expressions.wrap [new If @guard, body] if @guard
     code = set + @tab + """
-      while (#{ @condition.compile o, LEVEL.PAREN }) {
-      #{ body.compile o, LEVEL.TOP }
+      while (#{ @condition.compile o, LEVEL_PAREN }) {
+      #{ body.compile o, LEVEL_TOP }
       #{@tab}}
     """
     if @returns
@@ -1086,7 +1086,7 @@
     return @compileChain o     if @isChainable() and @first.unwrap().isChainable()
     return @compileExistence o if @operator is '?'
     @first.tags.front = @tags.front
-    "#{ @first.compile o, LEVEL.OP } #{@operator} #{ @second.compile o, LEVEL.OP }"
+    "#{ @first.compile o, LEVEL_OP } #{@operator} #{ @second.compile o, LEVEL_OP }"

   # Mimic Python's chained comparisons when multiple comparison operators are
   # used sequentially. For example:
@@ -1095,7 +1095,7 @@
   #     true
   compileChain: (o) ->
     [@first.second, shared] = @first.unwrap().second.cache o
-    "#{ @first.compile o, LEVEL.OP } && #{ shared.compile o } #{@operator} #{ @second.compile o, LEVEL.OP }"
+    "#{ @first.compile o, LEVEL_OP } && #{ shared.compile o } #{@operator} #{ @second.compile o, LEVEL_OP }"

   compileExistence: (o) ->
     if @first.isComplex()
@@ -1104,13 +1104,13 @@
     else
       fst = @first
       ref = fst.compile o
-    new Existence(fst).compile(o) + " ? #{ref} : #{ @second.compile o, LEVEL.LIST }"
+    new Existence(fst).compile(o) + " ? #{ref} : #{ @second.compile o, LEVEL_LIST }"

   # Compile a unary **Op**.
   compileUnary: (o) ->
     space = if @operator in @PREFIX_OPERATORS or @first instanceof Op and
         @first.operator is @operator and @operator in ['+', '-'] then ' ' else ''
-    parts = [@operator, space, @first.compile(o, LEVEL.OP)]
+    parts = [@operator, space, @first.compile(o, LEVEL_OP)]
     (if @flip then parts.reverse() else parts).join ''

 #### In
@@ -1131,20 +1131,20 @@
       @compileLoopTest o

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

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

   toString: (idt) ->
     super idt, @constructor.name + if @negated then '!' else ''
@@ -1171,14 +1171,14 @@
     o.indent  = @idt 1
     errorPart = if @error then " (#{ @error.compile o }) " else ' '
     catchPart = if @recovery
-      " catch#{errorPart}{\n#{ @recovery.compile o, LEVEL.TOP }\n#{@tab}}"
+      " catch#{errorPart}{\n#{ @recovery.compile o, LEVEL_TOP }\n#{@tab}}"
     else unless @ensure or @recovery
       ' catch (_e) {}'
     """
     #{@tab}try {
-    #{ @attempt.compile o, LEVEL.TOP }
+    #{ @attempt.compile o, LEVEL_TOP }
     #{@tab}}#{ catchPart or '' }
-    """ + if @ensure then " finally {\n#{ @ensure.compile o, LEVEL.TOP }\n#{@tab}}" else ''
+    """ + if @ensure then " finally {\n#{ @ensure.compile o, LEVEL_TOP }\n#{@tab}}" else ''

 #### Throw

@@ -1213,7 +1213,7 @@
       "typeof #{code} !== \"undefined\" && #{code} !== null"
     else
       "#{code} != null"
-    if o.level <= LEVEL.COND then code else "(#{code})"
+    if o.level <= LEVEL_COND then code else "(#{code})"

 #### Parens

@@ -1237,8 +1237,8 @@
     if expr instanceof Value and expr.isAtomic()
       expr.tags.front = @tags.front
       return expr.compile o
-    bare = o.level < LEVEL.OP and (expr instanceof Op or expr instanceof Call)
-    code = expr.compile o, LEVEL.PAREN
+    bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call)
+    code = expr.compile o, LEVEL_PAREN
     if bare then code else "(#{code})"

 #### For
@@ -1301,9 +1301,9 @@
       if name or @object and not @raw
         [sourcePart, svar] = @source.compileLoopReference o, 'ref'
       else
-        sourcePart = svar = @source.compile o, LEVEL.PAREN
+        sourcePart = svar = @source.compile o, LEVEL_PAREN
       namePart = if @pattern
-        new Assign(@name, new Literal "#{svar}[#{ivar}]").compile o, LEVEL.TOP
+        new Assign(@name, new Literal "#{svar}[#{ivar}]").compile o, LEVEL_TOP
       else if name
         "#{name} = #{svar}[#{ivar}]"
       unless @object
@@ -1325,7 +1325,7 @@
         when  1 then '++'
         when -1 then '--'
         else (if pvar < 0 then ' -= ' + pvar.slice 1 else ' += ' + pvar)
-    if o.level > LEVEL.TOP or @returns
+    if o.level > LEVEL_TOP or @returns
       rvar     = scope.freeVariable 'result'
       defPart += @tab + rvar + ' = [];\n'
       retPart  = @compileReturnValue rvar, o
@@ -1335,7 +1335,7 @@
     o.indent = idt
     defPart + """
     #{@tab}for (#{forPart}) {
-    #{ guardPart or '' }#{varPart}#{ body.compile o, LEVEL.TOP }
+    #{ guardPart or '' }#{varPart}#{ body.compile o, LEVEL_TOP }
     #{@tab}}
     """ + retPart

@@ -1358,17 +1358,17 @@
   compileNode: (o) ->
     idt1 = @idt 1
     idt2 = o.indent = @idt 2
-    code = @tab + "switch (#{ @subject?.compile(o, LEVEL.PAREN) or true }) {\n"
+    code = @tab + "switch (#{ @subject?.compile(o, LEVEL_PAREN) or true }) {\n"
     for [conditions, block], i in @cases
       for cond in flatten [conditions]
         cond  = cond.invert().invert() unless @subject
-        code += idt1 + "case #{ cond.compile o, LEVEL.PAREN }:\n"
-      code += block.compile(o, LEVEL.TOP) + '\n'
+        code += idt1 + "case #{ cond.compile o, LEVEL_PAREN }:\n"
+      code += block.compile(o, LEVEL_TOP) + '\n'
       break if i is @cases.length - 1 and not @otherwise
       for expr in block.expressions by -1 when expr not instanceof Comment
         code += idt2 + 'break;\n' unless expr instanceof Return
         break
-    code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL.TOP }\n" if @otherwise
+    code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL_TOP }\n" if @otherwise
     code +  @tab + '}'

 #### If
@@ -1404,7 +1404,7 @@
   # The **If** only compiles into a statement if either of its bodies needs
   # to be a statement. Otherwise a conditional operator is safe.
   isStatement: (o) ->
-    o?.level is LEVEL.TOP or @bodyNode().isStatement(o) or @elseBodyNode()?.isStatement(o)
+    o?.level is LEVEL_TOP or @bodyNode().isStatement(o) or @elseBodyNode()?.isStatement(o)

   compileNode: (o) ->
     if @isStatement o then @compileStatement o else @compileExpression o
@@ -1424,7 +1424,7 @@
   # force inner *else* bodies into statement form.
   compileStatement: (o) ->
     child    = del o, 'chainChild'
-    cond     = @condition.compile o, LEVEL.PAREN
+    cond     = @condition.compile o, LEVEL_PAREN
     o.indent = @idt 1
     body     = @ensureExpressions(@body).compile o
     ifPart   = "if (#{cond}) {\n#{body}\n#{@tab}}"
@@ -1433,14 +1433,14 @@
     ifPart + ' else ' + if @isChain
        @elseBodyNode().compile merge o, indent: @tab, chainChild: true
     else
-      "{\n#{ @elseBody.compile o, LEVEL.TOP }\n#{@tab}}"
+      "{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}"

   # Compile the If as a conditional operator.
   compileExpression: (o) ->
-    code = @condition .compile(o, LEVEL.COND) + ' ? ' +
-           @bodyNode().compile(o, LEVEL.LIST) + ' : ' +
-           @elseBodyNode()?.compile o, LEVEL.LIST
-    if o.level >= LEVEL.COND then "(#{code})" else code
+    code = @condition .compile(o, LEVEL_COND) + ' ? ' +
+           @bodyNode().compile(o, LEVEL_LIST) + ' : ' +
+           @elseBodyNode()?.compile o, LEVEL_LIST
+    if o.level >= LEVEL_COND then "(#{code})" else code

   unfoldSoak: -> @soakNode and this

@@ -1532,13 +1532,12 @@
   slice  : 'Array.prototype.slice'

 # Levels indicates a node's position in the AST.
-LEVEL =
-  TOP    : 0  # ...;
-  PAREN  : 1  # (...)
-  LIST   : 2  # [...]
-  COND   : 3  # ... ? x : y
-  OP     : 4  # !...
-  ACCESS : 5  # ...[0]
+LEVEL_TOP    = 0  # ...;
+LEVEL_PAREN  = 1  # (...)
+LEVEL_LIST   = 2  # [...]
+LEVEL_COND   = 3  # ... ? x : y
+LEVEL_OP     = 4  # !...
+LEVEL_ACCESS = 5  # ...[0]

 # Tabs are two spaces for pretty printing.
 TAB = '  '


Fixes #2630 -- Class bodies shouldn't be able to reference arguments.

--- nodes.coffee
+++ nodes.coffee
@@ -1934,6 +1934,8 @@
     func = new Code [], Block.wrap [expressions]
     args = []
     if (mentionsArgs = expressions.contains @literalArgs) or expressions.contains @literalThis
+      if mentionsArgs and expressions.classBody
+        throw SyntaxError "Class bodies don't have arguments"
       meth = new Literal if mentionsArgs then 'apply' else 'call'
       args = [new Literal 'this']
       args.push new Literal 'arguments' if mentionsArgs


Exclude linting on files prefixed with 'vendor-'

--- src/tasks/_util.coffee
+++ src/tasks/_util.coffee
@@ -44,9 +44,9 @@
 	files.inline          = "#{dir.inline}/**/*.{gif,jpg,png,svg}"
 	files.raw             = "#{dir.raw}/**/*"
 	files.scripts         = "#{dir.scripts}/**/*.js"
-	files.scripts_lint    = [files.bundles_scripts, files.scripts, "!#{dir.scripts_nolint}/**/*"]
+	files.scripts_lint    = [files.bundles_scripts, files.scripts, "!#{dir.scripts_nolint}/**/*", "!#{dir.scripts}/**/vendor-*"]
 	files.styles          = "#{dir.styles}/**/*.scss"
-	files.styles_lint     = [files.bundles_styles, files.styles, "!#{dir.styles_nolint}/**/*"]
+	files.styles_lint     = [files.bundles_styles, files.styles, "!#{dir.styles_nolint}/**/*", "!#{dir.styles}/**/vendor-*"]
 	files.templates       = "#{dir.templates}/**/*.jshtml"
 	files.bower_scripts   = "#{dir.bower}/**/*.js"
 	files.bower_styles    = "#{dir.bower}/**/*.{css,less,scss}"


change viewer location URL to only replace and not add to History stack

Previously, if you were tracing the URL would always update to the
current camera location and render the ‘back’ button useless, because
it would set the last know camera URL. However, I would argue, that one
usually wants to navigate back to the Dashboard /etc.

--- app/assets/javascripts/oxalis/controller/url_manager.coffee
+++ app/assets/javascripts/oxalis/controller/url_manager.coffee
@@ -14,7 +14,7 @@
     @initialState = @parseUrl url

     @update = _.throttle(
-      => location.href = @buildUrl()
+      => location.replace(@buildUrl())
       @MAX_UPDATE_INTERVAL
     )


Refactored checkout service to reduce function to update() & complete()

--- app/assets/javascripts/sprangular/resources/checkout.coffee
+++ app/assets/javascripts/sprangular/resources/checkout.coffee
@@ -1,72 +1,29 @@
-Sprangular.service "Checkout", ($q, $http, _, Account, Cart) ->
-
-  content =
-    order: [] # [{...}]
-    number: null
-
-  contentDefer = $q.defer()
+Sprangular.service "Checkout", ($http, _, Account, Cart) ->

   checkout =
+    update: ->
+      order = Cart.current

-    init: (number) ->
-      $http.get "/spree/api/orders/#{number}"
-        .success (data) ->
-          content.order = data
-          content.number = data.number
-          contentDefer.resolve content
-        .error (error) ->
-          console.log '404'
-
-    next: ->
-      $http.put "/spree/api/checkouts/#{content.number}/next"
-        .success (data) ->
-          content.order = data
-          content.number = data.number
-          contentDefer.resolve content
-        .error (error) ->
-          console.log '404', error
-
-    setShippingAddresses: (shippingAddress) ->
       params =
         order:
-          ship_address_attributes: shippingAddress.serialize()
-        state: 'address'
-      $http.put("/spree/api/checkouts/#{content.number}", $.param params)
-        .success (data) ->
-          content.order = data
-          contentDefer.resolve content
-        .error (error) ->
-          console.log '404', error
+          ship_address_attributes: order.actualShippingAddress().serialize()
+          bill_address_attributes: order.billingAddress.serialize()
+        state: 'confirm'

-    setBillingAddresses: (billingAddress) ->
+      if order.shippingMethod
+        params['order[shipments_attributes][][id]'] = order.shippingMethod.id
+
+      if order.shippingRate
+        params['order[shipments_attributes][][selected_shipping_rate_id]'] = order.shippingRate.id
+
+      @put(params)
+
+    complete: ->
       params =
-        order:
-          bill_address_attributes: billingAddress.serialize()
-        state: 'address'
-      $http.put("/spree/api/checkouts/#{content.number}", $.param params)
-        .success (data) ->
-          content.order = data
-          contentDefer.resolve content
-        .error (error) ->
-          console.log '404', error
+        'order[payments_attributes][][payment_method_id]': 99
+        'state': 'complete'

-    setDelivery: (shipment, shippingRate) ->
-      params =
-        'order[shipments_attributes][][id]': shipment.id
-        'order[shipments_attributes][][selected_shipping_rate_id]': shippingRate.id
-        'state': 'delivery'
-
-      $http.put("/spree/api/checkouts/#{content.number}", $.param params)
-        .success (data) ->
-          content.order = data
-          contentDefer.resolve content
-        .error (error) ->
-          console.log '404', error
-
-    setPayment: (card, paymentMethodId) ->
-      params =
-        'order[payments_attributes][][payment_method_id]': paymentMethodId
-        'state': 'payment'
+      card = Cart.current.creditCard

       if card.id
         params['use_existing_card'] = 'yes'
@@ -81,23 +38,14 @@
         params["payment_source[#{paymentMethodId}][last_digits]"] = card.lastDigits
         params["payment_source[#{paymentMethodId}][name]"] = card.name

-      $http.put("/spree/api/checkouts/#{content.number}", $.param params)
-        .success (data) ->
-          content.order = data
-          contentDefer.resolve content
-        .error (error) ->
-          console.log '404', error
+      @put(params)

-    confirm: ->
-      $http.put("/spree/api/checkouts/#{content.number}")
-        .success (data) ->
-          content.order = data
-          Account.reload()
-          contentDefer.resolve content
-        .error (error) ->
-          console.log '404', error
+    put: (params) ->
+      params ||= {}

-    fetchContent: ->
-      return contentDefer.promise
+      $http.put("/spree/api/checkouts/#{Cart.current.number}", $.param(params))
+           .success(Cart.load)
+           .error (response) ->
+             Cart.error(response.errors)

-  checkout+  checkout


let the user know when membership policy is updated

--- client/app/Applications/Groups.kdapplication/AppController.coffee
+++ client/app/Applications/Groups.kdapplication/AppController.coffee
@@ -695,8 +695,10 @@
     membershipPolicyView.enableInvitations.setValue policy.invitationsEnabled

   updateMembershipPolicy:(group, policy, formData, membershipPolicyView, callback)->
-    group.modifyMembershipPolicy formData, ->
-      policy.emit 'MembershipPolicyChangeSaved'
+    group.modifyMembershipPolicy formData, (err)->
+      policy.emit 'MembershipPolicyChangeSaved'  unless err
+      KD.showError err
+      new KDNotificationView {title:"Membership policy has been updated."}

   editPermissions:(group)->
     group.getData().fetchPermissions (err, permissionSet)->


Doc change for setFile (existsSync is necessary)

existsSync method is necessary for the object passed into setFile. Should be reflected in comment atom/text-buffer/issues/258

--- src/text-buffer.coffee
+++ src/text-buffer.coffee
@@ -576,6 +576,7 @@
   #   * `getPath` A {Function} that returns the {String} path to the file.
   #   * `createReadStream` A {Function} that returns a `Readable` stream
   #     that can be used to load the file's content.
+  #   * `existsSync` A {function} that returns the {Boolean}, true if the file exists, false otherwise
   #   * `createWriteStream` A {Function} that returns a `Writable` stream
   #     that can be used to save content to the file.
   #   * `onDidChange` (optional) A {Function} that invokes its callback argument


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/text_screen.coffee
+++ src/text_screen.coffee
@@ -1,5 +1,5 @@
 ###*
-The Text Screen class is a simple GameState that provides
+The Text Screen class is a GameState that provides convenie

 @see TextScreen
 @name TitleScreen